restored scenes branch

snap7
jmoenig 2021-03-15 08:51:15 +01:00
rodzic 0822005bf9
commit b11423a122
5 zmienionych plików z 164 dodań i 103 usunięć

Wyświetl plik

@ -3,6 +3,15 @@
## in development:
### 2021-03-15
* gui: marked methods for scene refactorings
### 2021-03-12
* scenes, gui, store: added scenes class
### 2021-03-11
* gui, store: refactor loading a project into the IDE
### 2021-03-09
* new dev version
## 6.7.1

Wyświetl plik

@ -3,7 +3,7 @@
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Snap! 6.7.2 - dev - Build Your Own Blocks</title>
<title>Snap! 7 - dev - Build Your Own Blocks</title>
<link rel="icon" href="src/favicon.ico">
<script src="src/morphic.js?version=2021-02-10"></script>
<script src="src/symbols.js?version=2021-03-03"></script>
@ -11,6 +11,7 @@
<script src="src/blocks.js?version=2021-02-27"></script>
<script src="src/threads.js?version=2021-03-02"></script>
<script src="src/objects.js?version=2021-03-09"></script>
<script src="src/scenes.js?version=2021-03-12"></script>
<script src="src/gui.js?version=2021-03-15"></script>
<script src="src/paint.js?version=2020-05-17"></script>
<script src="src/lists.js?version=2021-03-09"></script>
@ -20,7 +21,7 @@
<script src="src/video.js?version=2019-06-27"></script>
<script src="src/maps.js?version=2020-03-25"></script>
<script src="src/xml.js?version=2020-04-27"></script>
<script src="src/store.js?version=2021-03-09"></script>
<script src="src/store.js?version=2021-03-12"></script>
<script src="src/locale.js?version=2021-03-05"></script>
<script src="src/cloud.js?version=2021-02-04"></script>
<script src="src/api.js?version=2021-01-25"></script>

Wyświetl plik

