summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--blocks.js165
-rw-r--r--byob.js3
-rw-r--r--gui.js58
-rwxr-xr-xhistory.txt4
-rw-r--r--objects.js10
-rw-r--r--store.js38
-rw-r--r--threads.js10
-rw-r--r--widgets.js32
8 files changed, 261 insertions, 59 deletions
diff --git a/blocks.js b/blocks.js
index ce2a714..4258610 100644
--- a/blocks.js
+++ b/blocks.js
@@ -155,7 +155,7 @@ DialogBoxMorph, BlockInputFragmentMorph, PrototypeHatBlockMorph*/
// Global stuff ////////////////////////////////////////////////////////
-modules.blocks = '2013-June-25';
+modules.blocks = '2013-July-04';
var SyntaxElementMorph;
var BlockMorph;
@@ -1535,10 +1535,10 @@ SyntaxElementMorph.prototype.showBubble = function (value) {
it's not part of Snap's evaluator and not needed for Snap itself
*/
-SyntaxElementMorph.prototype.mappedCode = function () {
+SyntaxElementMorph.prototype.mappedCode = function (definitions) {
var result = this.evaluate();
if (result instanceof BlockMorph) {
- return result.mappedCode();
+ return result.mappedCode(definitions);
}
return result;
};
@@ -1859,6 +1859,10 @@ BlockMorph.prototype.userMenu = function () {
if (StageMorph.prototype.enableCodeMapping) {
menu.addLine();
menu.addItem(
+ 'header mapping...',
+ 'mapToHeader'
+ );
+ menu.addItem(
'code mapping...',
'mapToCode'
);
@@ -1941,6 +1945,11 @@ BlockMorph.prototype.userMenu = function () {
menu.addLine();
menu.addItem("ringify", 'ringify');
if (StageMorph.prototype.enableCodeMapping) {
+ menu.addLine();
+ menu.addItem(
+ 'header mapping...',
+ 'mapToHeader'
+ );
menu.addItem(
'code mapping...',
'mapToCode'
@@ -2182,6 +2191,45 @@ BlockMorph.prototype.showHelp = function () {
it's not part of Snap's evaluator and not needed for Snap itself
*/
+BlockMorph.prototype.mapToHeader = function () {
+ // open a dialog box letting the user map header code via the GUI
+ var key = this.selector.substr(0, 5) === 'reify' ?
+ 'reify' : this.selector,
+ block = this.codeDefinitionHeader(),
+ myself = this,
+ help,
+ pic;
+ block.addShadow(new Point(3, 3));
+ pic = block.fullImageClassic();
+ if (this.definition) {
+ help = 'Enter code that corresponds to the block\'s definition. ' +
+ 'Use the formal parameter\nnames as shown and <body> to ' +
+ 'reference the definition body\'s generated text code.';
+ } else {
+ help = 'Enter code that corresponds to the block\'s definition. ' +
+ 'Choose your own\nformal parameter names (ignoring the ones ' +
+ 'shown .';
+ }
+ new DialogBoxMorph(
+ this,
+ function (code) {
+ if (key === 'evaluateCustomBlock') {
+ myself.definition.codeHeader = code;
+ } else {
+ StageMorph.prototype.codeHeaders[key] = code;
+ }
+ },
+ this
+ ).promptCode(
+ 'Header mapping',
+ key === 'evaluateCustomBlock' ? this.definition.codeHeader || ''
+ : StageMorph.prototype.codeHeaders[key] || '',
+ this.world(),
+ pic,
+ help
+ );
+};
+
BlockMorph.prototype.mapToCode = function () {
// open a dialog box letting the user map code via the GUI
var key = this.selector.substr(0, 5) === 'reify' ?
@@ -2206,10 +2254,26 @@ BlockMorph.prototype.mapToCode = function () {
key === 'evaluateCustomBlock' ? this.definition.codeMapping || ''
: StageMorph.prototype.codeMappings[key] || '',
this.world(),
- pic
+ pic,
+ 'Enter code that corresponds to the block\'s operation ' +
+ '(usually a single\nfunction invocation). Use <#n> to ' +
+ 'reference actual arguments as shown.'
);
};
+BlockMorph.prototype.mapHeader = function (aString, key) {
+ // primitive for programatically mapping header code
+ var sel = key || this.selector.substr(0, 5) === 'reify' ?
+ 'reify' : this.selector;
+ if (aString) {
+ if (this.definition) { // custom block
+ this.definition.codeHeader = aString;
+ } else {
+ StageMorph.prototype.codeHeaders[sel] = aString;
+ }
+ }
+};
+
BlockMorph.prototype.mapCode = function (aString, key) {
// primitive for programatically mapping code
var sel = key || this.selector.substr(0, 5) === 'reify' ?
@@ -2223,19 +2287,63 @@ BlockMorph.prototype.mapCode = function (aString, key) {
}
};
-BlockMorph.prototype.mappedCode = function () {
+BlockMorph.prototype.mappedCode = function (definitions) {
var key = this.selector.substr(0, 5) === 'reify' ?
'reify' : this.selector,
code,
codeLines,
count = 1,
+ header,
+ headers,
+ headerLines,
+ body,
+ bodyLines,
+ defKey = this.definition ? this.definition.spec : key,
+ defs = definitions || {},
parts = [];
code = key === 'reportGetVar' ? this.blockSpec
: this.definition ? this.definition.codeMapping || ''
: StageMorph.prototype.codeMappings[key] || '';
+
+ // map header
+ if (key !== 'reportGetVar' && !defs.hasOwnProperty(defKey)) {
+ defs[defKey] = null; // create the property for recursive definitions
+ if (this.definition) {
+ header = this.definition.codeHeader || '';
+ if (header.indexOf('<body') !== -1) { // replace with def mapping
+ body = '';
+ if (this.definition.body) {
+ body = this.definition.body.expression.mappedCode(defs);
+ }
+ bodyLines = body.split('\n');
+ headerLines = header.split('\n');
+ headerLines.forEach(function (headerLine, idx) {
+ var prefix = '',
+ indent;
+ if (headerLine.trimLeft().indexOf('<body') === 0) {
+ indent = headerLine.indexOf('<body');
+ prefix = headerLine.slice(0, indent);
+ }
+ headerLines[idx] = headerLine.replace(
+ new RegExp('<body>'),
+ bodyLines.join('\n' + prefix)
+ );
+ headerLines[idx] = headerLines[idx].replace(
+ new RegExp('<body>', 'g'),
+ bodyLines.join('\n')
+ );
+ });
+ header = headerLines.join('\n');
+ }
+ defs[defKey] = header;
+ } else {
+ defs[defKey] = StageMorph.prototype.codeHeaders[defKey];
+ }
+ }
+
codeLines = code.split('\n');
this.inputs().forEach(function (input) {
- parts.push(input.mappedCode().toString());
+ parts.push(input.mappedCode(defs).toString());
});
parts.forEach(function (part) {
var partLines = part.split('\n'),
@@ -2258,11 +2366,46 @@ BlockMorph.prototype.mappedCode = function () {
});
code = codeLines.join('\n');
if (this.nextBlock && this.nextBlock()) { // Command
- code += ('\n' + this.nextBlock().mappedCode());
+ code += ('\n' + this.nextBlock().mappedCode(defs));
+ }
+ if (!definitions) { // top-level, add headers
+ headers = [];
+ Object.keys(defs).forEach(function (each) {
+ if (defs[each]) {
+ headers.push(defs[each]);
+ }
+ });
+ if (headers.length) {
+ return headers.join('\n\n')
+ + '\n\n'
+ + code;
+ }
}
return code;
};
+BlockMorph.prototype.codeDefinitionHeader = function () {
+ var block = this.definition ? new PrototypeHatBlockMorph(this.definition)
+ : SpriteMorph.prototype.blockForSelector(this.selector),
+ hat = new HatBlockMorph(),
+ count = 1;
+
+ if (this.definition) {return block; }
+ block.inputs().forEach(function (input) {
+ var part = new TemplateSlotMorph('#' + count);
+ block.silentReplaceInput(input, part);
+ count += 1;
+ });
+ block.isPrototype = true;
+ hat.setCategory("control");
+ hat.setSpec('%s');
+ hat.silentReplaceInput(hat.inputs()[0], block);
+ if (this.category === 'control') {
+ hat.alternateBlockColor();
+ }
+ return hat;
+};
+
BlockMorph.prototype.codeMappingHeader = function () {
var block = this.definition ? this.definition.blockInstance()
: SpriteMorph.prototype.blockForSelector(this.selector),
@@ -5402,11 +5545,11 @@ CSlotMorph.prototype.getSpec = function () {
return '%c';
};
-CSlotMorph.prototype.mappedCode = function () {
+CSlotMorph.prototype.mappedCode = function (definitions) {
var code = StageMorph.prototype.codeMappings.reify || '<#1>',
codeLines = code.split('\n'),
nested = this.nestedBlock(),
- part = nested ? nested.mappedCode() : '',
+ part = nested ? nested.mappedCode(definitions) : '',
partLines = (part.toString()).split('\n'),
rx = new RegExp('<#1>', 'g');
@@ -8541,7 +8684,7 @@ MultiArgMorph.prototype.mapToCode = function (key, label) {
);
};
-MultiArgMorph.prototype.mappedCode = function () {
+MultiArgMorph.prototype.mappedCode = function (definitions) {
var block = this.parentThatIsA(BlockMorph),
key = '',
code,
@@ -8564,7 +8707,7 @@ MultiArgMorph.prototype.mappedCode = function () {
delim = StageMorph.prototype.codeMappings[key + 'delim'] || ' ';
this.inputs().forEach(function (input) {
- parts.push(itemCode.replace(/<#1>/g, input.mappedCode()));
+ parts.push(itemCode.replace(/<#1>/g, input.mappedCode(definitions)));
});
parts.forEach(function (part) {
if (count) {
diff --git a/byob.js b/byob.js
index d8c0813..8954c6a 100644
--- a/byob.js
+++ b/byob.js
@@ -105,7 +105,7 @@ CommentMorph, localize, CSlotMorph, SpeechBubbleMorph, MorphicPreferences*/
// Global stuff ////////////////////////////////////////////////////////
-modules.byob = '2013-June-18';
+modules.byob = '2013-July-04';
// Declarations
@@ -139,6 +139,7 @@ function CustomBlockDefinition(spec, receiver) {
this.declarations = {}; // {'inputName' : [type, default]}
this.comment = null;
this.codeMapping = null; // experimental, generate text code
+ this.codeHeader = null; // experimental, generate text code
// don't serialize (not needed for functionality):
this.receiver = receiver || null; // for serialization only (pointer)
diff --git a/gui.js b/gui.js
index f0880ff..d13df20 100644
--- a/gui.js
+++ b/gui.js
@@ -68,7 +68,7 @@ sb, CommentMorph, CommandBlockMorph*/
// Global stuff ////////////////////////////////////////////////////////
-modules.gui = '2013-July-02';
+modules.gui = '2013-July-04';
// Declarations
@@ -1681,8 +1681,7 @@ IDE_Morph.prototype.applySavedSettings = function () {
zoom = this.getSetting('zoom'),
language = this.getSetting('language'),
click = this.getSetting('click'),
- longform = this.getSetting('longform'),
- code = this.getSetting('code');
+ longform = this.getSetting('longform');
// design
if (design === 'flat') {
@@ -1714,11 +1713,6 @@ IDE_Morph.prototype.applySavedSettings = function () {
if (longform) {
InputSlotDialogMorph.prototype.isLaunchingExpanded = true;
}
-
- // code mapping
- if (code && !StageMorph.prototype.enableCodeMapping) {
- StageMorph.prototype.enableCodeMapping = true;
- }
};
IDE_Morph.prototype.saveSetting = function (key, value) {
@@ -1763,7 +1757,7 @@ IDE_Morph.prototype.addNewSprite = function () {
this.selectSprite(sprite);
};
-IDE_Morph.prototype.paintNewSprite = function() {
+IDE_Morph.prototype.paintNewSprite = function () {
var sprite = new SpriteMorph(this.globalVariables),
cos = new Costume(),
myself = this;
@@ -1779,7 +1773,7 @@ IDE_Morph.prototype.paintNewSprite = function() {
this.world(),
this,
true,
- function() {myself.removeSprite(sprite); },
+ function () {myself.removeSprite(sprite); },
function () {
sprite.addCostume(cos);
sprite.wearCostume(cos);
@@ -2158,26 +2152,7 @@ IDE_Morph.prototype.settingsMenu = function () {
'check for alternative\nGUI design',
false
);
- addPreference(
- 'Code mapping',
- function () {
- StageMorph.prototype.enableCodeMapping =
- !StageMorph.prototype.enableCodeMapping;
- if (StageMorph.prototype.enableCodeMapping) {
- myself.saveSetting('code', true);
- } else {
- myself.removeSetting('code');
- }
- myself.currentSprite.blocksCache.variables = null;
- myself.currentSprite.paletteCache.variables = null;
- myself.refreshPalette();
- },
- StageMorph.prototype.enableCodeMapping,
- 'uncheck to disable\nblock to text mapping features',
- 'check for block\nto text mapping features',
- false
- );
- menu.addLine(); // everything below this line is made persistent
+ menu.addLine(); // everything below this line is stored in the project
addPreference(
'Thread safe scripts',
function () {stage.isThreadSafe = !stage.isThreadSafe; },
@@ -2192,6 +2167,20 @@ IDE_Morph.prototype.settingsMenu = function () {
'uncheck for greater speed\nat variable frame rates',
'check for smooth, predictable\nanimations across computers'
);
+ addPreference(
+ 'Codification support',
+ function () {
+ StageMorph.prototype.enableCodeMapping =
+ !StageMorph.prototype.enableCodeMapping;
+ myself.currentSprite.blocksCache.variables = null;
+ myself.currentSprite.paletteCache.variables = null;
+ myself.refreshPalette();
+ },
+ StageMorph.prototype.enableCodeMapping,
+ 'uncheck to disable\nblock to text mapping features',
+ 'check for block\nto text mapping features',
+ false
+ );
menu.popup(world, pos);
};
@@ -2580,6 +2569,9 @@ IDE_Morph.prototype.newProject = function () {
this.currentSprite = new SpriteMorph(this.globalVariables);
this.sprites = new List([this.currentSprite]);
StageMorph.prototype.hiddenPrimitives = {};
+ StageMorph.prototype.codeMappings = {};
+ StageMorph.prototype.codeHeaders = {};
+ StageMorph.prototype.enableCodeMapping = false;
this.setProjectName('');
this.projectNotes = '';
this.createStage();
@@ -5115,7 +5107,7 @@ CostumeIconMorph.prototype.renameCostume = function () {
);
};
-CostumeIconMorph.prototype.duplicateCostume = function() {
+CostumeIconMorph.prototype.duplicateCostume = function () {
var wardrobe = this.parentThatIsA(WardrobeMorph),
ide = this.parentThatIsA(IDE_Morph),
newcos = this.object.copy(),
@@ -5494,11 +5486,11 @@ WardrobeMorph.prototype.removeCostumeAt = function (idx) {
this.updateList();
};
-WardrobeMorph.prototype.paintNew = function() {
+WardrobeMorph.prototype.paintNew = function () {
var cos = new Costume(newCanvas(), "Untitled"),
ide = this.parentThatIsA(IDE_Morph),
myself = this;
- cos.edit(this.world(), ide, true, null, function() {
+ cos.edit(this.world(), ide, true, null, function () {
myself.sprite.addCostume(cos);
myself.updateList();
if (ide) {
diff --git a/history.txt b/history.txt
index 61e7306..0abd8df 100755
--- a/history.txt
+++ b/history.txt
@@ -1778,3 +1778,7 @@ ______
------
* Objects: took out "security margin" in Costume's shrinkWrap() method b/c Chrome no longer needs it -> fixed empty costume bug when drawing over the paint editor's bounds
* GUI: Import libraries feature (in the project menu)
+
+130704
+------
+* Codification (text code mapping and block header support)
diff --git a/objects.js b/objects.js
index 3d014cd..038b61e 100644
--- a/objects.js
+++ b/objects.js
@@ -123,7 +123,7 @@ PrototypeHatBlockMorph*/
// Global stuff ////////////////////////////////////////////////////////
-modules.objects = '2013-July-02';
+modules.objects = '2013-July-04';
var SpriteMorph;
var StageMorph;
@@ -1019,6 +1019,11 @@ SpriteMorph.prototype.initBlocks = function () {
},
// Code mapping - experimental
+ doMapHeader: { // experimental
+ type: 'command',
+ category: 'other',
+ spec: 'map %cmdRing to header %code'
+ },
doMapCode: { // experimental
type: 'command',
category: 'other',
@@ -1795,6 +1800,7 @@ SpriteMorph.prototype.blockTemplates = function (category) {
blocks.push('=');
if (StageMorph.prototype.enableCodeMapping) {
+ blocks.push(block('doMapHeader'));
blocks.push(block('doMapCode'));
blocks.push(block('doMapStringCode'));
blocks.push(block('doMapListCode'));
@@ -3223,6 +3229,7 @@ StageMorph.prototype.paletteTextColor
StageMorph.prototype.hiddenPrimitives = {};
StageMorph.prototype.codeMappings = {};
+StageMorph.prototype.codeHeaders = {};
StageMorph.prototype.enableCodeMapping = false;
// StageMorph instance creation
@@ -4047,6 +4054,7 @@ StageMorph.prototype.blockTemplates = function (category) {
blocks.push('=');
if (StageMorph.prototype.enableCodeMapping) {
+ blocks.push(block('doMapHeader'));
blocks.push(block('doMapCode'));
blocks.push(block('doMapStringCode'));
blocks.push(block('doMapListCode'));
diff --git a/store.js b/store.js
index 9736b6d..57b124a 100644
--- a/store.js
+++ b/store.js
@@ -61,7 +61,7 @@ SyntaxElementMorph*/
// Global stuff ////////////////////////////////////////////////////////
-modules.store = '2013-June-19';
+modules.store = '2013-July-04';
// XML_Serializer ///////////////////////////////////////////////////////
@@ -378,6 +378,8 @@ SnapSerializer.prototype.loadProjectModel = function (xmlNode) {
project.stage.setExtent(StageMorph.prototype.dimensions);
project.stage.isThreadSafe =
model.stage.attributes.threadsafe === 'true';
+ StageMorph.prototype.enableCodeMapping =
+ model.stage.attributes.codify === 'true';
model.hiddenPrimitives = model.project.childNamed('hidden');
if (model.hiddenPrimitives) {
@@ -390,6 +392,13 @@ SnapSerializer.prototype.loadProjectModel = function (xmlNode) {
);
}
+ model.codeHeaders = model.project.childNamed('headers');
+ if (model.codeHeaders) {
+ model.codeHeaders.children.forEach(function (xml) {
+ StageMorph.prototype.codeHeaders[xml.tag] = xml.contents;
+ });
+ }
+
model.codeMappings = model.project.childNamed('code');
if (model.codeMappings) {
model.codeMappings.children.forEach(function (xml) {
@@ -672,7 +681,7 @@ SnapSerializer.prototype.loadCustomBlocks = function (
// private
var myself = this;
element.children.forEach(function (child) {
- var definition, names, inputs, code, comment, i;
+ var definition, names, inputs, header, code, comment, i;
if (child.tag !== 'block-definition') {
return;
}
@@ -711,6 +720,11 @@ SnapSerializer.prototype.loadCustomBlocks = function (
});
}
+ header = child.childNamed('header');
+ if (header) {
+ definition.codeHeader = header.contents;
+ }
+
code = child.childNamed('code');
if (code) {
definition.codeMapping = code.contents;
@@ -1266,20 +1280,20 @@ StageMorph.prototype.toXML = function (serializer) {
thumbdata = null;
}
- function codeMappings() {
- var code = '';
- Object.keys(StageMorph.prototype.codeMappings).forEach(
+ function code(key) {
+ var str = '';
+ Object.keys(StageMorph.prototype[key]).forEach(
function (selector) {
- code += (
+ str += (
'<' + selector + '>' +
XML_Element.prototype.escape(
- StageMorph.prototype.codeMappings[selector]
+ StageMorph.prototype[key][selector]
) +
'</' + selector + '>'
);
}
);
- return code;
+ return str;
}
this.removeAllClones();
@@ -1288,6 +1302,7 @@ StageMorph.prototype.toXML = function (serializer) {
'<notes>$</notes>' +
'<thumbnail>$</thumbnail>' +
'<stage name="@" costume="@" tempo="@" threadsafe="@" ' +
+ 'codify="@" ' +
'scheduled="@" ~>' +
'<pentrails>$</pentrails>' +
'<costumes>%</costumes>' +
@@ -1297,6 +1312,7 @@ StageMorph.prototype.toXML = function (serializer) {
'<scripts>%</scripts><sprites>%</sprites>' +
'</stage>' +
'<hidden>$</hidden>' +
+ '<headers>%</headers>' +
'<code>%</code>' +
'<blocks>%</blocks>' +
'<variables>%</variables>' +
@@ -1310,6 +1326,7 @@ StageMorph.prototype.toXML = function (serializer) {
this.getCostumeIdx(),
this.getTempo(),
this.isThreadSafe,
+ this.enableCodeMapping,
StageMorph.prototype.frameRate !== 0,
this.trailsCanvas.toDataURL('image/png'),
serializer.store(this.costumes, this.name + '_cst'),
@@ -1322,7 +1339,8 @@ StageMorph.prototype.toXML = function (serializer) {
function (a, b) {return a + ' ' + b; },
''
),
- codeMappings(),
+ code('codeHeaders'),
+ code('codeMappings'),
serializer.store(this.globalBlocks),
(ide && ide.globalVariables) ?
serializer.store(ide.globalVariables) : ''
@@ -1587,6 +1605,7 @@ CustomBlockDefinition.prototype.toXML = function (serializer) {
return serializer.format(
'<block-definition s="@" type="@" category="@">' +
'%' +
+ '<header>@</header>' +
'<code>@</code>' +
'<inputs>%</inputs>%%' +
'</block-definition>',
@@ -1594,6 +1613,7 @@ CustomBlockDefinition.prototype.toXML = function (serializer) {
this.type,
this.category || 'other',
this.comment ? this.comment.toXML(serializer) : '',
+ this.codeHeader || '',
this.codeMapping || '',
Object.keys(this.declarations).reduce(function (xml, decl) {
return xml + serializer.format(
diff --git a/threads.js b/threads.js
index d98d2b5..ab904ad 100644
--- a/threads.js
+++ b/threads.js
@@ -83,7 +83,7 @@ ArgLabelMorph, localize*/
// Global stuff ////////////////////////////////////////////////////////
-modules.threads = '2013-June-18';
+modules.threads = '2013-July-04';
var ThreadManager;
var Process;
@@ -2291,6 +2291,14 @@ Process.prototype.reportTimer = function () {
blocks - not needed to run or debug Snap
*/
+Process.prototype.doMapHeader = function (aContext, aString) {
+ if (aContext instanceof Context) {
+ if (aContext.expression instanceof SyntaxElementMorph) {
+ return aContext.expression.mapHeader(aString || '');
+ }
+ }
+};
+
Process.prototype.doMapCode = function (aContext, aString) {
if (aContext instanceof Context) {
if (aContext.expression instanceof SyntaxElementMorph) {
diff --git a/widgets.js b/widgets.js
index 7d12549..45ef2d1 100644
--- a/widgets.js
+++ b/widgets.js
@@ -74,7 +74,7 @@ HTMLCanvasElement, fontHeight, SymbolMorph, localize, SpeechBubbleMorph,
ArrowMorph, MenuMorph, isString, isNil, SliderMorph, MorphicPreferences,
ScrollFrameMorph*/
-modules.widgets = '2013-June-25';
+modules.widgets = '2013-July-04';
var PushButtonMorph;
var ToggleButtonMorph;
@@ -1680,16 +1680,33 @@ DialogBoxMorph.prototype.promptCode = function (
title,
defaultString,
world,
- pic
+ pic,
+ instructions
) {
var frame = new ScrollFrameMorph(),
text = new TextMorph(defaultString || ''),
+ bdy = new AlignmentMorph('column', this.padding),
size = pic ? Math.max(pic.width, 400) : 400;
this.getInput = function () {
return text.text;
};
+ function remarkText(string) {
+ return new TextMorph(
+ string,
+ 10,
+ null, // style
+ false, // bold
+ null, // italic
+ null, // alignment
+ null, // width
+ null, // font name
+ MorphicPreferences.isFlat ? null : new Point(1, 1),
+ new Color(255, 255, 255) // shadowColor
+ );
+ }
+
frame.padding = 6;
frame.setWidth(size);
frame.acceptsDrops = false;
@@ -1723,8 +1740,17 @@ DialogBoxMorph.prototype.promptCode = function (
this.key = 'promptCode' + title + defaultString;
}
- this.addBody(frame);
+ bdy.setColor(this.color);
+ bdy.add(frame);
+ if (instructions) {
+ bdy.add(remarkText(instructions));
+ }
+ bdy.fixLayout();
+
+ this.addBody(bdy);
frame.drawNew();
+ bdy.drawNew();
+
this.addButton('ok', 'OK');
this.addButton('cancel', 'Cancel');
this.fixLayout();