summaryrefslogtreecommitdiff
path: root/paint.js
diff options
context:
space:
mode:
authorjmoenig <jens@moenig.org>2014-01-08 15:17:03 +0100
committerjmoenig <jens@moenig.org>2014-01-08 15:17:03 +0100
commitb9f8ef9951f2a534556925ad7a2776281f7e18c5 (patch)
tree868a5969e7f4a7f0b90ce80ec84e9dd75ec44e8a /paint.js
parent0020aeda14d7f7aea89f88c32fc06fcb3e077d40 (diff)
downloadsnap-byow-b9f8ef9951f2a534556925ad7a2776281f7e18c5.tar.gz
snap-byow-b9f8ef9951f2a534556925ad7a2776281f7e18c5.zip
add mouseLeaveDragging() behavior to the paint editor, thanks, Kartik!
All credit for fixing this goes to Kartik. This also seems to change just about every line ending for reasons known only to Xcode. Sorry Kartik, for not pulling your request because of those line endings, they are inevitable!
Diffstat (limited to 'paint.js')
-rw-r--r--paint.js1430
1 files changed, 717 insertions, 713 deletions
diff --git a/paint.js b/paint.js
index 44585b2..15b4172 100644
--- a/paint.js
+++ b/paint.js
@@ -1,14 +1,14 @@
-/*
+/*
paint.js
-
- a paint editor for Snap!
- inspired by the Scratch paint editor.
-
+
+ a paint editor for Snap!
+ inspired by the Scratch paint editor.
+
written by Kartik Chandra
- Copyright (C) 2013 by Kartik Chandra
-
- This file is part of Snap!.
-
+ Copyright (C) 2013 by Kartik Chandra
+
+ 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
@@ -50,186 +50,187 @@
May 16 - flat design adjustments (Jens)
July 12 - pipette tool, code formatting adjustments (Jens)
September 16 - flood fill freeze fix (Kartik)
+ Jan 08 - mouse leave dragging fix (Kartik)
+
+ */
- */
-
-/*global Point, Rectangle, DialogBoxMorph, fontHeight, AlignmentMorph,
- FrameMorph, PushButtonMorph, Color, SymbolMorph, newCanvas, Morph, TextMorph,
- CostumeIconMorph, IDE_Morph, Costume, SpriteMorph, nop, Image, WardrobeMorph,
- TurtleIconMorph, localize, MenuMorph, InputFieldMorph, SliderMorph,
+/*global Point, Rectangle, DialogBoxMorph, fontHeight, AlignmentMorph,
+ FrameMorph, PushButtonMorph, Color, SymbolMorph, newCanvas, Morph, TextMorph,
+ CostumeIconMorph, IDE_Morph, Costume, SpriteMorph, nop, Image, WardrobeMorph,
+ TurtleIconMorph, localize, MenuMorph, InputFieldMorph, SliderMorph,
ToggleMorph, ToggleButtonMorph, BoxMorph, modules, radians,
- MorphicPreferences, getDocumentPositionOf
- */
-
+ MorphicPreferences, getDocumentPositionOf
+ */
+
// Global stuff ////////////////////////////////////////////////////////
-modules.paint = '2013-September-16';
+modules.paint = '2014-January-08';
// Declarations
-var PaintEditorMorph;
-var PaintCanvasMorph;
-var PaintColorPickerMorph;
-
-// PaintEditorMorph //////////////////////////
+var PaintEditorMorph;
+var PaintCanvasMorph;
+var PaintColorPickerMorph;
+
+// PaintEditorMorph //////////////////////////
+
+// A complete paint editor
-// A complete paint editor
-
-PaintEditorMorph.prototype = new DialogBoxMorph();
-PaintEditorMorph.prototype.constructor = PaintEditorMorph;
-PaintEditorMorph.uber = DialogBoxMorph.prototype;
-
-PaintEditorMorph.prototype.padding = 10;
-
-function PaintEditorMorph() {
- this.init();
-}
-
-PaintEditorMorph.prototype.init = function () {
- // additional properties:
+PaintEditorMorph.prototype = new DialogBoxMorph();
+PaintEditorMorph.prototype.constructor = PaintEditorMorph;
+PaintEditorMorph.uber = DialogBoxMorph.prototype;
+
+PaintEditorMorph.prototype.padding = 10;
+
+function PaintEditorMorph() {
+ this.init();
+}
+
+PaintEditorMorph.prototype.init = function () {
+ // additional properties:
this.paper = null; // paint canvas
- this.oncancel = null;
-
- // initialize inherited properties:
- PaintEditorMorph.uber.init.call(this);
-
- // override inherited properties:
- this.labelString = "Paint Editor";
- this.createLabel();
-
- // build contents:
- this.buildContents();
-};
-
-PaintEditorMorph.prototype.buildContents = function () {
- var myself = this;
-
+ this.oncancel = null;
+
+ // initialize inherited properties:
+ PaintEditorMorph.uber.init.call(this);
+
+ // override inherited properties:
+ this.labelString = "Paint Editor";
+ this.createLabel();
+
+ // build contents:
+ this.buildContents();
+};
+
+PaintEditorMorph.prototype.buildContents = function () {
+ var myself = this;
+
this.paper = new PaintCanvasMorph(function () {return myself.shift; });
- this.paper.setExtent(new Point(480, 360));
-
- this.addBody(new AlignmentMorph('row', this.padding));
- this.controls = new AlignmentMorph('column', this.padding);
- this.controls.alignment = 'left';
-
- this.edits = new AlignmentMorph('row', this.padding);
- this.buildEdits();
- this.controls.add(this.edits);
-
- this.body.color = this.color;
-
- this.body.add(this.controls);
- this.body.add(this.paper);
-
- this.toolbox = new BoxMorph();
- this.toolbox.color = SpriteMorph.prototype.paletteColor.lighter(8);
+ this.paper.setExtent(new Point(480, 360));
+
+ this.addBody(new AlignmentMorph('row', this.padding));
+ this.controls = new AlignmentMorph('column', this.padding);
+ this.controls.alignment = 'left';
+
+ this.edits = new AlignmentMorph('row', this.padding);
+ this.buildEdits();
+ this.controls.add(this.edits);
+
+ this.body.color = this.color;
+
+ this.body.add(this.controls);
+ this.body.add(this.paper);
+
+ this.toolbox = new BoxMorph();
+ this.toolbox.color = SpriteMorph.prototype.paletteColor.lighter(8);
this.toolbox.borderColor = this.toolbox.color.lighter(40);
if (MorphicPreferences.isFlat) {
this.toolbox.edge = 0;
- }
-
- this.buildToolbox();
- this.controls.add(this.toolbox);
-
- this.propertiesControls = {
- colorpicker: null,
- penSizeSlider: null,
- penSizeField: null,
- primaryColorButton: null,
- primaryColorViewer: null,
- constrain: null
- };
- this.populatePropertiesMenu();
-
- this.addButton("ok", "OK");
- this.addButton("cancel", "Cancel");
-
- this.refreshToolButtons();
- this.fixLayout();
- this.drawNew();
-};
-
-PaintEditorMorph.prototype.buildToolbox = function () {
- var tools = {
- brush:
- "Paintbrush tool\n(free draw)",
- rectangle:
- "Stroked Rectangle\n(shift: square)",
- circle:
- "Stroked Ellipse\n(shift: circle)",
- eraser:
- "Eraser tool",
- crosshairs:
- "Set the rotation center",
-
- line:
- "Line tool\n(shift: vertical/horizontal)",
- rectangleSolid:
- "Filled Rectangle\n(shift: square)",
- circleSolid:
- "Filled Ellipse\n(shift: circle)",
- paintbucket:
- "Fill a region",
+ }
+
+ this.buildToolbox();
+ this.controls.add(this.toolbox);
+
+ this.propertiesControls = {
+ colorpicker: null,
+ penSizeSlider: null,
+ penSizeField: null,
+ primaryColorButton: null,
+ primaryColorViewer: null,
+ constrain: null
+ };
+ this.populatePropertiesMenu();
+
+ this.addButton("ok", "OK");
+ this.addButton("cancel", "Cancel");
+
+ this.refreshToolButtons();
+ this.fixLayout();
+ this.drawNew();
+};
+
+PaintEditorMorph.prototype.buildToolbox = function () {
+ var tools = {
+ brush:
+ "Paintbrush tool\n(free draw)",
+ rectangle:
+ "Stroked Rectangle\n(shift: square)",
+ circle:
+ "Stroked Ellipse\n(shift: circle)",
+ eraser:
+ "Eraser tool",
+ crosshairs:
+ "Set the rotation center",
+
+ line:
+ "Line tool\n(shift: vertical/horizontal)",
+ rectangleSolid:
+ "Filled Rectangle\n(shift: square)",
+ circleSolid:
+ "Filled Ellipse\n(shift: circle)",
+ paintbucket:
+ "Fill a region",
pipette:
"Pipette tool\n(pick a color anywhere)"
- },
- myself = this,
- left = this.toolbox.left(),
- top = this.toolbox.top(),
- padding = 2,
- inset = 5,
- x = 0,
- y = 0;
-
- Object.keys(tools).forEach(function (tool) {
- var btn = myself.toolButton(tool, tools[tool]);
- btn.setPosition(new Point(
- left + x,
- top + y
- ));
- x += btn.width() + padding;
- if (tool === "crosshairs") {
- x = 0;
- y += btn.height() + padding;
- myself.paper.drawcrosshair();
- }
- myself.toolbox[tool] = btn;
- myself.toolbox.add(btn);
- });
-
- this.toolbox.bounds = this.toolbox.fullBounds().expandBy(inset * 2);
- this.toolbox.drawNew();
-};
-
-PaintEditorMorph.prototype.buildEdits = function () {
- var paper = this.paper;
-
- this.edits.add(this.pushButton(
- "undo",
- function () {paper.undo(); }
- ));
-
- this.edits.add(this.pushButton(
- "clear",
- function () {paper.clearCanvas(); }
- ));
- this.edits.fixLayout();
-};
-
-PaintEditorMorph.prototype.openIn = function (world, oldim, oldrc, callback) {
+ },
+ myself = this,
+ left = this.toolbox.left(),
+ top = this.toolbox.top(),
+ padding = 2,
+ inset = 5,
+ x = 0,
+ y = 0;
+
+ Object.keys(tools).forEach(function (tool) {
+ var btn = myself.toolButton(tool, tools[tool]);
+ btn.setPosition(new Point(
+ left + x,
+ top + y
+ ));
+ x += btn.width() + padding;
+ if (tool === "crosshairs") {
+ x = 0;
+ y += btn.height() + padding;
+ myself.paper.drawcrosshair();
+ }
+ myself.toolbox[tool] = btn;
+ myself.toolbox.add(btn);
+ });
+
+ this.toolbox.bounds = this.toolbox.fullBounds().expandBy(inset * 2);
+ this.toolbox.drawNew();
+};
+
+PaintEditorMorph.prototype.buildEdits = function () {
+ var paper = this.paper;
+
+ this.edits.add(this.pushButton(
+ "undo",
+ function () {paper.undo(); }
+ ));
+
+ this.edits.add(this.pushButton(
+ "clear",
+ function () {paper.clearCanvas(); }
+ ));
+ this.edits.fixLayout();
+};
+
+PaintEditorMorph.prototype.openIn = function (world, oldim, oldrc, callback) {
// Open the editor in a world with an optional image to edit
- this.oldim = oldim;
- this.oldrc = oldrc.copy();
- this.callback = callback || nop;
+ this.oldim = oldim;
+ this.oldrc = oldrc.copy();
+ this.callback = callback || nop;
- this.processKeyUp = function () {
- this.shift = false;
- this.propertiesControls.constrain.refresh();
- };
+ this.processKeyUp = function () {
+ this.shift = false;
+ this.propertiesControls.constrain.refresh();
+ };
- this.processKeyDown = function () {
- this.shift = this.world().currentKey === 16;
- this.propertiesControls.constrain.refresh();
- };
+ this.processKeyDown = function () {
+ this.shift = this.world().currentKey === 16;
+ this.propertiesControls.constrain.refresh();
+ };
//merge oldim:
if (this.oldim) {
@@ -244,170 +245,170 @@ PaintEditorMorph.prototype.openIn = function (world, oldim, oldrc, callback) {
this.paper.drawNew();
}
- this.key = 'paint';
- this.popUp(world);
-};
-
+ this.key = 'paint';
+ this.popUp(world);
+};
+
PaintEditorMorph.prototype.fixLayout = function () {
var oldFlag = Morph.prototype.trackChanges;
-
+
this.changed();
oldFlag = Morph.prototype.trackChanges;
Morph.prototype.trackChanges = false;
if (this.paper) {
this.paper.buildContents();
- this.paper.drawNew();
- }
- if (this.controls) {this.controls.fixLayout(); }
- if (this.body) {this.body.fixLayout(); }
- PaintEditorMorph.uber.fixLayout.call(this);
+ this.paper.drawNew();
+ }
+ if (this.controls) {this.controls.fixLayout(); }
+ if (this.body) {this.body.fixLayout(); }
+ PaintEditorMorph.uber.fixLayout.call(this);
Morph.prototype.trackChanges = oldFlag;
this.changed();
-};
-
-PaintEditorMorph.prototype.refreshToolButtons = function () {
- this.toolbox.children.forEach(function (toggle) {
- toggle.refresh();
- });
-};
-
-PaintEditorMorph.prototype.ok = function () {
- this.callback(
- this.paper.paper,
- this.paper.rotationCenter
- );
- this.destroy();
-};
+};
+
+PaintEditorMorph.prototype.refreshToolButtons = function () {
+ this.toolbox.children.forEach(function (toggle) {
+ toggle.refresh();
+ });
+};
+
+PaintEditorMorph.prototype.ok = function () {
+ this.callback(
+ this.paper.paper,
+ this.paper.rotationCenter
+ );
+ this.destroy();
+};
PaintEditorMorph.prototype.cancel = function () {
if (this.oncancel) {this.oncancel(); }
this.destroy();
};
-
-PaintEditorMorph.prototype.populatePropertiesMenu = function () {
- var c = this.controls,
- myself = this,
- pc = this.propertiesControls,
- alpen = new AlignmentMorph("row", this.padding);
-
- pc.primaryColorViewer = new Morph();
- pc.primaryColorViewer.setExtent(new Point(180, 50));
- pc.primaryColorViewer.color = new Color(0, 0, 0);
- pc.colorpicker = new PaintColorPickerMorph(
- new Point(180, 100),
- function (color) {
- var ni = newCanvas(pc.primaryColorViewer.extent()),
- ctx = ni.getContext("2d"),
- i,
- j;
- myself.paper.settings.primarycolor = color;
- if (color === "transparent") {
- for (i = 0; i < 180; i += 5) {
- for (j = 0; j < 15; j += 5) {
- ctx.fillStyle =
- ((j + i) / 5) % 2 === 0 ?
- "rgba(0, 0, 0, 0.2)" :
- "rgba(0, 0, 0, 0.5)";
- ctx.fillRect(i, j, 5, 5);
-
- }
- }
- } else {
- ctx.fillStyle = color.toString();
- ctx.fillRect(0, 0, 180, 15);
- }
- ctx.strokeStyle = "black";
- ctx.lineWidth = Math.min(myself.paper.settings.linewidth, 20);
- ctx.beginPath();
- ctx.lineCap = "round";
- ctx.moveTo(20, 30);
- ctx.lineTo(160, 30);
- ctx.stroke();
- pc.primaryColorViewer.image = ni;
- pc.primaryColorViewer.changed();
- }
- );
- pc.colorpicker.action(new Color(0, 0, 0));
-
- pc.penSizeSlider = new SliderMorph(0, 20, 5, 5);
- pc.penSizeSlider.orientation = "horizontal";
- pc.penSizeSlider.setHeight(15);
- pc.penSizeSlider.setWidth(150);
- pc.penSizeSlider.action = function (num) {
- if (pc.penSizeField) {
- pc.penSizeField.setContents(num);
- }
- myself.paper.settings.linewidth = num;
- pc.colorpicker.action(myself.paper.settings.primarycolor);
- };
- pc.penSizeField = new InputFieldMorph("5", true, null, false);
- pc.penSizeField.contents().minWidth = 20;
- pc.penSizeField.setWidth(25);
- pc.penSizeField.accept = function () {
- var val = parseFloat(pc.penSizeField.getValue());
- pc.penSizeSlider.value = val;
- pc.penSizeSlider.drawNew();
- pc.penSizeSlider.updateValue();
- this.setContents(val);
- myself.paper.settings.linewidth = val;
- this.world().keyboardReceiver = myself;
- pc.colorpicker.action(myself.paper.settings.primarycolor);
- };
- alpen.add(pc.penSizeSlider);
- alpen.add(pc.penSizeField);
- alpen.color = myself.color;
- alpen.fixLayout();
- pc.penSizeField.drawNew();
- pc.constrain = new ToggleMorph(
- "checkbox",
- this,
- function () {myself.shift = !myself.shift; },
- "Constrain proportions of shapes?\n(you can also hold shift)",
- function () {return myself.shift; }
- );
- c.add(pc.colorpicker);
- //c.add(pc.primaryColorButton);
- c.add(pc.primaryColorViewer);
- c.add(new TextMorph("Brush size"));
- c.add(alpen);
- c.add(pc.constrain);
-};
-
-PaintEditorMorph.prototype.toolButton = function (icon, hint) {
- var button, myself = this;
-
- button = new ToggleButtonMorph(
- null,
+
+PaintEditorMorph.prototype.populatePropertiesMenu = function () {
+ var c = this.controls,
+ myself = this,
+ pc = this.propertiesControls,
+ alpen = new AlignmentMorph("row", this.padding);
+
+ pc.primaryColorViewer = new Morph();
+ pc.primaryColorViewer.setExtent(new Point(180, 50));
+ pc.primaryColorViewer.color = new Color(0, 0, 0);
+ pc.colorpicker = new PaintColorPickerMorph(
+ new Point(180, 100),
+ function (color) {
+ var ni = newCanvas(pc.primaryColorViewer.extent()),
+ ctx = ni.getContext("2d"),
+ i,
+ j;
+ myself.paper.settings.primarycolor = color;
+ if (color === "transparent") {
+ for (i = 0; i < 180; i += 5) {
+ for (j = 0; j < 15; j += 5) {
+ ctx.fillStyle =
+ ((j + i) / 5) % 2 === 0 ?
+ "rgba(0, 0, 0, 0.2)" :
+ "rgba(0, 0, 0, 0.5)";
+ ctx.fillRect(i, j, 5, 5);
+
+ }
+ }
+ } else {
+ ctx.fillStyle = color.toString();
+ ctx.fillRect(0, 0, 180, 15);
+ }
+ ctx.strokeStyle = "black";
+ ctx.lineWidth = Math.min(myself.paper.settings.linewidth, 20);
+ ctx.beginPath();
+ ctx.lineCap = "round";
+ ctx.moveTo(20, 30);
+ ctx.lineTo(160, 30);
+ ctx.stroke();
+ pc.primaryColorViewer.image = ni;
+ pc.primaryColorViewer.changed();
+ }
+ );
+ pc.colorpicker.action(new Color(0, 0, 0));
+
+ pc.penSizeSlider = new SliderMorph(0, 20, 5, 5);
+ pc.penSizeSlider.orientation = "horizontal";
+ pc.penSizeSlider.setHeight(15);
+ pc.penSizeSlider.setWidth(150);
+ pc.penSizeSlider.action = function (num) {
+ if (pc.penSizeField) {
+ pc.penSizeField.setContents(num);
+ }
+ myself.paper.settings.linewidth = num;
+ pc.colorpicker.action(myself.paper.settings.primarycolor);
+ };
+ pc.penSizeField = new InputFieldMorph("5", true, null, false);
+ pc.penSizeField.contents().minWidth = 20;
+ pc.penSizeField.setWidth(25);
+ pc.penSizeField.accept = function () {
+ var val = parseFloat(pc.penSizeField.getValue());
+ pc.penSizeSlider.value = val;
+ pc.penSizeSlider.drawNew();
+ pc.penSizeSlider.updateValue();
+ this.setContents(val);
+ myself.paper.settings.linewidth = val;
+ this.world().keyboardReceiver = myself;
+ pc.colorpicker.action(myself.paper.settings.primarycolor);
+ };
+ alpen.add(pc.penSizeSlider);
+ alpen.add(pc.penSizeField);
+ alpen.color = myself.color;
+ alpen.fixLayout();
+ pc.penSizeField.drawNew();
+ pc.constrain = new ToggleMorph(
+ "checkbox",
+ this,
+ function () {myself.shift = !myself.shift; },
+ "Constrain proportions of shapes?\n(you can also hold shift)",
+ function () {return myself.shift; }
+ );
+ c.add(pc.colorpicker);
+ //c.add(pc.primaryColorButton);
+ c.add(pc.primaryColorViewer);
+ c.add(new TextMorph("Brush size"));
+ c.add(alpen);
+ c.add(pc.constrain);
+};
+
+PaintEditorMorph.prototype.toolButton = function (icon, hint) {
+ var button, myself = this;
+
+ button = new ToggleButtonMorph(
+ null,
this,
function () { // action
- myself.paper.currentTool = icon;
- myself.paper.toolChanged(icon);
+ myself.paper.currentTool = icon;
+ myself.paper.toolChanged(icon);
myself.refreshToolButtons();
if (icon === 'pipette') {
myself.getUserColor();
- }
- },
- new SymbolMorph(icon, 18),
- function () {return myself.paper.currentTool === icon; }
- );
-
- button.hint = hint;
- button.drawNew();
- button.fixLayout();
- return button;
-};
-
-PaintEditorMorph.prototype.pushButton = function (title, action, hint) {
- return new PushButtonMorph(
- this,
- action,
- title,
- null,
- hint
- );
-};
+ }
+ },
+ new SymbolMorph(icon, 18),
+ function () {return myself.paper.currentTool === icon; }
+ );
+
+ button.hint = hint;
+ button.drawNew();
+ button.fixLayout();
+ return button;
+};
+
+PaintEditorMorph.prototype.pushButton = function (title, action, hint) {
+ return new PushButtonMorph(
+ this,
+ action,
+ title,
+ null,
+ hint
+ );
+};
PaintEditorMorph.prototype.getUserColor = function () {
var myself = this,
@@ -440,167 +441,167 @@ PaintEditorMorph.prototype.getUserColor = function () {
hand.processMouseUp = mouseUpBak;
};
};
-
-// AdvancedColorPickerMorph //////////////////
-// A large hsl color picker
-
-PaintColorPickerMorph.prototype = new Morph();
-PaintColorPickerMorph.prototype.constructor = PaintColorPickerMorph;
-PaintColorPickerMorph.uber = Morph.prototype;
-
-function PaintColorPickerMorph(extent, action) {
- this.init(extent, action);
-}
-
-PaintColorPickerMorph.prototype.init = function (extent, action) {
- this.setExtent(extent || new Point(200, 100));
- this.action = action || nop;
- this.drawNew();
-};
-
-PaintColorPickerMorph.prototype.drawNew = function () {
- var x = 0,
- y = 0,
- can = newCanvas(this.extent()),
- ctx = can.getContext("2d"),
- colorselection,
- r;
- for (x = 0; x < this.width(); x += 1) {
- for (y = 0; y < this.height() - 20; y += 1) {
- ctx.fillStyle = "hsl(" +
- (360 * x / this.width()) +
- "," +
- "100%," +
- (y * 100 / (this.height() - 20)) +
- "%)";
- ctx.fillRect(x, y, 1, 1);
- }
- }
- for (x = 0; x < this.width(); x += 1) {
- r = Math.floor(255 * x / this.width());
- ctx.fillStyle = "rgb(" + r + ", " + r + ", " + r + ")";
- ctx.fillRect(x, this.height() - 20, 1, 10);
- }
- colorselection = ["black", "white", "gray"];
- for (x = 0; x < colorselection.length; x += 1) {
- ctx.fillStyle = colorselection[x];
- ctx.fillRect(
- x * this.width() / colorselection.length,
- this.height() - 10,
- this.width() / colorselection.length,
- 10
- );
- }
- for (x = this.width() * 2 / 3; x < this.width(); x += 2) {
- for (y = this.height() - 10; y < this.height(); y += 2) {
- if ((x + y) / 2 % 2 === 0) {
- ctx.fillStyle = "#DDD";
- ctx.fillRect(x, y, 2, 2);
- }
- }
- }
- this.image = can;
-};
-
-PaintColorPickerMorph.prototype.mouseDownLeft = function (pos) {
- if ((pos.subtract(this.position()).x > this.width() * 2 / 3) &&
- (pos.subtract(this.position()).y > this.height() - 10)) {
- this.action("transparent");
- } else {
- this.action(this.getPixelColor(pos));
- }
-};
-
-PaintColorPickerMorph.prototype.mouseMove =
+// AdvancedColorPickerMorph //////////////////
+
+// A large hsl color picker
+
+PaintColorPickerMorph.prototype = new Morph();
+PaintColorPickerMorph.prototype.constructor = PaintColorPickerMorph;
+PaintColorPickerMorph.uber = Morph.prototype;
+
+function PaintColorPickerMorph(extent, action) {
+ this.init(extent, action);
+}
+
+PaintColorPickerMorph.prototype.init = function (extent, action) {
+ this.setExtent(extent || new Point(200, 100));
+ this.action = action || nop;
+ this.drawNew();
+};
+
+PaintColorPickerMorph.prototype.drawNew = function () {
+ var x = 0,
+ y = 0,
+ can = newCanvas(this.extent()),
+ ctx = can.getContext("2d"),
+ colorselection,
+ r;
+ for (x = 0; x < this.width(); x += 1) {
+ for (y = 0; y < this.height() - 20; y += 1) {
+ ctx.fillStyle = "hsl(" +
+ (360 * x / this.width()) +
+ "," +
+ "100%," +
+ (y * 100 / (this.height() - 20)) +
+ "%)";
+ ctx.fillRect(x, y, 1, 1);
+ }
+ }
+ for (x = 0; x < this.width(); x += 1) {
+ r = Math.floor(255 * x / this.width());
+ ctx.fillStyle = "rgb(" + r + ", " + r + ", " + r + ")";
+ ctx.fillRect(x, this.height() - 20, 1, 10);
+ }
+ colorselection = ["black", "white", "gray"];
+ for (x = 0; x < colorselection.length; x += 1) {
+ ctx.fillStyle = colorselection[x];
+ ctx.fillRect(
+ x * this.width() / colorselection.length,
+ this.height() - 10,
+ this.width() / colorselection.length,
+ 10
+ );
+ }
+ for (x = this.width() * 2 / 3; x < this.width(); x += 2) {
+ for (y = this.height() - 10; y < this.height(); y += 2) {
+ if ((x + y) / 2 % 2 === 0) {
+ ctx.fillStyle = "#DDD";
+ ctx.fillRect(x, y, 2, 2);
+ }
+ }
+ }
+ this.image = can;
+};
+
+PaintColorPickerMorph.prototype.mouseDownLeft = function (pos) {
+ if ((pos.subtract(this.position()).x > this.width() * 2 / 3) &&
+ (pos.subtract(this.position()).y > this.height() - 10)) {
+ this.action("transparent");
+ } else {
+ this.action(this.getPixelColor(pos));
+ }
+};
+
+PaintColorPickerMorph.prototype.mouseMove =
PaintColorPickerMorph.prototype.mouseDownLeft;
-
+
// PaintCanvasMorph ///////////////////////////
/*
- A canvas which reacts to drag events to
+ A canvas which reacts to drag events to
modify its image, based on a 'tool' property.
*/
-
-PaintCanvasMorph.prototype = new Morph();
-PaintCanvasMorph.prototype.constructor = PaintCanvasMorph;
-PaintCanvasMorph.uber = Morph.prototype;
-
-function PaintCanvasMorph(shift) {
- this.init(shift);
-}
-
-PaintCanvasMorph.prototype.init = function (shift) {
- this.rotationCenter = new Point(240, 180);
- this.dragRect = null;
- this.previousDragPoint = null;
- this.currentTool = "brush";
- this.dragRect = new Rectangle();
- // rectangle with origin being the starting drag position and
+
+PaintCanvasMorph.prototype = new Morph();
+PaintCanvasMorph.prototype.constructor = PaintCanvasMorph;
+PaintCanvasMorph.uber = Morph.prototype;
+
+function PaintCanvasMorph(shift) {
+ this.init(shift);
+}
+
+PaintCanvasMorph.prototype.init = function (shift) {
+ this.rotationCenter = new Point(240, 180);
+ this.dragRect = null;
+ this.previousDragPoint = null;
+ this.currentTool = "brush";
+ this.dragRect = new Rectangle();
+ // rectangle with origin being the starting drag position and
// corner being the current drag position
- this.mask = newCanvas(this.extent()); // Temporary canvas
- this.paper = newCanvas(this.extent()); // Actual canvas
- this.erasermask = newCanvas(this.extent()); // eraser memory
- this.background = newCanvas(this.extent()); // checkers
- this.settings = {
- "primarycolor": new Color(0, 0, 0, 255), // usually fill color
- "secondarycolor": new Color(0, 0, 0, 255), // (unused)
- "linewidth": 3 // stroke width
- };
- this.brushBuffer = [];
- this.undoBuffer = [];
- this.isShiftPressed = shift || function () {
- var key = this.world().currentKey;
- return (key === 16);
+ this.mask = newCanvas(this.extent()); // Temporary canvas
+ this.paper = newCanvas(this.extent()); // Actual canvas
+ this.erasermask = newCanvas(this.extent()); // eraser memory
+ this.background = newCanvas(this.extent()); // checkers
+ this.settings = {
+ "primarycolor": new Color(0, 0, 0, 255), // usually fill color
+ "secondarycolor": new Color(0, 0, 0, 255), // (unused)
+ "linewidth": 3 // stroke width
+ };
+ this.brushBuffer = [];
+ this.undoBuffer = [];
+ this.isShiftPressed = shift || function () {
+ var key = this.world().currentKey;
+ return (key === 16);
};
- this.buildContents();
-};
-
-PaintCanvasMorph.prototype.cacheUndo = function () {
- var cachecan = newCanvas(this.extent());
- this.merge(this.paper, cachecan);
- this.undoBuffer.push(cachecan);
-};
-
-PaintCanvasMorph.prototype.undo = function () {
- if (this.undoBuffer.length > 0) {
- this.paper = newCanvas(this.extent());
- this.mask.width = this.mask.width + 1 - 1;
- this.merge(this.undoBuffer.pop(), this.paper);
- this.drawNew();
- this.changed();
- }
-};
-
-PaintCanvasMorph.prototype.merge = function (a, b) {
- b.getContext("2d").drawImage(a, 0, 0);
+ this.buildContents();
};
-
-PaintCanvasMorph.prototype.centermerge = function (a, b) {
- b.getContext("2d").drawImage(
- a,
- (b.width - a.width) / 2,
- (b.height - a.height) / 2
- );
-};
-
+
+PaintCanvasMorph.prototype.cacheUndo = function () {
+ var cachecan = newCanvas(this.extent());
+ this.merge(this.paper, cachecan);
+ this.undoBuffer.push(cachecan);
+};
+
+PaintCanvasMorph.prototype.undo = function () {
+ if (this.undoBuffer.length > 0) {
+ this.paper = newCanvas(this.extent());
+ this.mask.width = this.mask.width + 1 - 1;
+ this.merge(this.undoBuffer.pop(), this.paper);
+ this.drawNew();
+ this.changed();
+ }
+};
+
+PaintCanvasMorph.prototype.merge = function (a, b) {
+ b.getContext("2d").drawImage(a, 0, 0);
+};
+
+PaintCanvasMorph.prototype.centermerge = function (a, b) {
+ b.getContext("2d").drawImage(
+ a,
+ (b.width - a.width) / 2,
+ (b.height - a.height) / 2
+ );
+};
+
PaintCanvasMorph.prototype.clearCanvas = function () {
- this.buildContents();
- this.drawNew();
- this.changed();
-};
-
-PaintCanvasMorph.prototype.toolChanged = function (tool) {
- this.mask = newCanvas(this.extent());
- if (tool === "crosshairs") {
- this.drawcrosshair();
- }
- this.drawNew();
- this.changed();
-};
-
-PaintCanvasMorph.prototype.drawcrosshair = function (context) {
- var ctx = context || this.mask.getContext("2d"),
- rp = this.rotationCenter;
+ this.buildContents();
+ this.drawNew();
+ this.changed();
+};
+
+PaintCanvasMorph.prototype.toolChanged = function (tool) {
+ this.mask = newCanvas(this.extent());
+ if (tool === "crosshairs") {
+ this.drawcrosshair();
+ }
+ this.drawNew();
+ this.changed();
+};
+
+PaintCanvasMorph.prototype.drawcrosshair = function (context) {
+ var ctx = context || this.mask.getContext("2d"),
+ rp = this.rotationCenter;
ctx.lineWidth = 1;
ctx.strokeStyle = 'black';
@@ -646,32 +647,32 @@ PaintCanvasMorph.prototype.drawcrosshair = function (context) {
ctx.moveTo(rp.x, 0);
ctx.lineTo(rp.x, this.mask.height);
ctx.stroke();
-
- this.drawNew();
- this.changed();
-};
-
+
+ this.drawNew();
+ this.changed();
+};
+
PaintCanvasMorph.prototype.floodfill = function (sourcepoint) {
- var width = this.paper.width,
- height = this.paper.height,
- ctx = this.paper.getContext("2d"),
- img = ctx.getImageData(0, 0, width, height),
- data = img.data,
- stack = [Math.round(sourcepoint.y) * width + sourcepoint.x],
- currentpoint,
- read,
- sourcecolor,
- checkpoint;
- read = function (p) {
- var d = p * 4;
- return [data[d], data[d + 1], data[d + 2], data[d + 3]];
- };
- sourcecolor = read(stack[0]);
- checkpoint = function (p) {
- return p[0] === sourcecolor[0] &&
- p[1] === sourcecolor[1] &&
- p[2] === sourcecolor[2] &&
- p[3] === sourcecolor[3];
+ var width = this.paper.width,
+ height = this.paper.height,
+ ctx = this.paper.getContext("2d"),
+ img = ctx.getImageData(0, 0, width, height),
+ data = img.data,
+ stack = [Math.round(sourcepoint.y) * width + sourcepoint.x],
+ currentpoint,
+ read,
+ sourcecolor,
+ checkpoint;
+ read = function (p) {
+ var d = p * 4;
+ return [data[d], data[d + 1], data[d + 2], data[d + 3]];
+ };
+ sourcecolor = read(stack[0]);
+ checkpoint = function (p) {
+ return p[0] === sourcecolor[0] &&
+ p[1] === sourcecolor[1] &&
+ p[2] === sourcecolor[2] &&
+ p[3] === sourcecolor[3];
};
// if already filled, abort
@@ -690,201 +691,204 @@ PaintCanvasMorph.prototype.floodfill = function (sourcepoint) {
}
while (stack.length > 0) {
- currentpoint = stack.pop();
- if (checkpoint(read(currentpoint))) {
- if (currentpoint % 480 > 1) {
- stack.push(currentpoint + 1);
- stack.push(currentpoint - 1);
- }
- if (currentpoint > 0 && currentpoint < 360 * 480) {
- stack.push(currentpoint + width);
- stack.push(currentpoint - width);
- }
- }
- if (this.settings.primarycolor === "transparent") {
- data[currentpoint * 4 + 3] = 0;
- } else {
- data[currentpoint * 4] = this.settings.primarycolor.r;
- data[currentpoint * 4 + 1] = this.settings.primarycolor.g;
- data[currentpoint * 4 + 2] = this.settings.primarycolor.b;
- data[currentpoint * 4 + 3] = this.settings.primarycolor.a;
- }
- }
+ currentpoint = stack.pop();
+ if (checkpoint(read(currentpoint))) {
+ if (currentpoint % 480 > 1) {
+ stack.push(currentpoint + 1);
+ stack.push(currentpoint - 1);
+ }
+ if (currentpoint > 0 && currentpoint < 360 * 480) {
+ stack.push(currentpoint + width);
+ stack.push(currentpoint - width);
+ }
+ }
+ if (this.settings.primarycolor === "transparent") {
+ data[currentpoint * 4 + 3] = 0;
+ } else {
+ data[currentpoint * 4] = this.settings.primarycolor.r;
+ data[currentpoint * 4 + 1] = this.settings.primarycolor.g;
+ data[currentpoint * 4 + 2] = this.settings.primarycolor.b;
+ data[currentpoint * 4 + 3] = this.settings.primarycolor.a;
+ }
+ }
ctx.putImageData(img, 0, 0);
this.drawNew();
this.changed();
-};
-
-PaintCanvasMorph.prototype.mouseDownLeft = function (pos) {
- this.cacheUndo();
- this.dragRect.origin = pos.subtract(this.bounds.origin);
- this.dragRect.corner = pos.subtract(this.bounds.origin);
- this.previousDragPoint = this.dragRect.corner.copy();
+};
+
+PaintCanvasMorph.prototype.mouseDownLeft = function (pos) {
+ this.cacheUndo();
+ this.dragRect.origin = pos.subtract(this.bounds.origin);
+ this.dragRect.corner = pos.subtract(this.bounds.origin);
+ this.previousDragPoint = this.dragRect.corner.copy();
if (this.currentTool === 'crosshairs') {
this.rotationCenter = pos.subtract(this.bounds.origin);
this.drawcrosshair();
return;
}
- if (this.currentTool === "paintbucket") {
- return this.floodfill(pos.subtract(this.bounds.origin));
- }
- if (this.settings.primarycolor === "transparent" &&
- this.currentTool !== "crosshairs") {
- this.erasermask = newCanvas(this.extent());
- this.merge(this.paper, this.erasermask);
- }
-};
-
+ if (this.currentTool === "paintbucket") {
+ return this.floodfill(pos.subtract(this.bounds.origin));
+ }
+ if (this.settings.primarycolor === "transparent" &&
+ this.currentTool !== "crosshairs") {
+ this.erasermask = newCanvas(this.extent());
+ this.merge(this.paper, this.erasermask);
+ }
+};
+
PaintCanvasMorph.prototype.mouseMove = function (pos) {
if (this.currentTool === "paintbucket") {
return;
}
-
- var relpos = pos.subtract(this.bounds.origin),
- mctx = this.mask.getContext("2d"),
- pctx = this.paper.getContext("2d"),
- x = this.dragRect.origin.x, // original drag X
- y = this.dragRect.origin.y, // original drag y
- p = relpos.x, // current drag x
- q = relpos.y, // current drag y
- w = (p - x) / 2, // half the rect width
- h = (q - y) / 2, // half the rect height
- i; // iterator number
- mctx.save();
- function newW() {
- return Math.max(Math.abs(w), Math.abs(h)) * (w / Math.abs(w));
- }
- function newH() {
- return Math.max(Math.abs(w), Math.abs(h)) * (h / Math.abs(h));
- }
- this.brushBuffer.push([p, q]);
- mctx.lineWidth = this.settings.linewidth;
- mctx.clearRect(0, 0, this.bounds.width(), this.bounds.height()); // mask
-
- this.dragRect.corner = relpos.subtract(this.dragRect.origin); // reset crn
-
- if (this.settings.primarycolor === "transparent" &&
- this.currentTool !== "crosshairs") {
- this.merge(this.erasermask, this.mask);
- pctx.clearRect(0, 0, this.bounds.width(), this.bounds.height());
- mctx.globalCompositeOperation = "destination-out";
- } else {
- mctx.fillStyle = this.settings.primarycolor.toString();
- mctx.strokeStyle = this.settings.primarycolor.toString();
- }
- switch (this.currentTool) {
- case "rectangle":
- if (this.isShiftPressed()) {
- mctx.strokeRect(x, y, newW() * 2, newH() * 2);
- } else {
- mctx.strokeRect(x, y, w * 2, h * 2);
- }
- break;
- case "rectangleSolid":
- if (this.isShiftPressed()) {
- mctx.fillRect(x, y, newW() * 2, newH() * 2);
- } else {
- mctx.fillRect(x, y, w * 2, h * 2);
- }
- break;
- case "brush":
- mctx.lineCap = "round";
- mctx.lineJoin = "round";
- mctx.beginPath();
- mctx.moveTo(this.brushBuffer[0][0], this.brushBuffer[0][1]);
- for (i = 0; i < this.brushBuffer.length; i += 1) {
- mctx.lineTo(this.brushBuffer[i][0], this.brushBuffer[i][1]);
- }
- mctx.stroke();
- break;
- case "line":
- mctx.beginPath();
- mctx.moveTo(x, y);
- if (this.isShiftPressed()) {
- if (Math.abs(h) > Math.abs(w)) {
- mctx.lineTo(x, q);
- } else {
- mctx.lineTo(p, y);
- }
- } else {
- mctx.lineTo(p, q);
- }
- mctx.stroke();
- break;
- case "circle":
- case "circleSolid":
- mctx.beginPath();
- if (this.isShiftPressed()) {
- mctx.arc(
- x,
- y,
- new Point(x, y).distanceTo(new Point(p, q)),
- 0,
- Math.PI * 2,
- false
- );
- } else {
- for (i = 0; i < 480; i += 1) {
- mctx.lineTo(
- i,
- (2 * h) * Math.sqrt(2 - Math.pow(
- (i - x) / (2 * w),
- 2
- )) + y
- );
- }
- for (i = 480; i > 0; i -= 1) {
- mctx.lineTo(
- i,
- -1 * (2 * h) * Math.sqrt(2 - Math.pow(
- (i - x) / (2 * w),
- 2
- )) + y
- );
- }
- }
- mctx.closePath();
- if (this.currentTool === "circleSolid") {
- mctx.fill();
- } else {
- if (this.currentTool === "circle") {
- mctx.stroke();
- }
- }
- break;
+
+ var relpos = pos.subtract(this.bounds.origin),
+ mctx = this.mask.getContext("2d"),
+ pctx = this.paper.getContext("2d"),
+ x = this.dragRect.origin.x, // original drag X
+ y = this.dragRect.origin.y, // original drag y
+ p = relpos.x, // current drag x
+ q = relpos.y, // current drag y
+ w = (p - x) / 2, // half the rect width
+ h = (q - y) / 2, // half the rect height
+ i; // iterator number
+ mctx.save();
+ function newW() {
+ return Math.max(Math.abs(w), Math.abs(h)) * (w / Math.abs(w));
+ }
+ function newH() {
+ return Math.max(Math.abs(w), Math.abs(h)) * (h / Math.abs(h));
+ }
+ this.brushBuffer.push([p, q]);
+ mctx.lineWidth = this.settings.linewidth;
+ mctx.clearRect(0, 0, this.bounds.width(), this.bounds.height()); // mask
+
+ this.dragRect.corner = relpos.subtract(this.dragRect.origin); // reset crn
+
+ if (this.settings.primarycolor === "transparent" &&
+ this.currentTool !== "crosshairs") {
+ this.merge(this.erasermask, this.mask);
+ pctx.clearRect(0, 0, this.bounds.width(), this.bounds.height());
+ mctx.globalCompositeOperation = "destination-out";
+ } else {
+ mctx.fillStyle = this.settings.primarycolor.toString();
+ mctx.strokeStyle = this.settings.primarycolor.toString();
+ }
+ switch (this.currentTool) {
+ case "rectangle":
+ if (this.isShiftPressed()) {
+ mctx.strokeRect(x, y, newW() * 2, newH() * 2);
+ } else {
+ mctx.strokeRect(x, y, w * 2, h * 2);
+ }
+ break;
+ case "rectangleSolid":
+ if (this.isShiftPressed()) {
+ mctx.fillRect(x, y, newW() * 2, newH() * 2);
+ } else {
+ mctx.fillRect(x, y, w * 2, h * 2);
+ }
+ break;
+ case "brush":
+ mctx.lineCap = "round";
+ mctx.lineJoin = "round";
+ mctx.beginPath();
+ mctx.moveTo(this.brushBuffer[0][0], this.brushBuffer[0][1]);
+ for (i = 0; i < this.brushBuffer.length; i += 1) {
+ mctx.lineTo(this.brushBuffer[i][0], this.brushBuffer[i][1]);
+ }
+ mctx.stroke();
+ break;
+ case "line":
+ mctx.beginPath();
+ mctx.moveTo(x, y);
+ if (this.isShiftPressed()) {
+ if (Math.abs(h) > Math.abs(w)) {
+ mctx.lineTo(x, q);
+ } else {
+ mctx.lineTo(p, y);
+ }
+ } else {
+ mctx.lineTo(p, q);
+ }
+ mctx.stroke();
+ break;
+ case "circle":
+ case "circleSolid":
+ mctx.beginPath();
+ if (this.isShiftPressed()) {
+ mctx.arc(
+ x,
+ y,
+ new Point(x, y).distanceTo(new Point(p, q)),
+ 0,
+ Math.PI * 2,
+ false
+ );
+ } else {
+ for (i = 0; i < 480; i += 1) {
+ mctx.lineTo(
+ i,
+ (2 * h) * Math.sqrt(2 - Math.pow(
+ (i - x) / (2 * w),
+ 2
+ )) + y
+ );
+ }
+ for (i = 480; i > 0; i -= 1) {
+ mctx.lineTo(
+ i,
+ -1 * (2 * h) * Math.sqrt(2 - Math.pow(
+ (i - x) / (2 * w),
+ 2
+ )) + y
+ );
+ }
+ }
+ mctx.closePath();
+ if (this.currentTool === "circleSolid") {
+ mctx.fill();
+ } else {
+ if (this.currentTool === "circle") {
+ mctx.stroke();
+ }
+ }
+ break;
case "crosshairs":
this.rotationCenter = relpos.copy();
this.drawcrosshair(mctx);
- break;
- case "eraser":
- this.merge(this.paper, this.mask);
- mctx.save();
- mctx.globalCompositeOperation = "destination-out";
- mctx.beginPath();
- mctx.moveTo(this.brushBuffer[0][0], this.brushBuffer[0][1]);
- for (i = 0; i < this.brushBuffer.length; i += 1) {
- mctx.lineTo(this.brushBuffer[i][0], this.brushBuffer[i][1]);
- }
- mctx.stroke();
- mctx.restore();
- this.paper = newCanvas(this.extent());
- this.merge(this.mask, this.paper);
- break;
- default:
- nop();
- }
- this.previousDragPoint = relpos;
- this.drawNew();
- this.changed();
- mctx.restore();
-};
-
+ break;
+ case "eraser":
+ this.merge(this.paper, this.mask);
+ mctx.save();
+ mctx.globalCompositeOperation = "destination-out";
+ mctx.beginPath();
+ mctx.moveTo(this.brushBuffer[0][0], this.brushBuffer[0][1]);
+ for (i = 0; i < this.brushBuffer.length; i += 1) {
+ mctx.lineTo(this.brushBuffer[i][0], this.brushBuffer[i][1]);
+ }
+ mctx.stroke();
+ mctx.restore();
+ this.paper = newCanvas(this.extent());
+ this.merge(this.mask, this.paper);
+ break;
+ default:
+ nop();
+ }
+ this.previousDragPoint = relpos;
+ this.drawNew();
+ this.changed();
+ mctx.restore();
+};
+
PaintCanvasMorph.prototype.mouseClickLeft = function () {
- if (this.currentTool !== "crosshairs") {
- this.merge(this.mask, this.paper);
- }
- this.brushBuffer = [];
-};
+ if (this.currentTool !== "crosshairs") {
+ this.merge(this.mask, this.paper);
+ }
+ this.brushBuffer = [];
+};
+
+PaintCanvasMorph.prototype.mouseLeaveDragging
+ = PaintCanvasMorph.prototype.mouseClickLeft;
PaintCanvasMorph.prototype.buildContents = function () {
this.background = newCanvas(this.extent());
@@ -903,47 +907,47 @@ PaintCanvasMorph.prototype.buildContents = function () {
}
}
};
-
-PaintCanvasMorph.prototype.drawNew = function () {
- var can = newCanvas(this.extent());
- this.merge(this.background, can);
- this.merge(this.paper, can);
- this.merge(this.mask, can);
- this.image = can;
- this.drawFrame();
-};
-
-PaintCanvasMorph.prototype.drawFrame = function () {
- var context, borderColor;
-
- context = this.image.getContext('2d');
- if (this.parent) {
- this.color = this.parent.color.lighter(this.contrast * 0.75);
- borderColor = this.parent.color;
- } else {
- borderColor = new Color(120, 120, 120);
- }
- context.fillStyle = this.color.toString();
-
- // cache my border colors
- this.cachedClr = borderColor.toString();
- this.cachedClrBright = borderColor.lighter(this.contrast)
- .toString();
- this.cachedClrDark = borderColor.darker(this.contrast).toString();
- this.drawRectBorder(context);
-};
-
-PaintCanvasMorph.prototype.drawRectBorder
- = InputFieldMorph.prototype.drawRectBorder;
-
-PaintCanvasMorph.prototype.edge
- = InputFieldMorph.prototype.edge;
-
-PaintCanvasMorph.prototype.fontSize
- = InputFieldMorph.prototype.fontSize;
-
-PaintCanvasMorph.prototype.typeInPadding
- = InputFieldMorph.prototype.typeInPadding;
-
-PaintCanvasMorph.prototype.contrast
- = InputFieldMorph.prototype.contrast;
+
+PaintCanvasMorph.prototype.drawNew = function () {
+ var can = newCanvas(this.extent());
+ this.merge(this.background, can);
+ this.merge(this.paper, can);
+ this.merge(this.mask, can);
+ this.image = can;
+ this.drawFrame();
+};
+
+PaintCanvasMorph.prototype.drawFrame = function () {
+ var context, borderColor;
+
+ context = this.image.getContext('2d');
+ if (this.parent) {
+ this.color = this.parent.color.lighter(this.contrast * 0.75);
+ borderColor = this.parent.color;
+ } else {
+ borderColor = new Color(120, 120, 120);
+ }
+ context.fillStyle = this.color.toString();
+
+ // cache my border colors
+ this.cachedClr = borderColor.toString();
+ this.cachedClrBright = borderColor.lighter(this.contrast)
+ .toString();
+ this.cachedClrDark = borderColor.darker(this.contrast).toString();
+ this.drawRectBorder(context);
+};
+
+PaintCanvasMorph.prototype.drawRectBorder
+ = InputFieldMorph.prototype.drawRectBorder;
+
+PaintCanvasMorph.prototype.edge
+ = InputFieldMorph.prototype.edge;
+
+PaintCanvasMorph.prototype.fontSize
+ = InputFieldMorph.prototype.fontSize;
+
+PaintCanvasMorph.prototype.typeInPadding
+ = InputFieldMorph.prototype.typeInPadding;
+
+PaintCanvasMorph.prototype.contrast
+ = InputFieldMorph.prototype.contrast;