Interactive Toggle Switches for Boolean Slots and Literals

in progress…
dev
Jens Mönig 2016-06-01 13:35:54 +02:00
rodzic 0c1ecf2b9a
commit f86a414343
5 zmienionych plików z 266 dodań i 73 usunięć

254
blocks.js
Wyświetl plik

@ -145,11 +145,11 @@ radians, useBlurredShadows, SpeechBubbleMorph, modules, StageMorph,
fontHeight, TableFrameMorph, SpriteMorph, Context, ListWatcherMorph,
CellMorph, DialogBoxMorph, BlockInputFragmentMorph, PrototypeHatBlockMorph,
Costume, IDE_Morph, BlockDialogMorph, BlockEditorMorph, localize, isNil,
isSnapObject, copy*/
isSnapObject, copy, PushButtonMorph*/
// Global stuff ////////////////////////////////////////////////////////
modules.blocks = '2016-May-30';
modules.blocks = '2016-June-01';
var SyntaxElementMorph;
var BlockMorph;
@ -1275,8 +1275,15 @@ SyntaxElementMorph.prototype.labelPart = function (spec) {
part = new ArgMorph('list');
break;
case '%b':
part = new BooleanSlotMorph();
break;
case '%boolUE':
part = new BooleanSlotMorph(null, true);
part = new BooleanSlotMorph();
part.isUnevaluated = true;
break;
case '%bool':
part = new BooleanSlotMorph(true);
part.isStatic = true;
break;
case '%cmd':
part = new CommandSlotMorph();
@ -1959,14 +1966,14 @@ SyntaxElementMorph.prototype.endLayout = function () {
arity: single
%br - user-forced line break
%s - white rectangular type-in slot ("string-type")
%br - user-forced line break
%s - white rectangular type-in slot ("string-type")
%txt - white rectangular type-in slot ("text-type")
%mlt - white rectangular type-in slot ("multi-line-text-type")
%code - white rectangular type-in slot, monospaced font
%n - white roundish type-in slot ("numerical")
%code - white rectangular type-in slot, monospaced font
%n - white roundish type-in slot ("numerical")
%dir - white roundish type-in slot with drop-down for directions
%inst - white roundish type-in slot with drop-down for instruments
%inst - white roundish type-in slot with drop-down for instruments
%ida - white roundish type-in slot with drop-down for list indices
%idx - white roundish type-in slot for indices incl. "any"
%obj - specially drawn slot for object reporters
@ -1984,18 +1991,19 @@ SyntaxElementMorph.prototype.endLayout = function () {
%var - chameleon colored rectangular drop-down for variable names
%shd - Chameleon colored rectuangular drop-down for shadowed var names
%lst - chameleon colored rectangular drop-down for list names
%b - chameleon colored hexagonal slot (for predicates)
%l - list icon
%c - C-shaped command slot, special form for primitives
%cs - C-shaped, auto-reifying, accepts reporter drops
%cl - C-shaped, auto-reifying, rejects reporters
%b - chameleon colored hexagonal slot (for predicates)
%bool - chameleon colored hexagonal slot (for predicates), static
%l - list icon
%c - C-shaped command slot, special form for primitives
%cs - C-shaped, auto-reifying, accepts reporter drops
%cl - C-shaped, auto-reifying, rejects reporters
%clr - interactive color slot
%t - inline variable reporter template
%anyUE - white rectangular type-in slot, unevaluated if replaced
%boolUE - chameleon colored hexagonal slot, unevaluated if replaced
%f - round function slot, unevaluated if replaced,
%r - round reporter slot
%p - hexagonal predicate slot
%t - inline variable reporter template
%anyUE - white rectangular type-in slot, unevaluated if replaced
%boolUE - chameleon colored hexagonal slot, unevaluated if replaced
%f - round function slot, unevaluated if replaced,
%r - round reporter slot
%p - hexagonal predicate slot
rings:
@ -3194,10 +3202,10 @@ BlockMorph.prototype.alternateBlockColor = function () {
this.setColor(
this.zebraContrast < 0 ? clr.darker(Math.abs(this.zebraContrast))
: clr.lighter(this.zebraContrast),
true // silently
this.hasLabels() // silently
);
} else {
this.setColor(clr, true); // silently
this.setColor(clr, this.hasLabels()); // silently
}
this.fixLabelColor();
this.fixChildrensBlockColor(true); // has issues if not forced
@ -3250,6 +3258,12 @@ BlockMorph.prototype.setCategory = function (aString) {
this.endLayout();
};
BlockMorph.prototype.hasLabels = function () {
return this.children.some(function (any) {
return any instanceof StringMorph;
});
};
// BlockMorph copying
BlockMorph.prototype.fullCopy = function (forClone) {
@ -5067,7 +5081,13 @@ RingMorph.prototype.embed = function (aBlock, inputNames) {
this.selector = 'reifyPredicate';
slot = this.parts()[0];
slot.silentReplaceInput(slot.contents(), aBlock);
} else { // reporter
} else if (aBlock instanceof BooleanSlotMorph) {
this.isStatic = false;
this.setSpec('%rp %ringparms');
this.selector = 'reifyPredicate';
slot = this.parts()[0];
slot.silentReplaceInput(slot.contents(), aBlock);
} else { // reporter or input slot)
this.isStatic = false;
this.setSpec('%rr %ringparms');
this.selector = 'reifyReporter';
@ -7951,7 +7971,16 @@ TemplateSlotMorph.prototype.drawRounded = ReporterBlockMorph
%b - Boolean
%boolUE - Boolean unevaluated
evaluate returns null
I can be directly edited. When the user clicks on me I toggle
between <true>, <false> and <null> values.
evaluate returns my value.
my most important public attributes and accessors are:
value - user editable contents (Boolean or null)
setContents(Boolean/null) - display the argument (Boolean or null)
*/
// BooleanSlotMorph inherits from ArgMorph:
@ -7962,16 +7991,55 @@ BooleanSlotMorph.uber = ArgMorph.prototype;
// BooleanSlotMorph instance creation:
function BooleanSlotMorph() {
this.init();
function BooleanSlotMorph(initialValue) {
this.init(initialValue);
}
BooleanSlotMorph.prototype.init = function () {
BooleanSlotMorph.prototype.init = function (initialValue) {
this.value = (typeof initialValue === 'boolean') ? initialValue : null;
this.isUnevaluated = false;
BooleanSlotMorph.uber.init.call(this);
};
BooleanSlotMorph.prototype.getSpec = function () {
return '%b';
return this.isUnevaluated ? '%boolUE' : '%b';
};
// BooleanSlotMorph accessing:
BooleanSlotMorph.prototype.evaluate = function () {
return this.value;
};
BooleanSlotMorph.prototype.isEmptySlot = function () {
return this.value === null;
};
BooleanSlotMorph.prototype.setContents = function (boolOrNull) {
this.value = boolOrNull;
this.drawNew();
this.changed();
};
BooleanSlotMorph.prototype.toggleValue = function () {
if (this.isStatic) {
this.setContents(!this.value);
return;
}
switch (this.value) {
case true:
return this.setContents(false);
case false:
return this.setContents(null);
default:
this.setContents(true);
}
};
// BooleanSlotMorph events:
BooleanSlotMorph.prototype.mouseClickLeft = function () {
this.toggleValue();
};
// BooleanSlotMorph drawing:
@ -7982,15 +8050,14 @@ BooleanSlotMorph.prototype.drawNew = function () {
(this.fontSize + this.edge * 2) * 2,
this.fontSize + this.edge * 2
));
if (this.parent) {
this.color = this.parent.color;
}
this.color = this.parent ? this.parent.color : new Color(200, 200, 200);
this.cachedClr = this.color.toString();
this.cachedClrBright = this.bright();
this.cachedClrDark = this.dark();
this.image = newCanvas(this.extent());
context = this.image.getContext('2d');
this.drawDiamond(context, true);
this.drawDiamond(context);
this.drawKnob(context);
};
BooleanSlotMorph.prototype.drawDiamond = function (context) {
@ -8001,7 +8068,16 @@ BooleanSlotMorph.prototype.drawDiamond = function (context) {
gradient;
// draw the 'flat' shape:
context.fillStyle = this.color.darker(25).toString();
switch (this.value) {
case true:
context.fillStyle = 'rgb(0, 200, 0)';
break;
case false:
context.fillStyle = 'rgb(200, 0, 0)';
break;
default:
context.fillStyle = this.color.darker(25).toString();
}
context.beginPath();
context.moveTo(0, r);
@ -8097,10 +8173,107 @@ BooleanSlotMorph.prototype.drawDiamond = function (context) {
context.stroke();
};
// BooleanSlotMorph implicit formal parameters:
BooleanSlotMorph.prototype.drawKnob = function (context) {
var w = this.width(),
r = this.height() / 2,
shift = this.edge / 2,
gradient,
x,
y = r,
outline = PushButtonMorph.prototype.outline / 2,
outlineColor = PushButtonMorph.prototype.outlineColor,
color = PushButtonMorph.prototype.color,
contrast = PushButtonMorph.prototype.contrast,
topColor = color.lighter(contrast),
bottomColor = color.darker(contrast);
BooleanSlotMorph.prototype.isEmptySlot = function () {
return true;
// draw the 'flat' shape:
switch (this.value) {
case true:
x = r;
if (!MorphicPreferences.isFlat) {
context.shadowOffsetX = shift;
context.shadowBlur = shift;
context.shadowColor = 'black';
}
break;
case false:
x = w - r;
break;
default:
return;
}
context.fillStyle = color.toString();
context.beginPath();
context.arc(x, y, r, radians(0), radians(360));
context.closePath();
context.fill();
if (MorphicPreferences.isFlat) {return; }
// add 3D-Effect
// outline:
context.shadowOffsetX = 0;
context.shadowBlur = 0;
context.shadowColor = 'black';
context.lineWidth = outline;
context.strokeStyle = outlineColor.toString();
context.beginPath();
context.arc(x, y, r - (outline / 2), radians(0), radians(360));
context.stroke();
// top-left:
gradient = context.createRadialGradient(
x,
y,
r - outline - this.edge,
x,
y,
r - outline
);
gradient.addColorStop(1, topColor.toString());
gradient.addColorStop(0, color.toString());
context.strokeStyle = gradient;
context.lineCap = 'round';
context.lineWidth = this.edge;
context.beginPath();
context.arc(
x,
y,
r - outline - this.edge / 2,
radians(180),
radians(270),
false
);
context.stroke();
// bottom-right:
gradient = context.createRadialGradient(
x,
y,
r - outline - this.edge,
x,
y,
r - outline
);
gradient.addColorStop(1, bottomColor.toString());
gradient.addColorStop(0, color.toString());
context.strokeStyle = gradient;
context.lineCap = 'round';
context.lineWidth = this.edge;
context.beginPath();
context.arc(
x,
y,
r - outline - this.edge / 2,
radians(0),
radians(90),
false
);
context.stroke();
};
// ArrowMorph //////////////////////////////////////////////////////////
@ -11628,6 +11801,10 @@ ScriptFocusMorph.prototype.trigger = function () {
current.mouseClickLeft();
return;
}
if (current instanceof BooleanSlotMorph) {
current.toggleValue();
return;
}
if (current instanceof InputSlotMorph) {
if (!current.isReadOnly) {
delete this.fps;
@ -11670,6 +11847,10 @@ ScriptFocusMorph.prototype.deleteLastElement = function () {
if (current.arrows().children[0].isVisible) {
current.removeInput();
}
} else if (current instanceof BooleanSlotMorph) {
if (!current.isStatic) {
current.setContents(null);
}
} else if (current instanceof ReporterBlockMorph) {
if (!current.isTemplate) {
this.lastElement();
@ -11996,6 +12177,7 @@ ScriptFocusMorph.prototype.items = function () {
!(each instanceof TemplateSlotMorph) &&
(!each.isStatic ||
each.choices ||
each instanceof BooleanSlotMorph ||
each instanceof RingMorph ||
each instanceof MultiArgMorph ||
each instanceof CommandSlotMorph);
@ -12159,7 +12341,7 @@ ScriptFocusMorph.prototype.reactToKeyEvent = function (key) {
default:
types = this.blockTypes();
if (!(this.element instanceof ScriptsMorph) &&
contains(types, 'reporter')) {
types && contains(types, 'reporter')) {
vNames = Object.keys(this.element.getVarNamesDict());
}
if (types) {

Wyświetl plik

@ -2930,3 +2930,4 @@ http://snap.berkeley.edu/run#cloud:Username=jens&ProjectName=rotation
== v4.0.7.2 ====
* in progress: Retina Display Support, thanks, Bartosz Leper!!
* in progress: Interactive Toggle Switches for Boolean Slots and Literals

Wyświetl plik

@ -80,9 +80,9 @@ document, isNaN, isString, newCanvas, nop, parseFloat, radians, window,
modules, IDE_Morph, VariableDialogMorph, HTMLCanvasElement, Context, List,
SpeechBubbleMorph, RingMorph, isNil, FileReader, TableDialogMorph,
BlockEditorMorph, BlockDialogMorph, PrototypeHatBlockMorph, localize,
TableMorph, TableFrameMorph, normalizeCanvas*/
TableMorph, TableFrameMorph, normalizeCanvas, BooleanSlotMorph*/
modules.objects = '2016-May-11';
modules.objects = '2016-June-01';
var SpriteMorph;
var StageMorph;
@ -968,15 +968,10 @@ SpriteMorph.prototype.initBlocks = function () {
category: 'operators',
spec: 'not %b'
},
reportTrue: {
reportBoolean: {
type: 'predicate',
category: 'operators',
spec: 'true'
},
reportFalse: {
type: 'predicate',
category: 'operators',
spec: 'false'
spec: '%bool'
},
reportJoinWords: {
type: 'reporter',
@ -1220,6 +1215,14 @@ SpriteMorph.prototype.initBlockMigrations = function () {
receiveClick: {
selector: 'receiveInteraction',
inputs: [['clicked']]
},
reportTrue: {
selector: 'reportBoolean',
inputs: [true]
},
reportFalse: {
selector: 'reportBoolean',
inputs: [false]
}
};
};
@ -1292,8 +1295,6 @@ SpriteMorph.prototype.blockAlternatives = {
reportGreaterThan: ['reportEquals', 'reportLessThan'],
reportAnd: ['reportOr'],
reportOr: ['reportAnd'],
reportTrue: ['reportFalse'],
reportFalse: ['reportTrue'],
// variables
doSetVar: ['doChangeVar'],
@ -1991,9 +1992,7 @@ SpriteMorph.prototype.blockTemplates = function (category) {
blocks.push(block('reportAnd'));
blocks.push(block('reportOr'));
blocks.push(block('reportNot'));
blocks.push('-');
blocks.push(block('reportTrue'));
blocks.push(block('reportFalse'));
blocks.push(block('reportBoolean'));
blocks.push('-');
blocks.push(block('reportJoinWords'));
blocks.push(block('reportTextSplit'));
@ -4528,11 +4527,7 @@ SpriteMorph.prototype.fullThumbnail = function (extentPoint) {
// SpriteMorph Boolean visual representation
SpriteMorph.prototype.booleanMorph = function (bool) {
// answer a block which can be shown in watchers, speech bubbles etc.
var block = new ReporterBlockMorph(true);
block.color = SpriteMorph.prototype.blockColor.operators;
block.setSpec(localize(bool.toString()));
return block;
return new BooleanSlotMorph(bool);
};
// SpriteMorph nesting
@ -5758,9 +5753,7 @@ StageMorph.prototype.blockTemplates = function (category) {
blocks.push(block('reportAnd'));
blocks.push(block('reportOr'));
blocks.push(block('reportNot'));
blocks.push('-');
blocks.push(block('reportTrue'));
blocks.push(block('reportFalse'));
blocks.push(block('reportBoolean'));
blocks.push('-');
blocks.push(block('reportJoinWords'));
blocks.push(block('reportTextSplit'));

Wyświetl plik

@ -56,11 +56,11 @@ Color, List, newCanvas, Costume, Sound, Audio, IDE_Morph, ScriptsMorph,
BlockMorph, ArgMorph, InputSlotMorph, TemplateSlotMorph, CommandSlotMorph,
FunctionSlotMorph, MultiArgMorph, ColorSlotMorph, nop, CommentMorph, isNil,
localize, sizeOf, ArgLabelMorph, SVG_Costume, MorphicPreferences,
SyntaxElementMorph, Variable, isSnapObject, console*/
SyntaxElementMorph, Variable, isSnapObject, console, BooleanSlotMorph*/
// Global stuff ////////////////////////////////////////////////////////
modules.store = '2016-May-10';
modules.store = '2016-June-01';
// XML_Serializer ///////////////////////////////////////////////////////
@ -1134,7 +1134,7 @@ SnapSerializer.prototype.loadInput = function (model, input, block) {
SnapSerializer.prototype.loadValue = function (model) {
// private
var v, lst, items, el, center, image, name, audio, option,
var v, lst, items, el, center, image, name, audio, option, bool,
myself = this;
function record() {
@ -1165,7 +1165,14 @@ SnapSerializer.prototype.loadValue = function (model) {
throw new Error('expecting a reference id');
case 'l':
option = model.childNamed('option');
return option ? [option.contents] : model.contents;
if (option) {
return [option.contents];
}
bool = model.childNamed('bool');
if (bool) {
return this.loadValue(bool);
}
return model.contents;
case 'bool':
return model.contents === 'true';
case 'list':
@ -1248,7 +1255,14 @@ SnapSerializer.prototype.loadValue = function (model) {
} else {
el = model.childNamed('l');
if (el) {
v.expression = new InputSlotMorph(el.contents);
bool = el.childNamed('bool');
if (bool) {
v.expression = new BooleanSlotMorph(
this.loadValue(bool)
);
} else {
v.expression = new InputSlotMorph(el.contents);
}
}
}
}
@ -1842,6 +1856,13 @@ ArgMorph.prototype.toXML = function () {
return '<l/>'; // empty by default
};
BooleanSlotMorph.prototype.toXML = function () {
return (typeof this.value === 'boolean') ?
'<l><bool>' + this.value + '</bool></l>'
: '<l/>';
};
InputSlotMorph.prototype.toXML = function (serializer) {
if (this.constant) {
return serializer.format(

Wyświetl plik

@ -61,7 +61,7 @@ StageMorph, SpriteMorph, StagePrompterMorph, Note, modules, isString, copy,
isNil, WatcherMorph, List, ListWatcherMorph, alert, console, TableMorph,
TableFrameMorph, isSnapObject*/
modules.threads = '2016-May-31';
modules.threads = '2016-June-01';
var ThreadManager;
var Process;
@ -149,6 +149,8 @@ function invoke(
action.blockSequence(),
proc.homeContext
);
} else if (action.evaluate) {
return action.evaluate();
} else {
throw new Error('expecting a block or ring but getting ' + action);
}
@ -346,9 +348,7 @@ ThreadManager.prototype.doWhen = function (block, stopIt) {
}
}
if (stopIt) {return; }
if ((!block) ||
!(pred instanceof ReporterBlockMorph) ||
this.findProcess(block)
if ((!block) || this.findProcess(block)
) {return; }
try {
if (invoke(
@ -2293,12 +2293,8 @@ Process.prototype.isImmutable = function (obj) {
type === 'undefined';
};
Process.prototype.reportTrue = function () {
return true;
};
Process.prototype.reportFalse = function () {
return false;
Process.prototype.reportBoolean = function (bool) {
return bool;
};
Process.prototype.reportRound = function (n) {