Paint editor fixes

pull/3/merge
jmoenig 2013-05-14 13:07:08 +02:00
rodzic f5e101dc57
commit 3f92313ae4
1 zmienionych plików z 270 dodań i 173 usunięć

443
paint.js
Wyświetl plik

@ -1,46 +1,75 @@
/* /*
paint.js paint.js
Paint editor for Snap!
Inspired by the Scratch paint editor.
written by Kartik Chandra
Latest revision: May 10 (Kartik)
This file is part of Snap!.
--current changes
Shrinkwrap
Draw crosshairs immediately
TRANSPARENT PAINT
Line width viewer
--To-Do list (in rough order of priority):
Eraser tool
After release: a paint editor for Snap!
-- inspired by the Scratch paint editor.
rgba sliders
Import image written by Kartik Chandra
Zoom/pan/Selection tools Copyright (C) 2013 by Kartik Chandra
Pick color from canvas
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/>.
toc
---
the following list shows the order in which all constructors are
defined. Use this list to locate code in this document:
PaintEditorMorph
PaintColorPickerMorph
PaintCanvasMorph
credits
-------
Nathan Dinsmore contributed a fully working prototype,
Nathan's brilliant flood-fill tool has been more or less
directly imported into this paint implementation.
Jens Mönig has contributed icons and bugfixes and says he has probably
introduced many other bugs in that process. :-)
revision history
----------------
May 10 - first full release (Kartik)
May 14 - bugfixes (bugfixes, Snap integration (Jens)
*/ */
/*global Point, Rectangle, DialogBoxMorph, fontHeight, AlignmentMorph, /*global Point, Rectangle, DialogBoxMorph, fontHeight, AlignmentMorph,
FrameMorph, PushButtonMorph, Color, SymbolMorph, newCanvas, Morph, TextMorph, FrameMorph, PushButtonMorph, Color, SymbolMorph, newCanvas, Morph, TextMorph,
CostumeIconMorph, IDE_Morph, Costume, SpriteMorph, nop, Image, WardrobeMorph, CostumeIconMorph, IDE_Morph, Costume, SpriteMorph, nop, Image, WardrobeMorph,
TurtleIconMorph, localize, MenuMorph, InputFieldMorph, SliderMorph, TurtleIconMorph, localize, MenuMorph, InputFieldMorph, SliderMorph,
ToggleMorph, ToggleButtonMorph, BoxMorph ToggleMorph, ToggleButtonMorph, BoxMorph, modules, radians, SVG_Costume
*/ */
// Global definitions // Global stuff ////////////////////////////////////////////////////////
modules.paint = '2013-May-14';
// Declarations
var PaintEditorMorph; var PaintEditorMorph;
var PaintCanvasMorph; var PaintCanvasMorph;
var PaintColorPickerMorph; var PaintColorPickerMorph;
// PaintEditorMorph ////////////////////////// // PaintEditorMorph //////////////////////////
// A complete paint editor // A complete paint editor
//////////////////////////////////////////////
PaintEditorMorph.prototype = new DialogBoxMorph(); PaintEditorMorph.prototype = new DialogBoxMorph();
PaintEditorMorph.prototype.constructor = PaintEditorMorph; PaintEditorMorph.prototype.constructor = PaintEditorMorph;
@ -54,7 +83,8 @@ function PaintEditorMorph() {
PaintEditorMorph.prototype.init = function() { PaintEditorMorph.prototype.init = function() {
// additional properties: // additional properties:
this.paper = null; // paint canvas this.paper = null; // paint canvas
this.oncancel = null;
// initialize inherited properties: // initialize inherited properties:
PaintEditorMorph.uber.init.call(this); PaintEditorMorph.uber.init.call(this);
@ -70,7 +100,8 @@ PaintEditorMorph.prototype.init = function() {
PaintEditorMorph.prototype.buildContents = function () { PaintEditorMorph.prototype.buildContents = function () {
var myself = this; var myself = this;
this.paper = new PaintCanvasMorph(function() {return myself.shift; }); this.paper = new PaintCanvasMorph(function() {return myself.shift; });
this.paper.setExtent(new Point(480, 360));
this.addBody(new AlignmentMorph('row', this.padding)); this.addBody(new AlignmentMorph('row', this.padding));
this.controls = new AlignmentMorph('column', this.padding); this.controls = new AlignmentMorph('column', this.padding);
@ -113,22 +144,22 @@ PaintEditorMorph.prototype.buildContents = function () {
PaintEditorMorph.prototype.buildToolbox = function() { PaintEditorMorph.prototype.buildToolbox = function() {
var tools = { var tools = {
brush: brush:
"Paintbrush tool (free draw)", "Paintbrush tool\n(free draw)",
rectangle: rectangle:
"Stroked Rectangle (shift: square)", "Stroked Rectangle\n(shift: square)",
circle: circle:
"Stroked Ellipse (shift: circle)", "Stroked Ellipse\n(shift: circle)",
eraser: eraser:
"Eraser tool", "Eraser tool",
crosshairs: crosshairs:
"Set the rotation center", "Set the rotation center",
line: line:
"Line tool (shift: vertical/horizontal)", "Line tool\n(shift: vertical/horizontal)",
rectangleSolid: rectangleSolid:
"Filled Rectangle (shift: square)", "Filled Rectangle\n(shift: square)",
circleSolid: circleSolid:
"Filled Ellipse (shift: circle)", "Filled Ellipse\n(shift: circle)",
paintbucket: paintbucket:
"Fill a region" "Fill a region"
}, },
@ -165,21 +196,18 @@ PaintEditorMorph.prototype.buildEdits = function() {
this.edits.add(this.pushButton( this.edits.add(this.pushButton(
"undo", "undo",
function () {paper.undo(); }, function () {paper.undo(); }
"Undo last action"
)); ));
this.edits.add(this.pushButton( this.edits.add(this.pushButton(
"clear", "clear",
function () {paper.clearCanvas(); }, function () {paper.clearCanvas(); }
"Clear the paper"
)); ));
this.edits.fixLayout(); this.edits.fixLayout();
}; };
// Open the editor in a world with an optional image to edit
PaintEditorMorph.prototype.openIn = function(world, oldim, oldrc, callback) { PaintEditorMorph.prototype.openIn = function(world, oldim, oldrc, callback) {
// Open the editor in a world with an optional image to edit
this.setCenter(world.center()); this.setCenter(world.center());
this.oldim = oldim; this.oldim = oldim;
this.oldrc = oldrc.copy(); this.oldrc = oldrc.copy();
@ -194,29 +222,40 @@ PaintEditorMorph.prototype.openIn = function(world, oldim, oldrc, callback) {
this.shift = this.world().currentKey === 16; this.shift = this.world().currentKey === 16;
this.propertiesControls.constrain.refresh(); this.propertiesControls.constrain.refresh();
}; };
this.fixLayout(); // merge oldim - factor out into separate function
this.changed(); //merge oldim:
if (this.oldim) {
this.paper.centermerge(this.oldim, this.paper.paper);
this.paper.rotationCenter =
this.oldrc.add(
new Point(
(this.paper.paper.width - this.oldim.width) / 2,
(this.paper.paper.height - this.oldim.height) / 2
)
);
this.paper.drawNew();
}
this.fullChanged();
}; };
PaintEditorMorph.prototype.fixLayout = function() { PaintEditorMorph.prototype.fixLayout = function() {
if (this.paper) { var oldFlag = Morph.prototype.trackChanges;
this.paper.setExtent(new Point(480, 360));
this.paper.fixLayout(); this.changed();
if (this.oldim) { oldFlag = Morph.prototype.trackChanges;
this.paper.centermerge(this.oldim, this.paper.paper); Morph.prototype.trackChanges = false;
this.paper.rotationCenter =
this.oldrc.add( if (this.paper) {
new Point( this.paper.buildContents();
(this.paper.paper.width - this.oldim.width) / 2,
(this.paper.paper.height - this.oldim.height) / 2
)
);
}
this.paper.drawNew(); this.paper.drawNew();
} }
if (this.controls) {this.controls.fixLayout(); } if (this.controls) {this.controls.fixLayout(); }
if (this.body) {this.body.fixLayout(); } if (this.body) {this.body.fixLayout(); }
PaintEditorMorph.uber.fixLayout.call(this); PaintEditorMorph.uber.fixLayout.call(this);
Morph.prototype.trackChanges = oldFlag;
this.changed();
}; };
PaintEditorMorph.prototype.refreshToolButtons = function() { PaintEditorMorph.prototype.refreshToolButtons = function() {
@ -232,6 +271,11 @@ PaintEditorMorph.prototype.ok = function() {
); );
this.destroy(); this.destroy();
}; };
PaintEditorMorph.prototype.cancel = function () {
if (this.oncancel) {this.oncancel(); }
this.destroy();
};
PaintEditorMorph.prototype.populatePropertiesMenu = function() { PaintEditorMorph.prototype.populatePropertiesMenu = function() {
var c = this.controls, var c = this.controls,
@ -317,7 +361,7 @@ PaintEditorMorph.prototype.populatePropertiesMenu = function() {
c.add(pc.colorpicker); c.add(pc.colorpicker);
//c.add(pc.primaryColorButton); //c.add(pc.primaryColorButton);
c.add(pc.primaryColorViewer); c.add(pc.primaryColorViewer);
c.add(new TextMorph("Pen size")); c.add(new TextMorph("Brush size"));
c.add(alpen); c.add(alpen);
c.add(pc.constrain); c.add(pc.constrain);
}; };
@ -354,8 +398,8 @@ PaintEditorMorph.prototype.pushButton = function(title, action, hint) {
}; };
// AdvancedColorPickerMorph ////////////////// // AdvancedColorPickerMorph //////////////////
// A large hsl color picker // A large hsl color picker
//////////////////////////////////////////////
PaintColorPickerMorph.prototype = new Morph(); PaintColorPickerMorph.prototype = new Morph();
PaintColorPickerMorph.prototype.constructor = PaintColorPickerMorph; PaintColorPickerMorph.prototype.constructor = PaintColorPickerMorph;
@ -425,11 +469,13 @@ PaintColorPickerMorph.prototype.mouseDownLeft = function(pos) {
}; };
PaintColorPickerMorph.prototype.mouseMove = PaintColorPickerMorph.prototype.mouseMove =
PaintColorPickerMorph.prototype.mouseDownLeft; PaintColorPickerMorph.prototype.mouseDownLeft;
// PaintCanvasMorph ///////////////////////////
// A canvas which reacts to drag events to // PaintCanvasMorph ///////////////////////////
// modify its image, based on a 'tool' property. /*
/////////////////////////////////////////////// A canvas which reacts to drag events to
modify its image, based on a 'tool' property.
*/
PaintCanvasMorph.prototype = new Morph(); PaintCanvasMorph.prototype = new Morph();
PaintCanvasMorph.prototype.constructor = PaintCanvasMorph; PaintCanvasMorph.prototype.constructor = PaintCanvasMorph;
@ -440,14 +486,13 @@ function PaintCanvasMorph(shift) {
} }
PaintCanvasMorph.prototype.init = function(shift) { PaintCanvasMorph.prototype.init = function(shift) {
this.fixLayout();
this.rotationCenter = new Point(240, 180); this.rotationCenter = new Point(240, 180);
this.dragRect = null; this.dragRect = null;
this.previousDragPoint = null; this.previousDragPoint = null;
this.currentTool = "brush"; this.currentTool = "brush";
this.dragRect = new Rectangle(); this.dragRect = new Rectangle();
// rectangle with origin being the starting drag position and // rectangle with origin being the starting drag position and
// corner being the current drag position // corner being the current drag position
this.mask = newCanvas(this.extent()); // Temporary canvas this.mask = newCanvas(this.extent()); // Temporary canvas
this.paper = newCanvas(this.extent()); // Actual canvas this.paper = newCanvas(this.extent()); // Actual canvas
this.erasermask = newCanvas(this.extent()); // eraser memory this.erasermask = newCanvas(this.extent()); // eraser memory
@ -462,7 +507,8 @@ PaintCanvasMorph.prototype.init = function(shift) {
this.isShiftPressed = shift || function() { this.isShiftPressed = shift || function() {
var key = this.world().currentKey; var key = this.world().currentKey;
return (key === 16); return (key === 16);
}; };
this.buildContents();
}; };
PaintCanvasMorph.prototype.cacheUndo = function() { PaintCanvasMorph.prototype.cacheUndo = function() {
@ -483,7 +529,8 @@ PaintCanvasMorph.prototype.undo = function() {
PaintCanvasMorph.prototype.merge = function(a, b) { PaintCanvasMorph.prototype.merge = function(a, b) {
b.getContext("2d").drawImage(a, 0, 0); b.getContext("2d").drawImage(a, 0, 0);
}; };
PaintCanvasMorph.prototype.centermerge = function(a, b) { PaintCanvasMorph.prototype.centermerge = function(a, b) {
b.getContext("2d").drawImage( b.getContext("2d").drawImage(
a, a,
@ -507,33 +554,60 @@ PaintCanvasMorph.prototype.toolChanged = function(tool) {
this.changed(); this.changed();
}; };
PaintCanvasMorph.prototype.drawcrosshair = function() { PaintCanvasMorph.prototype.drawcrosshair = function(context) {
var mctx = this.mask.getContext("2d"), var ctx = context || this.mask.getContext("2d"),
pos = this.rotationCenter; rp = this.rotationCenter;
mctx.strokeStyle = "rgba(0,0,0,0.6)"; ctx.lineWidth = 1;
mctx.lineWidth = 5; ctx.strokeStyle = 'black';
mctx.beginPath(); ctx.clearRect(0, 0, this.mask.width, this.mask.height);
mctx.moveTo(pos.x, 0);
mctx.lineTo(pos.x, this.extent().y); // draw crosshairs:
mctx.moveTo(0, pos.y); ctx.globalAlpha = 0.5;
mctx.lineTo(this.extent().x, pos.y);
mctx.stroke(); // circle around center:
ctx.fillStyle = 'white';
mctx.strokeStyle = "rgba(255,255,255,0.6)"; ctx.beginPath();
mctx.lineWidth = 1; ctx.arc(
mctx.beginPath(); rp.x,
mctx.moveTo(pos.x, 0); rp.y,
mctx.lineTo(pos.x, this.extent().y); 20,
mctx.moveTo(0, pos.y); radians(0),
mctx.lineTo(this.extent().x, pos.y); radians(360),
mctx.stroke(); false
);
ctx.closePath();
ctx.fill();
ctx.stroke();
ctx.beginPath();
ctx.arc(
rp.x,
rp.y,
10,
radians(0),
radians(360),
false
);
ctx.stroke();
// horizontal line:
ctx.beginPath();
ctx.moveTo(0, rp.y);
ctx.lineTo(this.mask.width, rp.y);
ctx.stroke();
// vertical line:
ctx.beginPath();
ctx.moveTo(rp.x, 0);
ctx.lineTo(rp.x, this.mask.height);
ctx.stroke();
this.drawNew(); this.drawNew();
this.changed(); this.changed();
}; };
PaintCanvasMorph.prototype.floodfill = function(sourcepoint) { PaintCanvasMorph.prototype.floodfill = function(sourcepoint) {
var width = this.paper.width, var width = this.paper.width,
height = this.paper.height, height = this.paper.height,
ctx = this.paper.getContext("2d"), ctx = this.paper.getContext("2d"),
@ -555,7 +629,7 @@ PaintCanvasMorph.prototype.floodfill = function(sourcepoint) {
p[2] === sourcecolor[2] && p[2] === sourcecolor[2] &&
p[3] === sourcecolor[3]; p[3] === sourcecolor[3];
}; };
while (stack.length > 0) { while (stack.length > 0) {
currentpoint = stack.pop(); currentpoint = stack.pop();
if (checkpoint(read(currentpoint))) { if (checkpoint(read(currentpoint))) {
if (currentpoint % 480 > 1) { if (currentpoint % 480 > 1) {
@ -576,7 +650,9 @@ PaintCanvasMorph.prototype.floodfill = function(sourcepoint) {
data[currentpoint * 4 + 3] = this.settings.primarycolor.a; data[currentpoint * 4 + 3] = this.settings.primarycolor.a;
} }
} }
ctx.putImageData(img, 0, 0); ctx.putImageData(img, 0, 0);
this.drawNew();
this.changed();
}; };
PaintCanvasMorph.prototype.mouseDownLeft = function(pos) { PaintCanvasMorph.prototype.mouseDownLeft = function(pos) {
@ -584,8 +660,13 @@ PaintCanvasMorph.prototype.mouseDownLeft = function(pos) {
this.dragRect.origin = pos.subtract(this.bounds.origin); this.dragRect.origin = pos.subtract(this.bounds.origin);
this.dragRect.corner = pos.subtract(this.bounds.origin); this.dragRect.corner = pos.subtract(this.bounds.origin);
this.previousDragPoint = this.dragRect.corner.copy(); this.previousDragPoint = this.dragRect.corner.copy();
if (this.currentTool === 'crosshairs') {
this.rotationCenter = pos.subtract(this.bounds.origin);
this.drawcrosshair();
return;
}
if (this.currentTool === "paintbucket") { if (this.currentTool === "paintbucket") {
this.floodfill(pos.subtract(this.bounds.origin)); return this.floodfill(pos.subtract(this.bounds.origin));
} }
if (this.settings.primarycolor === "transparent" && if (this.settings.primarycolor === "transparent" &&
this.currentTool !== "crosshairs") { this.currentTool !== "crosshairs") {
@ -594,7 +675,11 @@ PaintCanvasMorph.prototype.mouseDownLeft = function(pos) {
} }
}; };
PaintCanvasMorph.prototype.mouseMove = function(pos) { PaintCanvasMorph.prototype.mouseMove = function(pos) {
if (this.currentTool === "paintbucket") {
return;
}
var relpos = pos.subtract(this.bounds.origin), var relpos = pos.subtract(this.bounds.origin),
mctx = this.mask.getContext("2d"), mctx = this.mask.getContext("2d"),
pctx = this.paper.getContext("2d"), pctx = this.paper.getContext("2d"),
@ -707,27 +792,9 @@ PaintCanvasMorph.prototype.mouseMove = function(pos) {
} }
} }
break; break;
case "crosshairs": case "crosshairs":
mctx.save(); this.rotationCenter = relpos.copy();
mctx.globalCompositeOperation = "source-over"; this.drawcrosshair(mctx);
mctx.strokeStyle = "rgba(0,0,0,0.6)";
mctx.lineWidth = 5;
mctx.beginPath();
mctx.moveTo(p, 0);
mctx.lineTo(p, this.extent().y);
mctx.moveTo(0, q);
mctx.lineTo(this.extent().x, q);
mctx.stroke();
mctx.strokeStyle = "rgba(255,255,255,0.6)";
mctx.lineWidth = 1;
mctx.beginPath();
mctx.moveTo(p, 0);
mctx.lineTo(p, this.extent().y);
mctx.moveTo(0, q);
mctx.lineTo(this.extent().x, q);
mctx.stroke();
this.rotationCenter = relpos.copy();
mctx.restore();
break; break;
case "eraser": case "eraser":
this.merge(this.paper, this.mask); this.merge(this.paper, this.mask);
@ -752,30 +819,30 @@ PaintCanvasMorph.prototype.mouseMove = function(pos) {
mctx.restore(); mctx.restore();
}; };
PaintCanvasMorph.prototype.mouseClickLeft = function() { PaintCanvasMorph.prototype.mouseClickLeft = function() {
if (this.currentTool !== "crosshairs") { if (this.currentTool !== "crosshairs") {
this.merge(this.mask, this.paper); this.merge(this.mask, this.paper);
} }
this.brushBuffer = []; this.brushBuffer = [];
}; };
PaintCanvasMorph.prototype.fixLayout = function() { PaintCanvasMorph.prototype.buildContents = function() {
this.background = newCanvas(this.extent()); this.background = newCanvas(this.extent());
this.paper = newCanvas(this.extent()); this.paper = newCanvas(this.extent());
this.mask = newCanvas(this.extent()); this.mask = newCanvas(this.extent());
this.erasermask = newCanvas(this.extent()); this.erasermask = newCanvas(this.extent());
var i, j, bkctx = this.background.getContext("2d"); var i, j, bkctx = this.background.getContext("2d");
for (i = 0; i < this.background.width; i += 5) { for (i = 0; i < this.background.width; i += 5) {
for (j = 0; j < this.background.height; j += 5) { for (j = 0; j < this.background.height; j += 5) {
if ((i + j) / 5 % 2 === 1) { if ((i + j) / 5 % 2 === 1) {
bkctx.fillStyle = "rgba(255, 255, 255, 1)"; bkctx.fillStyle = "rgba(255, 255, 255, 1)";
} else { } else {
bkctx.fillStyle = "rgba(255, 255, 255, 0.3)"; bkctx.fillStyle = "rgba(255, 255, 255, 0.3)";
} }
bkctx.fillRect(i, j, 5, 5); bkctx.fillRect(i, j, 5, 5);
} }
} }
}; };
PaintCanvasMorph.prototype.drawNew = function() { PaintCanvasMorph.prototype.drawNew = function() {
var can = newCanvas(this.extent()); var can = newCanvas(this.extent());
@ -825,9 +892,16 @@ PaintCanvasMorph.prototype.contrast
// These will be incorporated into the respective files later // These will be incorporated into the respective files later
// They add costume editing functionality to Snap!. // They add costume editing functionality to Snap!.
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
CostumeIconMorph.prototype.editCostume = function () {
var ide = this.parentThatIsA(IDE_Morph); CostumeIconMorph.prototype.editCostume = function () {
this.object.edit(this.world(), ide); if (this.object instanceof SVG_Costume) {
this.object.editRotationPointOnly(this.world());
} else {
this.object.edit(
this.world(),
this.parentThatIsA(IDE_Morph)
);
}
}; };
Costume.prototype.edit = function (aWorld, anIDE, isnew, oncancel, onsubmit) { Costume.prototype.edit = function (aWorld, anIDE, isnew, oncancel, onsubmit) {
@ -857,9 +931,6 @@ Costume.prototype.edit = function (aWorld, anIDE, isnew, oncancel, onsubmit) {
); );
}; };
IDE_Morph.prototype.createCorralBar = function () { IDE_Morph.prototype.createCorralBar = function () {
// assumes the stage has already been created // assumes the stage has already been created
var padding = 5, var padding = 5,
@ -869,14 +940,17 @@ IDE_Morph.prototype.createCorralBar = function () {
this.groupColor, this.groupColor,
this.frameColor.darker(50), this.frameColor.darker(50),
this.frameColor.darker(50) this.frameColor.darker(50)
]; ];
if (this.corralBar) { if (this.corralBar) {
this.corralBar.destroy(); this.corralBar.destroy();
} }
this.corralBar = new Morph(); this.corralBar = new Morph();
this.corralBar.color = this.frameColor; this.corralBar.color = this.frameColor;
this.corralBar.setHeight(this.logo.height()); // height is fixed this.corralBar.setHeight(this.logo.height()); // height is fixed
this.add(this.corralBar); this.add(this.corralBar);
// new sprite button // new sprite button
newbutton = new PushButtonMorph( newbutton = new PushButtonMorph(
this, this,
@ -899,6 +973,7 @@ IDE_Morph.prototype.createCorralBar = function () {
newbutton.setCenter(this.corralBar.center()); newbutton.setCenter(this.corralBar.center());
newbutton.setLeft(this.corralBar.left() + padding); newbutton.setLeft(this.corralBar.left() + padding);
this.corralBar.add(newbutton); this.corralBar.add(newbutton);
paintbutton = new PushButtonMorph( paintbutton = new PushButtonMorph(
this, this,
"paintNewSprite", "paintNewSprite",
@ -922,21 +997,31 @@ IDE_Morph.prototype.createCorralBar = function () {
this.corralBar.left() + padding + newbutton.width() + padding this.corralBar.left() + padding + newbutton.width() + padding
); );
this.corralBar.add(paintbutton); this.corralBar.add(paintbutton);
}; };
IDE_Morph.prototype.paintNewSprite = function() { IDE_Morph.prototype.paintNewSprite = function() {
var sprite = new SpriteMorph(this.globalVariables), var sprite = new SpriteMorph(this.globalVariables),
cos = new Costume(); cos = new Costume(),
sprite.name = sprite.name + myself = this;
(this.corral.frame.contents.children.length + 1);
sprite.setCenter(this.stage.center()); sprite.name = sprite.name +
this.stage.add(sprite); (this.corral.frame.contents.children.length + 1);
this.sprites.add(sprite); sprite.setCenter(this.stage.center());
this.corral.addSprite(sprite); this.stage.add(sprite);
this.selectSprite(sprite); this.sprites.add(sprite);
cos.edit(this.world(), this, true, function() {sprite.remove(); }); this.corral.addSprite(sprite);
sprite.addCostume(cos); this.selectSprite(sprite);
}; cos.edit(
this.world(),
this,
true,
function() {myself.removeSprite(sprite); },
function () {
sprite.addCostume(cos);
sprite.wearCostume(cos);
}
);
};
WardrobeMorph.prototype.updateList = function () { WardrobeMorph.prototype.updateList = function () {
var myself = this, var myself = this,
@ -948,15 +1033,12 @@ WardrobeMorph.prototype.updateList = function () {
icon, icon,
template, template,
txt, txt,
paintbutton, paintbutton;
colors = [
new Color(50, 50, 50, 1),
new Color(60, 60, 60, 1),
new Color(70, 70, 70, 1)
];
this.changed(); this.changed();
oldFlag = Morph.prototype.trackChanges; oldFlag = Morph.prototype.trackChanges;
Morph.prototype.trackChanges = false; Morph.prototype.trackChanges = false;
this.contents.destroy(); this.contents.destroy();
this.contents = new FrameMorph(this); this.contents = new FrameMorph(this);
this.contents.acceptsDrops = false; this.contents.acceptsDrops = false;
@ -964,6 +1046,7 @@ WardrobeMorph.prototype.updateList = function () {
myself.reactToDropOf(icon); myself.reactToDropOf(icon);
}; };
this.addBack(this.contents); this.addBack(this.contents);
icon = new TurtleIconMorph(this.sprite); icon = new TurtleIconMorph(this.sprite);
icon.setPosition(new Point(x, y)); icon.setPosition(new Point(x, y));
myself.addContents(icon); myself.addContents(icon);
@ -974,31 +1057,37 @@ WardrobeMorph.prototype.updateList = function () {
"paintNew", "paintNew",
new SymbolMorph("brush", 15) new SymbolMorph("brush", 15)
); );
paintbutton.padding = 5; paintbutton.padding = 0;
paintbutton.corner = 12; paintbutton.corner = 12;
paintbutton.color = colors[0]; paintbutton.color = IDE_Morph.prototype.groupColor;
paintbutton.highlightColor = colors[1]; paintbutton.highlightColor = IDE_Morph.prototype.frameColor.darker(50);
paintbutton.pressColor = colors[2]; paintbutton.pressColor = paintbutton.highlightColor;
paintbutton.labelMinExtent = new Point(36, 18); paintbutton.labelMinExtent = new Point(36, 18);
paintbutton.labelShadowOffset = new Point(-1, -1); paintbutton.labelShadowOffset = new Point(-1, -1);
paintbutton.labelShadowColor = colors[1]; paintbutton.labelShadowColor = paintbutton.highlightColor;
paintbutton.labelColor = new Color(255, 255, 255); paintbutton.labelColor = new Color(255, 255, 255);
paintbutton.contrast = this.buttonContrast; paintbutton.contrast = this.buttonContrast;
paintbutton.drawNew(); paintbutton.drawNew();
paintbutton.hint = "Paint a new costume"; paintbutton.hint = "Paint a new costume";
paintbutton.setPosition(new Point(x, y)); paintbutton.setPosition(new Point(x, y));
paintbutton.fixLayout(); paintbutton.fixLayout();
paintbutton.setCenter(icon.center());
paintbutton.setLeft(icon.right() + padding * 4);
this.addContents(paintbutton); this.addContents(paintbutton);
y = paintbutton.bottom() + padding;
txt = new TextMorph(localize( txt = new TextMorph(localize(
"costumes tab help" // look up long string in translator "costumes tab help" // look up long string in translator
)); ));
txt.fontSize = 9; txt.fontSize = 9;
txt.setColor(new Color(230, 230, 230)); txt.setColor(new Color(230, 230, 230));
txt.setPosition(new Point(x, y)); txt.setPosition(new Point(x, y));
this.addContents(txt); this.addContents(txt);
y = txt.bottom() + padding; y = txt.bottom() + padding;
this.sprite.costumes.asArray().forEach(function (costume) { this.sprite.costumes.asArray().forEach(function (costume) {
template = icon = new CostumeIconMorph(costume, template); template = icon = new CostumeIconMorph(costume, template);
icon.setPosition(new Point(x, y)); icon.setPosition(new Point(x, y));
@ -1006,10 +1095,12 @@ WardrobeMorph.prototype.updateList = function () {
y = icon.bottom() + padding; y = icon.bottom() + padding;
}); });
this.costumesVersion = this.sprite.costumes.lastChanged; this.costumesVersion = this.sprite.costumes.lastChanged;
this.contents.setPosition(oldPos); this.contents.setPosition(oldPos);
this.adjustScrollBars(); this.adjustScrollBars();
Morph.prototype.trackChanges = oldFlag; Morph.prototype.trackChanges = oldFlag;
this.changed(); this.changed();
this.updateSelection(); this.updateSelection();
}; };
@ -1029,6 +1120,14 @@ CostumeIconMorph.prototype.userMenu = function () {
var menu = new MenuMorph(this); var menu = new MenuMorph(this);
if (!(this.object instanceof Costume)) {return null; } if (!(this.object instanceof Costume)) {return null; }
menu.addItem("edit", "editCostume"); menu.addItem("edit", "editCostume");
if (this.world().currentKey === 16) { // shift clicked
menu.addItem(
'edit rotation point only...',
'editRotationPointOnly',
null,
new Color(100, 0, 0)
);
}
menu.addItem("rename", "renameCostume"); menu.addItem("rename", "renameCostume");
menu.addLine(); menu.addLine();
menu.addItem("duplicate", "duplicateCostume"); menu.addItem("duplicate", "duplicateCostume");
@ -1058,7 +1157,6 @@ CostumeIconMorph.prototype.duplicateCostume = function() {
} }
}; };
// I had to change this because adding a "paint new" button changed the offset // I had to change this because adding a "paint new" button changed the offset
// of the costume (so the 5th child would be the 3rd costume, not the 4th as // of the costume (so the 5th child would be the 3rd costume, not the 4th as
// it was before with only the text morph child). // it was before with only the text morph child).
@ -1072,7 +1170,6 @@ CostumeIconMorph.prototype.removeCostume = function () {
} }
}; };
Costume.prototype.shrinkWrap = function () { Costume.prototype.shrinkWrap = function () {
// adjust my contents' bounds to my visible bounding box // adjust my contents' bounds to my visible bounding box
var bb = this.boundingBox(), var bb = this.boundingBox(),