@ -74,7 +74,8 @@ CommandBlockMorph, BooleanSlotMorph, RingReporterSlotMorph, ScriptFocusMorph,
BlockLabelPlaceHolderMorph, SpeechBubbleMorph, XML_Element, WatcherMorph, WHITE,
BlockRemovalDialogMorph,TableMorph, isSnapObject, isRetinaEnabled, SliderMorph,
disableRetinaSupport, enableRetinaSupport, isRetinaSupported, MediaRecorder,
Animation, BoxMorph, BlockEditorMorph, BlockDialogMorph, Note, ZERO, BLACK*/
Animation, BoxMorph, BlockEditorMorph, BlockDialogMorph, Note, ZERO, BLACK,
Scene*/
// Global stuff ////////////////////////////////////////////////////////
@ -227,7 +228,8 @@ IDE_Morph.prototype.init = function (isAutoFill) {
this.source = null;
this.serializer = new SnapSerializer();
this.globalVariables = new VariableFrame();
this.scene = new Scene();
this.globalVariables = this.scene.globalVariables;
this.currentSprite = new SpriteMorph(this.globalVariables);
this.sprites = new List([this.currentSprite]);
this.currentCategory = 'motion';
@ -4353,7 +4355,7 @@ IDE_Morph.prototype.aboutSnap = function () {
module, btn1, btn2, btn3, btn4, licenseBtn, translatorsBtn,
world = this.world();
aboutTxt = 'Snap! 6.7.2 - dev -\nBuild Your Own Blocks\n\n'
aboutTxt = 'Snap! 7 - dev -\nBuild Your Own Blocks\n\n'
+ 'Copyright \u24B8 2008-2021 Jens M\u00F6nig and '
+ 'Brian Harvey\n'
+ 'jens@moenig.org, bh@cs.berkeley.edu\n\n'
@ -4586,7 +4588,7 @@ IDE_Morph.prototype.editProjectNotes = function () {
text.edit();
};
IDE_Morph.prototype.newProject = function () {
IDE_Morph.prototype.newProject = function () { // +++
this.source = this.cloud.username ? 'cloud' : null;
if (this.stage) {
this.stage.destroy();
@ -4594,6 +4596,9 @@ IDE_Morph.prototype.newProject = function () {
if (location.hash.substr(0, 6) !== '#lang:') {
location.hash = '';
}
// +++ this.switchToScene(new Scene());
this.globalVariables = new VariableFrame();
this.currentSprite = new SpriteMorph(this.globalVariables);
this.sprites = new List([this.currentSprite]);
@ -5087,7 +5092,7 @@ IDE_Morph.prototype.openProjectString = function (str, callback) {
]);
};
IDE_Morph.prototype.rawOpenProjectString = function (str) {
IDE_Morph.prototype.rawOpenProjectString = function (str) { // +++
this.toggleAppMode(false);
this.spriteBar.tabBar.tabTo('scripts');
StageMorph.prototype.hiddenPrimitives = {};
@ -5102,17 +5107,15 @@ IDE_Morph.prototype.rawOpenProjectString = function (str) {
this.hasUnsavedEdits = false;
if (Process.prototype.isCatchingErrors) {
try {
this.serializer.openProject(
this.serializer.load(str, this),
this
this.switchToScene(
this.serializer.load(str, this)
);
} catch (err) {
this.showMessage('Load failed: ' + err);
}
} else {
this.serializer.openProject(
this.serializer.load(str, this),
this
this.switchToScene(
this.serializer.load(str, this)
);
}
this.stopFastTracking();
@ -5130,7 +5133,7 @@ IDE_Morph.prototype.openCloudDataString = function (str) {
]);
};
IDE_Morph.prototype.rawOpenCloudDataString = function (str) {
IDE_Morph.prototype.rawOpenCloudDataString = function (str) { // +++
var model;
StageMorph.prototype.hiddenPrimitives = {};
StageMorph.prototype.codeMappings = {};
@ -5146,13 +5149,12 @@ IDE_Morph.prototype.rawOpenCloudDataString = function (str) {
try {
model = this.serializer.parse(str);
this.serializer.loadMediaModel(model.childNamed('media'));
this.serializer.openProject(
this.switchToScene(
this.serializer.loadProjectModel(
model.childNamed('project'),
this,
model.attributes.remixID
),
this
)
);
} catch (err) {
this.showMessage('Load failed: ' + err);
@ -5160,13 +5162,12 @@ IDE_Morph.prototype.rawOpenCloudDataString = function (str) {
} else {
model = this.serializer.parse(str);
this.serializer.loadMediaModel(model.childNamed('media'));
this.serializer.openProject(
this.switchToScene(
this.serializer.loadProjectModel(
model.childNamed('project'),
this,
model.attributes.remixID
),
this
)
);
}
this.stopFastTracking();
@ -5359,6 +5360,33 @@ IDE_Morph.prototype.openProject = function (name) {
}
};
IDE_Morph.prototype.switchToScene = function (scene) { // +++
var sprites = [];
if (!scene || !scene.stage) {
return;
}
this.siblings().forEach(morph =>
morph.destroy()
);
this.scene = scene;
this.projectName = scene.name;
this.projectNotes = scene.notes || '';
this.globalVariables = scene.globalVariables;
this.stage.destroy();
this.add(scene.stage);
this.stage = scene.stage;
sprites = this.stage.children.filter(
child => child instanceof SpriteMorph
);
sprites.sort((x, y) => x.idx - y.idx);
this.sprites = new List(sprites);
this.stage.pauseGenericHatBlocks();
this.createCorral();
this.selectSprite(sprites[0] || this.stage);
this.fixLayout();
this.world().keyboardFocus = this.stage;
};
IDE_Morph.prototype.setURL = function (str) {
// Set the URL to a project's XML contents
location.hash = this.projectsInURLs ? str : '';

73
src/scenes.js 100644
Wyświetl plik

@ -0,0 +1,73 @@
/*
scenes.js
multi-scene support for Snap!
written by Jens Mönig
jens@moenig.org
Copyright (C) 2021 by Jens Mönig
This file is part of Snap!.
Snap! is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 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 Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
prerequisites:
--------------
needs morphic.js and objects.js
toc
---
the following list shows the order in which all constructors are
defined. Use this list to locate code in this document:
Scene
credits
-------
scenes have been inspired by Ted Kaehlers's personal demos of HyperCard
and many discussions with Ted about the design and practice of HyperCard,
and by personal discussions with Wolfgang Slany about his design of
scenes in Catrobat/PocketCode, which I love and admire.
*/
// Global stuff ////////////////////////////////////////////////////////
/*global modules, VariableFrame, aStageMorph*/
modules.scenes = '2021-March-12';
// Scene /////////////////////////////////////////////////////////
// I am a container for a Snap! stage, scene-global variables
// and its associated settings.
// I can be used as a slide in a presentation, a chapter in a narrative,
// a level in a game, etc.
// Scene instance creation:
function Scene(aStageMorph) {
this.name = null;
this.notes = null;
this.globalVariables = aStageMorph ?
aStageMorph.globalVariables() : new VariableFrame();
this.stage = aStageMorph || new StageMorph(this.globalVariables);
// for deserializing - do not persist
this.sprites = {};
this.targetStage = null;
}

Wyświetl plik

@ -27,7 +27,7 @@
prerequisites:
--------------
needs morphic.js, xml.js, and most of Snap!'s other modules
needs morphic.js, xml.js, scenes.js and most of Snap!'s other modules
hierarchy
@ -49,19 +49,18 @@
*/
/*global modules, XML_Element, VariableFrame, StageMorph, SpriteMorph,
WatcherMorph, Point, CustomBlockDefinition, Context, ReporterBlockMorph,
/*global modules, XML_Element, VariableFrame, StageMorph, SpriteMorph, console,
WatcherMorph, Point, CustomBlockDefinition, Context, ReporterBlockMorph, Sound,
CommandBlockMorph, detect, CustomCommandBlockMorph, CustomReporterBlockMorph,
Color, List, newCanvas, Costume, Sound, Audio, IDE_Morph, ScriptsMorph,
Color, List, newCanvas, Costume, Audio, IDE_Morph, ScriptsMorph, ArgLabelMorph,
BlockMorph, ArgMorph, InputSlotMorph, TemplateSlotMorph, CommandSlotMorph,
FunctionSlotMorph, MultiArgMorph, ColorSlotMorph, nop, CommentMorph, isNil,
localize, sizeOf, ArgLabelMorph, SVG_Costume, MorphicPreferences, Process,
SyntaxElementMorph, Variable, isSnapObject, console, BooleanSlotMorph,
normalizeCanvas, contains*/
localize, SVG_Costume, MorphicPreferences, Process, isSnapObject, Variable,
SyntaxElementMorph, BooleanSlotMorph, normalizeCanvas, contains, Scene*/
// Global stuff ////////////////////////////////////////////////////////
modules.store = '2021-March-09';
modules.store = '2021-March-12';
// XML_Serializer ///////////////////////////////////////////////////////
@ -279,7 +278,7 @@ function SnapSerializer() {
// SnapSerializer initialization:
SnapSerializer.prototype.init = function () {
this.project = {};
this.scene = new Scene();
this.objects = {};
this.mediaDict = {};
};
@ -331,11 +330,11 @@ SnapSerializer.prototype.loadProjectModel = function (xmlNode, ide, remixID) {
SnapSerializer.prototype.rawLoadProjectModel = function (xmlNode, remixID) {
// private
var project = {sprites: {}},
var project = new Scene(),
model,
nameID;
this.project = project;
this.scene = project;
model = {project: xmlNode };
if (+xmlNode.attributes.version > this.version) {
@ -363,14 +362,13 @@ SnapSerializer.prototype.rawLoadProjectModel = function (xmlNode, remixID) {
project.notes = model.notes.contents;
}
model.globalVariables = model.project.childNamed('variables');
project.globalVariables = new VariableFrame();
/* Stage */
model.stage = model.project.require('stage');
StageMorph.prototype.frameRate = 0;
project.stage = new StageMorph(project.globalVariables);
project.stage.remixID = remixID;
if (Object.prototype.hasOwnProperty.call(
model.stage.attributes,
'id'
@ -484,10 +482,10 @@ SnapSerializer.prototype.rawLoadProjectModel = function (xmlNode, remixID) {
);
// restore inheritance and nesting associations
this.project.stage.children.forEach(sprite => {
this.scene.stage.children.forEach(sprite => {
var exemplar, anchor;
if (sprite.inheritanceInfo) { // only sprites can inherit
exemplar = this.project.sprites[
exemplar = this.scene.sprites[
sprite.inheritanceInfo.exemplar
];
if (exemplar) {
@ -497,14 +495,14 @@ SnapSerializer.prototype.rawLoadProjectModel = function (xmlNode, remixID) {
sprite.updatePropagationCache();
}
if (sprite.nestingInfo) { // only sprites may have nesting info
anchor = this.project.sprites[sprite.nestingInfo.anchor];
anchor = this.scene.sprites[sprite.nestingInfo.anchor];
if (anchor) {
anchor.attachPart(sprite);
}
sprite.rotatesWithAnchor = (sprite.nestingInfo.synch === 'true');
}
});
this.project.stage.children.forEach(sprite => {
this.scene.stage.children.forEach(sprite => {
var costume;
if (sprite.nestingInfo) { // only sprites may have nesting info
sprite.nestingScale = +(sprite.nestingInfo.scale || sprite.scale);
@ -621,7 +619,7 @@ SnapSerializer.prototype.rawLoadProjectModel = function (xmlNode, remixID) {
});
// clear sprites' inherited methods caches, if any
this.project.stage.children.forEach(
this.scene.stage.children.forEach(
sprite => sprite.inheritedMethodsCache = []
);
@ -632,14 +630,11 @@ SnapSerializer.prototype.rawLoadProjectModel = function (xmlNode, remixID) {
SnapSerializer.prototype.loadBlocks = function (xmlString, targetStage) {
// public - answer a new Array of custom block definitions
// represented by the given XML String
var stage = new StageMorph(),
model;
var stage, model;
this.project = {
stage: stage,
sprites: {},
targetStage: targetStage // for secondary custom block def look-up
};
this.scene = new Scene();
this.scene.targetStage = targetStage; // for secondary block def look-up
stage = this.scene.stage;
model = this.parse(xmlString);
if (+model.attributes.version > this.version) {
throw 'Module uses newer version of Serializer';
@ -653,7 +648,7 @@ SnapSerializer.prototype.loadBlocks = function (xmlString, targetStage) {
this.objects = {};
stage.globalBlocks.forEach(def => def.receiver = null);
this.objects = {};
this.project = {};
this.scene = new Scene();
this.mediaDict = {};
return stage.globalBlocks;
};
@ -663,11 +658,8 @@ SnapSerializer.prototype.loadSprites = function (xmlString, ide) {
// into the current project of the ide
var model, project;
project = this.project = {
globalVariables: ide.globalVariables,
stage: ide.stage,
sprites: {}
};
this.scene = new Scene(ide.stage);
project = this.scene;
project.sprites[project.stage.name] = project.stage;
model = this.parse(xmlString);
@ -740,7 +732,7 @@ SnapSerializer.prototype.loadSprites = function (xmlString, ide) {
});
this.objects = {};
this.project = {};
this.scene = new Scene();
this.mediaDict = {};
ide.stage.fixLayout();
@ -1112,9 +1104,9 @@ SnapSerializer.prototype.loadScript = function (model, object) {
// Check whether we're importing a single script, not a script as part of a
// whole project
if (!this.project.stage) {
this.project.stage = object.parentThatIsA(StageMorph);
this.project.targetStage = this.project.stage;
if (!this.scene.stage) {
this.scene.stage = object.parentThatIsA(StageMorph);
this.scene.targetStage = this.scene.stage;
}
model.children.forEach(child => {
@ -1185,15 +1177,15 @@ SnapSerializer.prototype.loadBlock = function (model, isReporter, object) {
}
} else if (model.tag === 'custom-block') {
isGlobal = model.attributes.scope ? false : true;
receiver = isGlobal ? this.project.stage : object;
receiver = isGlobal ? this.scene.stage : object;
if (isGlobal) {
info = detect(
receiver.globalBlocks,
block => block.blockSpec() === model.attributes.s
);
if (!info && this.project.targetStage) { // importing block files
if (!info && this.scene.targetStage) { // importing block files
info = detect(
this.project.targetStage.globalBlocks,
this.scene.targetStage.globalBlocks,
block => block.blockSpec() === model.attributes.s
);
}
@ -1411,13 +1403,13 @@ SnapSerializer.prototype.loadValue = function (model, object) {
});
return v;
case 'sprite':
v = new SpriteMorph(this.project.globalVariables);
v = new SpriteMorph(this.scene.globalVariables);
if (model.attributes.id) {
this.objects[model.attributes.id] = v;
}
if (model.attributes.name) {
v.name = model.attributes.name;
this.project.sprites[model.attributes.name] = v;
this.scene.sprites[model.attributes.name] = v;
}
if (model.attributes.idx) {
v.idx = +model.attributes.idx;
@ -1435,7 +1427,7 @@ SnapSerializer.prototype.loadValue = function (model, object) {
if (model.attributes.pan) {
v.pan = +model.attributes.pan;
}
this.project.stage.add(v);
this.scene.stage.add(v);
v.scale = parseFloat(model.attributes.scale || '1');
v.rotationStyle = parseFloat(
model.attributes.rotation || '1'
@ -1617,48 +1609,6 @@ SnapSerializer.prototype.loadColor = function (colorString) {
);
};
SnapSerializer.prototype.openProject = function (project, ide) {
var stage = ide.stage,
sprites = [],
sprite;
if (!project || !project.stage) {
return;
}
ide.siblings().forEach(morph =>
morph.destroy()
);
ide.projectName = project.name;
ide.projectNotes = project.notes || '';
if (ide.globalVariables) {
ide.globalVariables = project.globalVariables;
}
if (stage) {
stage.destroy();
}
ide.add(project.stage);
ide.stage = project.stage;
sprites = ide.stage.children.filter(
child => child instanceof SpriteMorph
);
sprites.sort((x, y) => x.idx - y.idx);
ide.sprites = new List(sprites);
sprite = sprites[0] || project.stage;
if (sizeOf(this.mediaDict) > 0) {
ide.hasChangedMedia = false;
this.mediaDict = {};
} else {
ide.hasChangedMedia = true;
}
project.stage.fixLayout();
project.stage.pauseGenericHatBlocks();
ide.createCorral();
ide.selectSprite(sprite);
ide.fixLayout();
ide.world().keyboardFocus = project.stage;
};
// SnapSerializer XML-representation of objects:
// Generics