Skip to content

Instantly share code, notes, and snippets.

@dekrain
Last active August 23, 2016 19:51
Show Gist options
  • Save dekrain/4b71a5cd7310fc050e61031bb0aefaf6 to your computer and use it in GitHub Desktop.
Save dekrain/4b71a5cd7310fc050e61031bb0aefaf6 to your computer and use it in GitHub Desktop.
Snap! Pen controller
// Control bar for PenMorph by (C) ~DK
// Based on morphic.js and widgets.js (PushButtonMorph)
/*global Morph PenMorph PushButtonMorph PenMorph BoxMorph WorldMorph Point Color*/
WorldMorph.prototype.customMorphs = function() { // !!! Comment this function in blocks.js
return [
new PenControllerMorph(),
];
};
var PushButtonMorph = PushButtonMorph || (function(){var SymbolMorph=SymbolMorph||(function(){});var PushButtonMorph;PushButtonMorph.prototype=new TriggerMorph;PushButtonMorph.prototype.constructor=PushButtonMorph;PushButtonMorph.uber=TriggerMorph.prototype;PushButtonMorph.prototype.fontSize=10;PushButtonMorph.prototype.fontStyle="sans-serif";PushButtonMorph.prototype.labelColor=new Color(0,0,0);PushButtonMorph.prototype.labelShadowColor=new Color(255,255,255);PushButtonMorph.prototype.labelShadowOffset=new Point(1,1);PushButtonMorph.prototype.color=new Color(220,220,220);PushButtonMorph.prototype.pressColor=new Color(115,180,240);PushButtonMorph.prototype.highlightColor=PushButtonMorph.prototype.pressColor.lighter(50);PushButtonMorph.prototype.outlineColor=new Color(30,30,30);PushButtonMorph.prototype.outlineGradient=false;PushButtonMorph.prototype.contrast=60;PushButtonMorph.prototype.edge=2;PushButtonMorph.prototype.corner=5;PushButtonMorph.prototype.outline=1.00001;PushButtonMorph.prototype.padding=3;function PushButtonMorph(target,action,labelString,environment,hint,template){this.init(target,action,labelString,environment,hint,template)}PushButtonMorph.prototype.init=function(target,action,labelString,environment,hint,template){this.is3D=false;this.target=target||null;this.action=action||null;this.environment=environment||null;this.labelString=labelString||null;this.label=null;this.labelMinExtent=new Point(0,0);this.hint=hint||null;this.template=template||null;TriggerMorph.uber.init.call(this);this.color=PushButtonMorph.prototype.color;this.drawNew();this.fixLayout()};PushButtonMorph.prototype.fixLayout=function(){if(this.label!==null){var padding=this.padding*2+this.outline*2+this.edge*2;this.setExtent(new Point(Math.max(this.label.width(),this.labelMinExtent.x)+padding,Math.max(this.label instanceof StringMorph?this.label.rawHeight():this.label.height(),this.labelMinExtent.y)+padding));this.label.setCenter(this.center())}};PushButtonMorph.prototype.mouseDownLeft=function(){PushButtonMorph.uber.mouseDownLeft.call(this);if(this.label){this.label.setCenter(this.center().add(1))}};PushButtonMorph.prototype.mouseClickLeft=function(){PushButtonMorph.uber.mouseClickLeft.call(this);if(this.label){this.label.setCenter(this.center())}};PushButtonMorph.prototype.mouseLeave=function(){PushButtonMorph.uber.mouseLeave.call(this);if(this.label){this.label.setCenter(this.center())}};PushButtonMorph.prototype.outlinePath=BoxMorph.prototype.outlinePath;PushButtonMorph.prototype.drawOutline=function(context){var outlineStyle,isFlat=MorphicPreferences.isFlat&&!this.is3D;if(!this.outline||isFlat){return null}if(this.outlineGradient){outlineStyle=context.createLinearGradient(0,0,0,this.height());outlineStyle.addColorStop(1,"white");outlineStyle.addColorStop(0,this.outlineColor.darker().toString())}else{outlineStyle=this.outlineColor.toString()}context.fillStyle=outlineStyle;context.beginPath();this.outlinePath(context,isFlat?0:this.corner,0);context.closePath();context.fill()};PushButtonMorph.prototype.drawBackground=function(context,color){var isFlat=MorphicPreferences.isFlat&&!this.is3D;context.fillStyle=color.toString();context.beginPath();this.outlinePath(context,isFlat?0:Math.max(this.corner-this.outline,0),this.outline);context.closePath();context.fill();context.lineWidth=this.outline};PushButtonMorph.prototype.drawEdges=function(context,color,topColor,bottomColor){if(MorphicPreferences.isFlat&&!this.is3D){return}var minInset=Math.max(this.corner,this.outline+this.edge),w=this.width(),h=this.height(),gradient;gradient=context.createLinearGradient(0,this.outline,0,this.outline+this.edge);gradient.addColorStop(0,topColor.toString());gradient.addColorStop(1,color.toString());context.strokeStyle=gradient;context.lineCap="round";context.lineWidth=this.edge;context.beginPath();context.moveTo(minInset,this.outline+this.edge/2);context.lineTo(w-minInset,this.outline+this.edge/2);context.stroke();gradient=context.createRadialGradient(this.corner,this.corner,Math.max(this.corner-this.outline-this.edge,0),this.corner,this.corner,Math.max(this.corner-this.outline,0));gradient.addColorStop(1,topColor.toString());gradient.addColorStop(0,color.toString());context.strokeStyle=gradient;context.lineCap="round";context.lineWidth=this.edge;context.beginPath();context.arc(this.corner,this.corner,Math.max(this.corner-this.outline-this.edge/2,0),radians(180),radians(270),false);context.stroke();gradient=context.createLinearGradient(this.outline,0,this.outline+this.edge,0);gradient.addColorStop(0,topColor.toString());gradient.addColorStop(1,color.toString());context.strokeStyle=gradient;context.lineCap="round";context.lineWidth=this.edge;context.beginPath();context.moveTo(this.outline+this.edge/2,minInset);context.lineTo(this.outline+this.edge/2,h-minInset);context.stroke();gradient=context.createLinearGradient(0,h-this.outline,0,h-this.outline-this.edge);gradient.addColorStop(0,bottomColor.toString());gradient.addColorStop(1,color.toString());context.strokeStyle=gradient;context.lineCap="round";context.lineWidth=this.edge;context.beginPath();context.moveTo(minInset,h-this.outline-this.edge/2);context.lineTo(w-minInset,h-this.outline-this.edge/2);context.stroke();gradient=context.createRadialGradient(w-this.corner,h-this.corner,Math.max(this.corner-this.outline-this.edge,0),w-this.corner,h-this.corner,Math.max(this.corner-this.outline,0));gradient.addColorStop(1,bottomColor.toString());gradient.addColorStop(0,color.toString());context.strokeStyle=gradient;context.lineCap="round";context.lineWidth=this.edge;context.beginPath();context.arc(w-this.corner,h-this.corner,Math.max(this.corner-this.outline-this.edge/2,0),radians(0),radians(90),false);context.stroke();gradient=context.createLinearGradient(w-this.outline,0,w-this.outline-this.edge,0);gradient.addColorStop(0,bottomColor.toString());gradient.addColorStop(1,color.toString());context.strokeStyle=gradient;context.lineCap="round";context.lineWidth=this.edge;context.beginPath();context.moveTo(w-this.outline-this.edge/2,minInset);context.lineTo(w-this.outline-this.edge/2,h-minInset);context.stroke()};PushButtonMorph.prototype.createBackgrounds=function(){var context,ext=this.extent();if(this.template){this.image=this.template.image;this.normalImage=this.template.normalImage;this.highlightImage=this.template.highlightImage;this.pressImage=this.template.pressImage;return null}this.normalImage=newCanvas(ext);context=this.normalImage.getContext("2d");this.drawOutline(context);this.drawBackground(context,this.color);this.drawEdges(context,this.color,this.color.lighter(this.contrast),this.color.darker(this.contrast));this.highlightImage=newCanvas(ext);context=this.highlightImage.getContext("2d");this.drawOutline(context);this.drawBackground(context,this.highlightColor);this.drawEdges(context,this.highlightColor,this.highlightColor.lighter(this.contrast),this.highlightColor.darker(this.contrast));this.pressImage=newCanvas(ext);context=this.pressImage.getContext("2d");this.drawOutline(context);this.drawBackground(context,this.pressColor);this.drawEdges(context,this.pressColor,this.pressColor.darker(this.contrast),this.pressColor.lighter(this.contrast));this.image=this.normalImage};PushButtonMorph.prototype.createLabel=function(){var shading=!MorphicPreferences.isFlat||this.is3D;if(this.label!==null){this.label.destroy()}if(this.labelString instanceof SymbolMorph){this.label=this.labelString.fullCopy();if(shading){this.label.shadowOffset=this.labelShadowOffset;this.label.shadowColor=this.labelShadowColor}this.label.color=this.labelColor;this.label.drawNew()}else{this.label=new StringMorph(localize(this.labelString),this.fontSize,this.fontStyle,true,false,false,shading?this.labelShadowOffset:null,this.labelShadowColor,this.labelColor)}this.add(this.label)};return PushButtonMorph;}());
var PenControllerMorph;
// PenControllerMorph inherits from Morph
PenControllerMorph.prototype = new Morph();
PenControllerMorph.prototype.constructor = PenControllerMorph;
PenControllerMorph.uber = Morph.prototype;
// PenControllerMorph instance creation
function PenControllerMorph(aPen) {
this.init(aPen);
};
PenControllerMorph.prototype.init = function(aPen) {
PenControllerMorph.uber.init.call(this);
this.target = (aPen&&aPen instanceof PenMorph&&aPen) || new PenMorph();
this.setExtent(new Point(250,115), true); // No re-draw
this.penWindow = new Morph();
this.penWindow.setPosition(this.position().add(new Point(25,10)));
this.penWindow.setColor(new Color(0,0,0xCC));
this.penWindow.setExtent(new Point(100,80));
this.penWindow.drawNew();
this.add(this.penWindow);
this.buttons = new BoxMorph();
this.buttons.setPosition(new Point( this.left() + 5, this.bottom() - 10 ));
this.buttons.setExtent(new Point(this.width()-10, 5));
this.buttons.setColor(this.color.lighter());
this.add(this.buttons);
this.fields = [];
if(!(this.target === aPen)) { // Merge new pen
this.penWindow.add(this.target);
this.target.setPosition(this.penWindow.position());
this.target.drawNew();
this.target.isDraggable = false;
this.penWindow.add(
(function(){
var button = new PushButtonMorph(this, function(){this.target.setPosition(this.bottomLeft().add(new Point(0,15)));this.parent.add(this.target);this.target.isDraggable = true;this.penWindow.button.destroy();delete this.penWindow.button;}, 'flush');
this.penWindow.button = button;
button.setPosition(this.penWindow.bottomRight().subtract(button.extent()));
return button;
}).call(this)
);
};
this.buildControls();
this.buildFields();
this.fixButtonsPosition();
this.drawNew();
};
PenControllerMorph.prototype.buildControls = function() {
var myself = this;
function n(i){return parseFloat(myself.fields[i].string())||0;}
this.addButton('forward', function(){this.target.forward(n(0));});
this.addButton('back',function(){this.target.forward(-(n(0)));});
this.addButton('turn',function(){this.target.turn(n(0))});
this.addButton('turnLeft',function(){this.target.turn(-(n(0)))});
this.addButton('color',function(){this.pickColor('Set Pen color:',this.target.setColor,this.target,this.target.color)});
this.addButton('clear',function(){this.target.clear();});
this.addButton('down',function(){this.target.down();});
this.addButton('up',function(){this.target.up();});
this.addMenu('','shapes',['square spiral'],function(idx){switch(idx){
case 0: (function(){var pen = this.target, down=pen.isDown; if(!down)pen.down(); for(var i=0;i<200;++i){pen.forward(i);pen.turn(92);}; if(!down)pen.up();}).call(this); break;
}});
this.addMenu('','other',['tree (2,1,3 slot)','sierpinski (1,2 slot)'],function(idx){switch(idx){
case 0: this.target.tree(n(1),n(0),n(2)); break;
case 1: this.target.sierpinski(n(0),n(1)); break;
}});
};
PenControllerMorph.prototype.buildFields = function() {
function num(start){var n = new StringFieldMorph(start.toString(),15,null,null,null,null,true); n.setWidth(30); return n;}
var n1 = num(15),
n2 = num(0),
n3 = num(0);
this.fields.push(n1);
this.fields.push(n2);
this.fields.push(n3);
this.add(n1);
this.add(n2);
this.add(n3);
var x = this.right() - 60,
y = this.top() + 15;
n1.setPosition(new Point(x,y));
y+=15;
n2.setPosition(new Point(x,y));
y+=15;
n3.setPosition(new Point(x,y));
y+=15;
};
PenControllerMorph.prototype.addButton = function(
label,
action
) {
var button = new PushButtonMorph(this, action || 'nop', label);
button.fontSize = 12;
button.drawNew();
button.fixLayout();
this.buttons.add(button);
return button;
};
PenControllerMorph.prototype.addMenu = function(
label, // Optional
b_label, // Label for button
labels,
action // function(choice) { ... } choice is 0..N
) {
var menu = new MenuMorph(this, label||null);
labels.forEach(function(l,i){
menu.addItem(l,function(){ action.call(this,i); });
});
this.addButton(b_label,function(){ if(labels.length>0) menu.popUpAtHand(this.world()); });
}
PenControllerMorph.prototype.fixButtonsPosition = function() {
var buttons = this.buttons.children,
myself = this,
offset = 5,
col = 0;
buttons.forEach(function(button){if((myself.buttons.width()-(offset+5))<=button.width()+5) ++col,offset=5; button.setPosition(myself.buttons.position().add(new Point(offset, 5+(col*25)))); offset+=button.width();});
++col;
this.setHeight(115+(col*25));
this.buttons.setHeight(10+(col*25));
};
PenControllerMorph.prototype.developersMenu = function() {
var menu = PenControllerMorph.uber.developersMenu.call(this);
menu.addLine();
menu.addItem('set target','setTarget','chose other pen to control');
return menu;
};
PenControllerMorph.prototype.setTarget = function() {
var choices = this.overlappedMorphs().filter(function(each){return each instanceof PenMorph}),
menu = new MenuMorph(this, 'choose target:'),
myself = this;
choices.forEach(function (each) {
menu.addItem(each.toString().slice(0, 50), function () {
myself.target = each;
});
});
if (choices.length === 1) {
this.target = choices[0];
} else if (choices.length > 0) {
menu.popUpAtHand(this.world());
}
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment