kopia lustrzana https://github.com/backface/turtlestitch
Paint editor fixes
rodzic
f5e101dc57
commit
3f92313ae4
443
paint.js
443
paint.js
|
@ -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(),
|
||||||
|
|
Ładowanie…
Reference in New Issue