From 78ab4de381c5c0d22475f830beeb993199355c22 Mon Sep 17 00:00:00 2001 From: jmoenig Date: Mon, 18 Mar 2013 12:32:24 +0100 Subject: [PATCH] Scalable blocks and scripts Shift-clicking on the settings menu lets you specify a fraction, by which blocks and scripts are scaled, allowing you to e.g. export poster-sized hi-res script pics, or to present Snap! live on hi-res screens and projectors --- blocks.js | 86 ++++++++++++++++++++++++++++++----------------------- byob.js | 18 ++++++----- gui.js | 56 +++++++++++++++++++++++++++++++++- history.txt | 7 ++++- widgets.js | 7 +++-- 5 files changed, 123 insertions(+), 51 deletions(-) diff --git a/blocks.js b/blocks.js index 223e9b67..25e360a7 100644 --- a/blocks.js +++ b/blocks.js @@ -153,7 +153,7 @@ DialogBoxMorph, BlockInputFragmentMorph, PrototypeHatBlockMorph*/ // Global stuff //////////////////////////////////////////////////////// -modules.blocks = '2013-February-26'; +modules.blocks = '2013-March-18'; var SyntaxElementMorph; var BlockMorph; @@ -296,37 +296,46 @@ SyntaxElementMorph.uber = Morph.prototype; rfColor - for reified outlines and slot backgrounds */ -SyntaxElementMorph.prototype.corner = 3; -SyntaxElementMorph.prototype.rounding = 9; -SyntaxElementMorph.prototype.edge = 1.000001; // shadow bug in Chrome -SyntaxElementMorph.prototype.inset = 6; -SyntaxElementMorph.prototype.hatHeight = 12; -SyntaxElementMorph.prototype.hatWidth = 70; -SyntaxElementMorph.prototype.rfBorder = 3; -SyntaxElementMorph.prototype.minWidth = 0; -SyntaxElementMorph.prototype.dent = 8; -SyntaxElementMorph.prototype.bottomPadding = 3; -SyntaxElementMorph.prototype.cSlotPadding = 4; -SyntaxElementMorph.prototype.typeInPadding = 1; -SyntaxElementMorph.prototype.labelPadding = 4; -SyntaxElementMorph.prototype.labelFontName = 'Verdana'; -SyntaxElementMorph.prototype.labelFontStyle = 'sans-serif'; -SyntaxElementMorph.prototype.fontSize = 10; -SyntaxElementMorph.prototype.embossing = new Point(-1, -1); -SyntaxElementMorph.prototype.labelWidth = 450; -SyntaxElementMorph.prototype.labelWordWrap = true; -SyntaxElementMorph.prototype.dynamicInputLabels = true; -SyntaxElementMorph.prototype.feedbackColor = new Color(255, 255, 255); -SyntaxElementMorph.prototype.feedbackMinHeight = 5; -SyntaxElementMorph.prototype.minSnapDistance = 20; -SyntaxElementMorph.prototype.reporterDropFeedbackPadding = 10; -SyntaxElementMorph.prototype.contrast = 65; -SyntaxElementMorph.prototype.labelContrast = 25; -SyntaxElementMorph.prototype.activeHighlight = new Color(153, 255, 213); -SyntaxElementMorph.prototype.errorHighlight = new Color(173, 15, 0); -SyntaxElementMorph.prototype.activeBlur = 20; -SyntaxElementMorph.prototype.activeBorder = 4; -SyntaxElementMorph.prototype.rfColor = new Color(120, 120, 120); +SyntaxElementMorph.prototype.setScale = function (num) { + var scale = Math.max(num, 1); + SyntaxElementMorph.prototype.scale = scale; + SyntaxElementMorph.prototype.corner = 3 * scale; + SyntaxElementMorph.prototype.rounding = 9 * scale; + SyntaxElementMorph.prototype.edge = 1.000001 * scale; + SyntaxElementMorph.prototype.inset = 6 * scale; + SyntaxElementMorph.prototype.hatHeight = 12 * scale; + SyntaxElementMorph.prototype.hatWidth = 70 * scale; + SyntaxElementMorph.prototype.rfBorder = 3 * scale; + SyntaxElementMorph.prototype.minWidth = 0; + SyntaxElementMorph.prototype.dent = 8 * scale; + SyntaxElementMorph.prototype.bottomPadding = 3 * scale; + SyntaxElementMorph.prototype.cSlotPadding = 4 * scale; + SyntaxElementMorph.prototype.typeInPadding = scale; + SyntaxElementMorph.prototype.labelPadding = 4 * scale; + SyntaxElementMorph.prototype.labelFontName = 'Verdana'; + SyntaxElementMorph.prototype.labelFontStyle = 'sans-serif'; + SyntaxElementMorph.prototype.fontSize = 10 * scale; + SyntaxElementMorph.prototype.embossing = new Point( + -1 * Math.max(scale / 2, 1), + -1 * Math.max(scale / 2, 1) + ); + SyntaxElementMorph.prototype.labelWidth = 450 * scale; + SyntaxElementMorph.prototype.labelWordWrap = true; + SyntaxElementMorph.prototype.dynamicInputLabels = true; + SyntaxElementMorph.prototype.feedbackColor = new Color(255, 255, 255); + SyntaxElementMorph.prototype.feedbackMinHeight = 5; + SyntaxElementMorph.prototype.minSnapDistance = 20; + SyntaxElementMorph.prototype.reporterDropFeedbackPadding = 10 * scale; + SyntaxElementMorph.prototype.contrast = 65; + SyntaxElementMorph.prototype.labelContrast = 25; + SyntaxElementMorph.prototype.activeHighlight = new Color(153, 255, 213); + SyntaxElementMorph.prototype.errorHighlight = new Color(173, 15, 0); + SyntaxElementMorph.prototype.activeBlur = 20; + SyntaxElementMorph.prototype.activeBorder = 4; + SyntaxElementMorph.prototype.rfColor = new Color(120, 120, 120); +}; + +SyntaxElementMorph.prototype.setScale(1); // SyntaxElementMorph instance creation: @@ -2033,6 +2042,7 @@ BlockMorph.prototype.showHelp = function () { BlockMorph.prototype.eraseHoles = function (context) { var myself = this, + isReporter = this instanceof ReporterBlockMorph, shift = this.edge * 0.5, gradient, rightX, @@ -2071,9 +2081,9 @@ BlockMorph.prototype.eraseHoles = function (context) { var w = hole.width(), h = Math.floor(hole.height()) - 2; // Opera needs this context.clearRect( - Math.floor(hole.bounds.origin.x - myself.bounds.origin.x), + Math.floor(hole.bounds.origin.x - myself.bounds.origin.x) + 1, Math.floor(hole.bounds.origin.y - myself.bounds.origin.y) + 1, - w, + isReporter ? w - 1 : w + 1, h ); }); @@ -2760,9 +2770,9 @@ CommandBlockMorph.prototype.drawNew = function () { CommandBlockMorph.prototype.drawBody = function (context) { context.fillRect( 0, - this.corner, + Math.floor(this.corner), this.width(), - this.height() - (this.corner * 3) + this.height() - Math.floor(this.corner * 3) + 1 ); }; @@ -3173,9 +3183,9 @@ HatBlockMorph.prototype.drawTop = function (context) { HatBlockMorph.prototype.drawBody = function (context) { context.fillRect( 0, - this.hatHeight + this.corner, + this.hatHeight + Math.floor(this.corner) - 1, this.width(), - this.height() - (this.corner * 3) - (this.hatHeight) + this.height() - Math.floor(this.corner * 3) - this.hatHeight + 2 ); }; diff --git a/byob.js b/byob.js index e8c80807..29ab1b54 100644 --- a/byob.js +++ b/byob.js @@ -105,7 +105,7 @@ CommentMorph, localize, CSlotMorph*/ // Global stuff //////////////////////////////////////////////////////// -modules.byob = '2013-February-18'; +modules.byob = '2013-March-18'; // Declarations @@ -2002,7 +2002,7 @@ BlockLabelPlaceHolderMorph.prototype.drawNew = function () { context.beginPath(); context.arc( cx, - cy, + cy * 1.2, Math.min(cx, cy), radians(0), radians(360), @@ -2127,7 +2127,8 @@ InputSlotDialogMorph.prototype.init = function ( environment, category ) { - var fh = fontHeight(10) / 1.2; // "raw height" + var scale = SyntaxElementMorph.prototype.scale, + fh = fontHeight(10) / 1.2 * scale; // "raw height" // additional properties: this.fragment = fragment || new BlockLabelFragment(); @@ -2152,7 +2153,7 @@ InputSlotDialogMorph.prototype.init = function ( this.slots = new BoxMorph(); this.slots.color = new Color(55, 55, 55); // same as palette this.slots.borderColor = this.slots.color.lighter(50); - this.slots.setExtent(new Point((fh + 10) * 24, (fh + 10) * 10.4)); + this.slots.setExtent(new Point((fh + 10) * 24, (fh + 10 * scale) * 10.4)); this.add(this.slots); this.createSlotTypeButtons(); this.fixSlotsLayout(); @@ -2548,10 +2549,11 @@ InputSlotDialogMorph.prototype.addSlotArityButton = function ( InputSlotDialogMorph.prototype.fixSlotsLayout = function () { var slots = this.slots, - xPadding = 10, - ypadding = 14, - bh = fontHeight(10) / 1.2 + 15, // slot type button height - ah = fontHeight(10) / 1.2 + 10, // arity button height + scale = SyntaxElementMorph.prototype.scale, + xPadding = 10 * scale, + ypadding = 14 * scale, + bh = (fontHeight(10) / 1.2 + 15) * scale, // slot type button height + ah = (fontHeight(10) / 1.2 + 10) * scale, // arity button height size = 12, // number slot type radio buttons cols = [ slots.left() + xPadding, diff --git a/gui.js b/gui.js index 6056277e..0619201a 100644 --- a/gui.js +++ b/gui.js @@ -68,7 +68,7 @@ sb*/ // Global stuff //////////////////////////////////////////////////////// -modules.gui = '2013-March-15'; +modules.gui = '2013-March-18'; // Declarations @@ -1687,6 +1687,14 @@ IDE_Morph.prototype.settingsMenu = function () { menu = new MenuMorph(this); menu.addItem('Language...', 'languageMenu'); + if (shiftClicked) { + menu.addItem( + 'Scale blocks...', + 'userSetBlocksScale', + null, + new Color(100, 0, 0) + ); + } menu.addLine(); addPreference( 'Blurred shadows', @@ -2760,6 +2768,52 @@ IDE_Morph.prototype.reflectLanguage = function (lang) { this.openProjectString(projectData); }; +// IDE_Morph blocks scaling + +IDE_Morph.prototype.userSetBlocksScale = function () { + var myself = this; + new DialogBoxMorph( + null, + function (num) { + myself.setBlocksScale(num); + } + ).prompt( + 'Scale Blocks', + SyntaxElementMorph.prototype.scale.toString(), + this.world(), + null, + { + 'normal (1)' : 1, + 'demo (1.2)' : 1.2, + 'big (2)' : 2, + 'huge (4)' : 4, + 'giant (8)' : 8 + }, + false, // read only? + true // numeric + ); +}; + +IDE_Morph.prototype.setBlocksScale = function (num) { + var projectData; + if (Process.prototype.isCatchingErrors) { + try { + projectData = this.serializer.serialize(this.stage); + } catch (err) { + this.showMessage('Serialization failed: ' + err); + } + } else { + projectData = this.serializer.serialize(this.stage); + } + SyntaxElementMorph.prototype.setScale(num); + SpriteMorph.prototype.initBlocks(); + this.spriteBar.tabBar.tabTo('scripts'); + this.createCategories(); + this.createCorralBar(); + this.fixLayout(); + this.openProjectString(projectData); +}; + // IDE_Morph cloud interface IDE_Morph.prototype.initializeCloud = function () { diff --git a/history.txt b/history.txt index bf72c0ee..46e615af 100755 --- a/history.txt +++ b/history.txt @@ -1522,4 +1522,9 @@ ______ 130314 ------ * GUI: When logged into the Cloud, "cloud" becomes default in the project dialog -* Store: local custom blocks can now store their definition receiver directly as value (avoiding turning them into "Obsolete!" blocks when re-opening the project), this is important for reified blocks assigned to variables elsewhere, and such for the part of OOP we can already do now. \ No newline at end of file +* Store: local custom blocks can now store their definition receiver directly as value (avoiding turning them into "Obsolete!" blocks when re-opening the project), this is important for reified blocks assigned to variables elsewhere, and such for the part of OOP we can already do now. + +130318 +------ +* GUI, Blocks, BYOB, Widgets: Scaling Blocks and Scripts (shift-click on settings menu) +* Widets: numerical prompts \ No newline at end of file diff --git a/widgets.js b/widgets.js index 6740ef5e..2760171c 100644 --- a/widgets.js +++ b/widgets.js @@ -73,7 +73,7 @@ newCanvas, StringMorph, Morph, TextMorph, nop, detect, StringFieldMorph, HTMLCanvasElement, fontHeight, SymbolMorph, localize, SpeechBubbleMorph, ArrowMorph, MenuMorph, isString*/ -modules.widgets = '2013-February-26'; +modules.widgets = '2013-March-18'; var PushButtonMorph; var ToggleButtonMorph; @@ -1531,11 +1531,12 @@ DialogBoxMorph.prototype.prompt = function ( world, pic, choices, // optional dictionary for drop-down of choices - isReadOnly // optional when using choices + isReadOnly, // optional when using choices + isNumeric // optional ) { var txt = new InputFieldMorph( defaultString, - false, // numeric? + isNumeric || false, // numeric? choices || null, // drop-down dict, optional choices ? isReadOnly || false : false );