From 454c9c4cc0c8d229563e9e90502c41ebd7cfa7ea Mon Sep 17 00:00:00 2001 From: Nathan Dinsmore Date: Tue, 17 Jun 2014 13:51:08 -0400 Subject: [PATCH] Made blocks keep track of their full state when grabbed This fixes a number of issues with restoring block state and undeleting blocks. --- src/blocks/Block.as | 73 +++++++++++++++++++++++++++++------ src/scratch/ScratchRuntime.as | 4 +- src/ui/BlockPalette.as | 2 +- src/ui/SpriteThumbnail.as | 7 ++-- src/uiwidgets/ScriptsPane.as | 10 ++--- src/util/GestureHandler.as | 6 ++- 6 files changed, 77 insertions(+), 25 deletions(-) diff --git a/src/blocks/Block.as b/src/blocks/Block.as index 1986d32..67ec712 100644 --- a/src/blocks/Block.as +++ b/src/blocks/Block.as @@ -95,8 +95,14 @@ public class Block extends Sprite { private var indentTop:int = 2, indentBottom:int = 3; private var indentLeft:int = 4, indentRight:int = 3; - public var wasInScriptsPane:Boolean; - private var originalX:int, originalY:int; + private static var ROLE_NONE:int = 0; + private static var ROLE_ABSOLUTE:int = 1; + private static var ROLE_EMBEDDED:int = 2; + private static var ROLE_NEXT:int = 3; + private static var ROLE_SUBSTACK1:int = 4; + private static var ROLE_SUBSTACK2:int = 5; + + private var originalParent:DisplayObjectContainer, originalRole:int, originalIndex:int, originalPosition:Point; public function Block(spec:String, type:String = " ", color:int = 0xD00000, op:* = 0, defaultArgs:Array = null) { this.spec = Translator.map(spec); @@ -317,15 +323,58 @@ public class Block extends Sprite { return [f]; } - public function saveOriginalPosition():void { - wasInScriptsPane = topBlock().parent is ScriptsPane; - originalX = x; - originalY = y; + public function saveOriginalState():void { + originalParent = parent; + if (parent) { + var b:Block = parent as Block; + if (b == null) { + originalRole = ROLE_ABSOLUTE; + } else if (isReporter) { + originalRole = ROLE_EMBEDDED; + originalIndex = b.args.indexOf(this); + } else if (b.nextBlock == this) { + originalRole = ROLE_NEXT; + } else if (b.subStack1 == this) { + originalRole = ROLE_SUBSTACK1; + } else if (b.subStack2 == this) { + originalRole = ROLE_SUBSTACK2; + } + originalPosition = localToGlobal(new Point(0, 0)); + } else { + originalRole = ROLE_NONE; + originalPosition = null; + } } - public function restoreOriginalPosition():void { - x = originalX; - y = originalY; + public function restoreOriginalState():void { + var b:Block = originalParent as Block; + switch (originalRole) { + case ROLE_NONE: + if (parent) parent.removeChild(this); + break; + case ROLE_ABSOLUTE: + originalParent.addChild(this); + var p:Point = originalParent.globalToLocal(originalPosition); + x = p.x; + y = p.y; + break; + case ROLE_EMBEDDED: + b.replaceArgWithBlock(b.args[originalIndex], this, Scratch.app.scriptsPane); + break; + case ROLE_NEXT: + b.insertBlock(this); + break; + case ROLE_SUBSTACK1: + b.insertBlockSub1(this); + break; + case ROLE_SUBSTACK2: + b.insertBlockSub2(this); + break; + } + } + + public function originalPositionIn(p:DisplayObject):Point { + return originalPosition && p.globalToLocal(originalPosition); } private function setDefaultArgs(defaults:Array):void { @@ -742,9 +791,9 @@ public class Block extends Sprite { if (isProcDef()) return; // don't duplicate procedure definition var forStage:Boolean = Scratch.app.viewedObj() && Scratch.app.viewedObj().isStage; var newStack:Block = BlockIO.stringToStack(BlockIO.stackToString(this), forStage); - newStack.x = x + deltaX; - newStack.y = y + deltaY; - parent.addChild(newStack); + var p:Point = localToGlobal(new Point(0, 0)); + newStack.x = p.x + deltaX; + newStack.y = p.y + deltaY; Scratch.app.gh.grabOnMouseUp(newStack); } diff --git a/src/scratch/ScratchRuntime.as b/src/scratch/ScratchRuntime.as index 47c4c23..e203c3c 100644 --- a/src/scratch/ScratchRuntime.as +++ b/src/scratch/ScratchRuntime.as @@ -969,8 +969,8 @@ public class ScratchRuntime { } else if ((obj is Block) || (obj is ScratchComment)) { app.selectSprite(prevOwner); app.setTab('scripts'); - obj.x = x; - obj.y = y; + obj.x = app.scriptsPane.padding; + obj.y = app.scriptsPane.padding; if (obj is Block) obj.cacheAsBitmap = true; app.scriptsPane.addChild(obj); } diff --git a/src/ui/BlockPalette.as b/src/ui/BlockPalette.as index 6c21ed3..0a2d6e4 100644 --- a/src/ui/BlockPalette.as +++ b/src/ui/BlockPalette.as @@ -25,6 +25,7 @@ // creates a copy of that block when it is dragged out of the palette. package ui { + import flash.geom.*; import blocks.Block; import interpreter.Interpreter; import uiwidgets.*; @@ -67,7 +68,6 @@ public class BlockPalette extends ScrollFrameContents { return false; } if (b.parent) b.parent.removeChild(b); - b.restoreOriginalPosition(); // restore position in case block is undeleted Scratch.app.runtime.recordForUndelete(b, b.x, b.y, 0, Scratch.app.viewedObj()); app.scriptsPane.saveScripts(); app.updatePalette(); diff --git a/src/ui/SpriteThumbnail.as b/src/ui/SpriteThumbnail.as index f55f90f..86fa830 100644 --- a/src/ui/SpriteThumbnail.as +++ b/src/ui/SpriteThumbnail.as @@ -233,9 +233,10 @@ public class SpriteThumbnail extends Sprite { if (obj is Block) { // copy a block/stack to this sprite if (targetObj == app.viewedObj()) return false; // dropped on my own thumbnail; do nothing - var b:Block = obj as Block; - b.restoreOriginalPosition(); - targetObj.scripts.push(b.duplicate(false, targetObj.isStage)); + var copy:Block = Block(obj).duplicate(false, targetObj.isStage); + copy.x = app.scriptsPane.padding; + copy.y = app.scriptsPane.padding; + targetObj.scripts.push(copy); return false; // do not consume the original block } return false; diff --git a/src/uiwidgets/ScriptsPane.as b/src/uiwidgets/ScriptsPane.as index c39b76f..5f9c565 100644 --- a/src/uiwidgets/ScriptsPane.as +++ b/src/uiwidgets/ScriptsPane.as @@ -42,6 +42,7 @@ public class ScriptsPane extends ScrollFrameContents { private const INSERT_WRAP:int = 4; public var app:Scratch; + public var padding:int = 10; private var viewedObj:ScratchObj; private var commentLines:Shape; @@ -493,21 +494,20 @@ return true; // xxx disable this check for now; it was causing confusion at Scra // 3. Compute the column widths // 4. Move stacks into place - var pad:int = 10; var stacks:Array = stacksSortedByX(); var columns:Array = assignStacksToColumns(stacks); var columnWidths:Array = computeColumnWidths(columns); - var nextX:int = pad; + var nextX:int = padding; for (var i:int = 0; i < columns.length; i++) { var col:Array = columns[i]; - var nextY:int = pad; + var nextY:int = padding; for each (var b:Block in col) { b.x = nextX; b.y = nextY; - nextY += b.height + pad; + nextY += b.height + padding; } - nextX += columnWidths[i] + pad; + nextX += columnWidths[i] + padding; } saveScripts(); } diff --git a/src/util/GestureHandler.as b/src/util/GestureHandler.as index 63b606a..b447a6b 100644 --- a/src/util/GestureHandler.as +++ b/src/util/GestureHandler.as @@ -411,7 +411,7 @@ public class GestureHandler { if (obj is Block) { var b:Block = Block(obj); - b.saveOriginalPosition(); + b.saveOriginalState(); if (b.parent is Block) Block(b.parent).removeBlock(b); if (b.parent != null) b.parent.removeChild(b); app.scriptsPane.prepareToDrag(b); @@ -469,7 +469,9 @@ public class GestureHandler { carriedObj.parent.removeChild(carriedObj); if (!dropHandled(carriedObj, evt)) { - if (originalParent) { // put carriedObj back where it came from + if (carriedObj is Block) { + Block(carriedObj).restoreOriginalState(); + } else if (originalParent) { // put carriedObj back where it came from carriedObj.x = originalPosition.x; carriedObj.y = originalPosition.y; carriedObj.scaleX = carriedObj.scaleY = originalScale;