Created
October 1, 2016 20:00
-
-
Save dekrain/5b80ac03263fd36eb3c8370fd6f13e67 to your computer and use it in GitHub Desktop.
Snap! Block Factory!!!
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// A Block Factory for Snap! by (C) ~DK | |
// Based on morphic.js and Snap! | |
// Needs: morphic.js, widgets.js, blocks.js, objects.js, gui.js | |
/*global Morph DialogBoxMorph BlockMorph CommandBlockMorph ReporterBlockMorph AlignmentMorph SpriteMorph ToggleButtonMorph IDE_Morph*/ | |
var BlockFactoryMorph; | |
// BlockFactoryMorph inherits from DialogBoxMorph | |
BlockFactoryMorph.prototype = new DialogBoxMorph(); | |
BlockFactoryMorph.prototype.constructor = BlockFactoryMorph; | |
BlockFactoryMorph.uber = DialogBoxMorph.prototype; | |
// BlockFactoryMorph opening | |
BlockFactoryMorph.openIn = function(world) { | |
var factory = new this(); | |
factory.prompt('Block Factory', factory.spec, world); | |
return factory; | |
}; | |
BlockFactoryMorph.openInButton = function(world) { | |
return new PushButtonMorph(null, function(){BlockFactoryMorph.openIn(world);}, 'Open Dialog'); | |
} | |
// BlockFactoryMorph instance creation | |
function BlockFactoryMorph() { | |
this.init(); | |
} | |
BlockFactoryMorph.prototype.init = function() { | |
// Additional properties | |
this.category = 'motion'; | |
this.shape = 'command'; | |
this.spec = 'Your spec here!'; | |
this.selector = 'A block selector...'; | |
this.block = new CommandBlockMorph(); | |
this.refreshBlock(); | |
// Initialize inherited properties | |
BlockFactoryMorph.uber.init.call( | |
this, | |
this, | |
'registerBlock', | |
this | |
); | |
// Override inherited properties | |
this.key = 'buildABlock'; | |
this.shapes = new AlignmentMorph('row', this.padding); | |
this.add(this.shapes); | |
this.categories = new BoxMorph(); | |
this.categories.color = SpriteMorph.prototype.paletteColor.lighter(8); | |
this.categories.borderColor = this.categories.color.lighter(40); | |
this.add(this.categories); | |
this.code = SpriteMorph.prototype.blockForSelector('reportJSFunction'); | |
this.add(this.code); | |
this.selectorInput = new InputFieldMorph( | |
this.selector, | |
false | |
); | |
this.add(this.selectorInput); | |
this.createMyButtons(); | |
this.fixMyLayout(); | |
}; | |
// Category buttons | |
BlockFactoryMorph.prototype.createMyButtons = function() { | |
this.createCategoryButtons(); | |
this.createShapeButtons(); | |
}; | |
BlockFactoryMorph.prototype.createCategoryButtons = function () { | |
var myself = this, | |
oldFlag = Morph.prototype.trackChanges; | |
Morph.prototype.trackChanges = false; | |
SpriteMorph.prototype.categories.forEach(function (cat) { | |
myself.addCategoryButton(cat); | |
}); | |
Morph.prototype.trackChanges = oldFlag; | |
}; | |
BlockFactoryMorph.prototype.addCategoryButton = function (category) { | |
var labelWidth = 75, | |
myself = this, | |
colors = [ | |
SpriteMorph.prototype.paletteColor, | |
SpriteMorph.prototype.paletteColor.darker(50), | |
SpriteMorph.prototype.blockColor[category] | |
], | |
button; | |
button = new ToggleButtonMorph( | |
colors, | |
this, // this block dialog box is the target | |
function () { | |
myself.category = category; | |
myself.categories.children.forEach(function (each) { | |
each.refresh(); | |
}); | |
if (myself.shapes) { | |
myself.shapes.children.forEach(function (each) { | |
each.setColor(colors[2]); | |
}); | |
} | |
myself.edit(); | |
}, | |
category[0].toUpperCase().concat(category.slice(1)), // UCase label | |
function () {return myself.category === category; }, // query | |
null, // env | |
null, // hint | |
null, // template cache | |
labelWidth, // minWidth | |
true // has preview | |
); | |
button.corner = 8; | |
button.padding = 0; | |
button.labelShadowOffset = new Point(-1, -1); | |
button.labelShadowColor = colors[1]; | |
button.labelColor = IDE_Morph.prototype.buttonLabelColor; | |
button.contrast = this.buttonContrast; | |
button.fixLayout(); | |
button.refresh(); | |
this.categories.add(button); | |
return button; | |
}; | |
BlockFactoryMorph.prototype.createShapeButtons = function () { | |
var block, | |
myself = this, | |
clr = SpriteMorph.prototype.blockColor[this.category]; | |
block = new CommandBlockMorph(); | |
block.setColor(clr); | |
block.setSpec(localize('Command')); | |
this.addBlockShapeButton( | |
function () {myself.setShape('command'); }, | |
block, | |
function () {return myself.shape === 'command'; } | |
); | |
block = new ReporterBlockMorph(); | |
block.setColor(clr); | |
block.setSpec(localize('Reporter')); | |
this.addBlockShapeButton( | |
function () {myself.setShape('reporter'); }, | |
block, | |
function () {return myself.shape === 'reporter'; } | |
); | |
block = new ReporterBlockMorph(true); | |
block.setColor(clr); | |
block.setSpec(localize('Predicate')); | |
this.addBlockShapeButton( | |
function () {myself.setShape('predicate'); }, | |
block, | |
function () {return myself.shape === 'predicate'; } | |
); | |
}; | |
BlockFactoryMorph.prototype.addBlockShapeButton = function ( | |
action, | |
element, | |
query | |
) { | |
var button = new ToggleElementMorph( | |
this, | |
action, | |
element, | |
query, | |
null, | |
null, | |
'rebuild' | |
); | |
button.refresh(); | |
this.shapes.add(button); | |
return button; | |
}; | |
BlockFactoryMorph.prototype.refreshBlock = function() { | |
var shapes = ['command', ['reporter', 'predicate']]; | |
var shape = shapes[[CommandBlockMorph, ReporterBlockMorph].indexOf(this.block.constructor)]; | |
if (shape instanceof Array) shape = shape[this.block.isPredicate ? 1 : 0]; | |
if (shape !== this.shape) this.block = (function(){ | |
switch (this.shape) { | |
case 'command': return new CommandBlockMorph(); | |
case 'reporter': return new ReporterBlockMorph(); | |
case 'predicate': return new ReporterBlockMorph(true); | |
default: throw new TypeError('Invalid block shape!'); | |
} | |
}.call(this)); | |
this.block.blockSpec = this.spec; | |
this.block.category = this.category; | |
this.block.selector = this.selector; | |
this.block.rebuild(); | |
this.block.fixBlockColor(); | |
this.block.drawNew(); | |
}; | |
// BlockFactoryMorph layout | |
BlockFactoryMorph.prototype.fixLayout = function() { | |
var th = fontHeight(this.titleFontSize) + this.titlePadding * 2, w, n = this.top() + th; | |
if (this.head) { | |
this.head.setPosition(this.position().add(new Point( | |
this.padding, | |
th + this.padding | |
))); | |
this.silentSetWidth(this.head.width() + this.padding * 2); | |
this.silentSetHeight( | |
this.head.height() | |
+ this.padding * 2 | |
+ th | |
); | |
} | |
if (this.body) { | |
if (this.head) { | |
this.body.setPosition(this.head.bottomLeft().add(new Point( | |
0, | |
this.padding | |
))); | |
this.silentSetWidth(Math.max( | |
this.width(), | |
this.body.width() + this.padding * 2 | |
)); | |
this.silentSetHeight( | |
this.height() | |
+ this.body.height() | |
+ this.padding | |
); | |
w = this.width(); | |
this.head.setLeft( | |
this.left() | |
+ Math.round((w - this.head.width()) / 2) | |
); | |
this.body.setLeft( | |
this.left() | |
+ Math.round((w - this.body.width()) / 2) | |
); | |
} else { | |
this.body.setPosition(this.position().add(new Point( | |
this.padding, | |
th + this.padding | |
))); | |
this.silentSetWidth(this.body.width() + this.padding * 2); | |
this.silentSetHeight( | |
this.body.height() | |
+ this.padding * 2 | |
+ th | |
); | |
} | |
} | |
n += 10; | |
if (this.categories) { | |
this.categories.setCenter(this.center()); | |
this.categories.setTop(n); | |
n = this.categories.bottom() + 15; | |
} | |
if (this.shapes) { | |
this.shapes.fixLayout(); | |
this.shapes.setCenter(this.center()); | |
this.shapes.setTop(n); | |
n = this.shapes.bottom() + 20; | |
} | |
if (this.label) { | |
this.label.setCenter(this.center()); | |
this.label.setTop(this.top() + (th - this.label.height()) / 2); | |
} | |
if (this.code) { | |
this.code.setLeft(this.left() + 15); | |
this.code.setTop(n); | |
this.code.labelWidth = this.width() - (2 * 15); | |
n = this.code.bottom() + 10; | |
} | |
if (this.body) { | |
this.body.setTop(n+15); | |
n = this.body.bottom() + 5; | |
this.selectorInput.setWidth(this.body.width()); | |
this.selectorInput.setTop(n); | |
this.selectorInput.setLeft(this.body.left()); | |
n = this.selectorInput.bottom() + 15; | |
} | |
this.silentSetHeight(n-this.top()); | |
if (this.buttons && (this.buttons.children.length > 0)) { | |
this.buttons.fixLayout(); | |
this.silentSetHeight( | |
this.height() | |
+ this.buttons.height() | |
+ this.padding | |
); | |
this.silentSetWidth(Math.max( | |
this.width(), | |
this.buttons.width() | |
+ (2 * this.padding) | |
) | |
); | |
this.buttons.setCenter(this.center()); | |
this.buttons.setBottom(this.bottom() - this.padding); | |
} | |
}; | |
BlockFactoryMorph.prototype.fixMyLayout = function() { | |
this.fixCategoriesLayout(); | |
}; | |
BlockFactoryMorph.prototype.fixCategoriesLayout = function () { | |
var buttonWidth = this.categories.children[0].width(), // all the same | |
buttonHeight = this.categories.children[0].height(), // all the same | |
xPadding = 15, | |
yPadding = 2, | |
border = 10, // this.categories.border, | |
rows = Math.ceil((this.categories.children.length) / 2), | |
l = this.categories.left(), | |
t = this.categories.top(), | |
i = 0, | |
row, | |
col, | |
oldFlag = Morph.prototype.trackChanges; | |
Morph.prototype.trackChanges = false; | |
this.categories.children.forEach(function (button) { | |
i += 1; | |
row = Math.ceil(i / 2); | |
col = 2 - (i % 2); | |
button.setPosition(new Point( | |
l + (col * xPadding + ((col - 1) * buttonWidth)), | |
t + (row * yPadding + ((row - 1) * buttonHeight) + border) | |
)); | |
}); | |
if (MorphicPreferences.isFlat) { | |
this.categories.corner = 0; | |
this.categories.border = 0; | |
this.categories.edge = 0; | |
} | |
this.categories.setExtent(new Point( | |
3 * xPadding + 2 * buttonWidth, | |
(rows + 1) * yPadding + rows * buttonHeight + 2 * border | |
)); | |
Morph.prototype.trackChanges = oldFlag; | |
this.categories.changed(); | |
}; | |
BlockFactoryMorph.prototype.setShape = function(shape) { | |
if (['command', 'reporter', 'predicate'].indexOf(shape) > -1) { | |
this.shape = shape; | |
this.shapes.children.forEach(function(c){ | |
c.refresh(); | |
}); | |
this.edit(); | |
} | |
} | |
BlockFactoryMorph.prototype.registerBlock = function(spec) { | |
this.spec = spec; | |
this.selector = this.selectorInput.getValue(); | |
console.log(invoke(this.code)); | |
console.log(this.code.inputs()[0].evaluate().concat([this.code.inputs()[1].evaluate()])); | |
this.refreshBlock(); | |
this.block.isDraggable = true; | |
this.block.pickUp(this.world()); | |
this.block.fullChanged(); | |
}; | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment