From 3b56f75efa18f06154a2c6a5d9ece6b936cd2d58 Mon Sep 17 00:00:00 2001 From: jmoenig Date: Fri, 19 Nov 2021 18:59:35 +0100 Subject: [PATCH] visually indicate empty categories by half-toning their buttons --- HISTORY.md | 6 +++++- snap.html | 6 +++--- src/byob.js | 6 +++++- src/gui.js | 40 +++++++++++++++++++++++++++++++++++----- src/objects.js | 26 ++++++++++++++++++++++++-- sw.js | 2 +- 6 files changed, 73 insertions(+), 13 deletions(-) diff --git a/HISTORY.md b/HISTORY.md index 9785b649..2f27f058 100755 --- a/HISTORY.md +++ b/HISTORY.md @@ -16,7 +16,8 @@ * block-instances can be dragged off from templates in the "export blocks", "unused blocks" and "hide blocks" dialogs * added "enter" key to key-pressed dropdown * added green flag symbol to message drop-down - * the green flag button's background color indicates whether the current scene is running or idle + * the green flag button's background color indicates whether the current scene is running or idle + * empty categories are indicated by half-tone buttons * new preference setting per scene for pen color model and graphic effects, HSV or HSL, default is HSV * new preference setting per scene to "disable click-to-run" on blocks, for use in micro-world extensions * **Notable Changes:** @@ -62,6 +63,9 @@ * Chinese, thanks, Simon! * Brazilian Portuguese, thank you, Cassiano D'Andrea! +### 2021-11-19 +* objects, byob, gui: visually indicate empty categories by half-toning their buttons + ### 2021-11-18 * gui: only pause generic hat blocks when loading a new project, not when switching to a new scene diff --git a/snap.html b/snap.html index f1e50fc0..102ed5ac 100755 --- a/snap.html +++ b/snap.html @@ -18,12 +18,12 @@ - + - + - + diff --git a/src/byob.js b/src/byob.js index ec51bec8..0a671354 100644 --- a/src/byob.js +++ b/src/byob.js @@ -110,7 +110,7 @@ WatcherMorph, XML_Serializer, SnapTranslator, SnapExtensions*/ // Global stuff //////////////////////////////////////////////////////// -modules.byob = '2021-November-09'; +modules.byob = '2021-November-19'; // Declarations @@ -1368,6 +1368,7 @@ CustomCommandBlockMorph.prototype.deleteBlockDefinition = function () { ide = rcvr.parentThatIsA(IDE_Morph); if (ide) { ide.flushPaletteCache(); + ide.categories.refreshEmpty(); ide.refreshPalette(); ide.recordUnsavedChanges(); } @@ -2554,6 +2555,7 @@ BlockEditorMorph.prototype.updateDefinition = function () { this.refreshAllBlockInstances(oldSpec); ide = this.target.parentThatIsA(IDE_Morph); ide.flushPaletteCache(); + ide.categories.refreshEmpty(); ide.refreshPalette(); ide.recordUnsavedChanges(); }; @@ -4389,6 +4391,7 @@ BlockImportDialogMorph.prototype.importBlocks = function (name) { ide.stage.replaceDoubleDefinitionsFor(def); }); ide.flushPaletteCache(); + ide.categories.refreshEmpty(); ide.refreshPalette(); ide.showMessage( 'Imported Blocks Module' + (name ? ': ' + name : '') + '.', @@ -4480,6 +4483,7 @@ BlockRemovalDialogMorph.prototype.removeBlocks = function () { } }); ide.flushPaletteCache(); + ide.categories.refreshEmpty(); ide.refreshPalette(); ide.showMessage( this.blocks.length + ' ' + localize('unused block(s) removed'), diff --git a/src/gui.js b/src/gui.js index d9dfee0b..a13b125e 100644 --- a/src/gui.js +++ b/src/gui.js @@ -86,7 +86,7 @@ BlockVisibilityDialogMorph, ThreadManager*/ // Global stuff //////////////////////////////////////////////////////// -modules.gui = '2021-November-18'; +modules.gui = '2021-November-19'; // Declarations @@ -1310,6 +1310,18 @@ IDE_Morph.prototype.createCategories = function () { }); }; + this.categories.refreshEmpty = function () { + var dict = myself.currentSprite.emptyCategories(); + dict.variables = dict.variables || dict.lists || dict.other; + this.buttons.forEach(cat => { + if (dict[cat.category]) { + cat.enable(); + } else { + cat.disable(); + } + }); + }; + function changePalette(category) { return () => { myself.currentCategory = category; @@ -1353,6 +1365,7 @@ IDE_Morph.prototype.createCategories = function () { true // has preview ); + button.category = category; button.corner = 8; button.padding = 0; button.labelShadowOffset = new Point(-1, -1); @@ -1389,6 +1402,7 @@ IDE_Morph.prototype.createCategories = function () { true // has preview ); + button.category = category; button.corner = 8; button.padding = 0; button.labelShadowOffset = new Point(-1, -1); @@ -2818,7 +2832,7 @@ IDE_Morph.prototype.stopAllScripts = function () { this.stage.fireStopAllEvent(); }; -IDE_Morph.prototype.selectSprite = function (sprite) { +IDE_Morph.prototype.selectSprite = function (sprite, noEmptyRefresh) { // prevent switching to another sprite if a block editor or a block // visibility dialog box is open // so local blocks of different sprites don't mix @@ -2837,6 +2851,9 @@ IDE_Morph.prototype.selectSprite = function (sprite) { } this.currentSprite = sprite; this.scene.currentSprite = sprite; + if (!noEmptyRefresh) { + this.categories.refreshEmpty(); + } this.createPalette(); this.createSpriteBar(); this.createSpriteEditor(); @@ -4717,7 +4734,7 @@ IDE_Morph.prototype.aboutSnap = function () { module, btn1, btn2, btn3, btn4, licenseBtn, translatorsBtn, world = this.world(); - aboutTxt = 'Snap! 7 - dev211118 -\nBuild Your Own Blocks\n\n' + aboutTxt = 'Snap! 7 - dev211119 -\nBuild Your Own Blocks\n\n' + 'Copyright \u24B8 2008-2021 Jens M\u00F6nig and ' + 'Brian Harvey\n' + 'jens@moenig.org, bh@cs.berkeley.edu\n\n' @@ -5010,6 +5027,7 @@ IDE_Morph.prototype.addPaletteCategory = function (name, color) { if (name === '') {return; } SpriteMorph.prototype.customCategories.set(name, color); this.createCategories(); + this.categories.refreshEmpty(); this.createPaletteHandle(); this.categories.fixLayout(); this.fixLayout(); @@ -5068,6 +5086,7 @@ IDE_Morph.prototype.deletePaletteCategory = function (name) { this.categories.fixLayout(); this.flushPaletteCache(); this.refreshPalette(true); + this.categories.refreshEmpty(); this.fixLayout(); this.recordUnsavedChanges(); }; @@ -5653,6 +5672,7 @@ IDE_Morph.prototype.rawOpenBlocksString = function (str, name, silently) { new BlockImportDialogMorph(blocks, this.stage, name).popUp(); } this.createCategories(); + this.categories.refreshEmpty(); this.createPaletteHandle(); this.categories.fixLayout(); this.fixLayout(); @@ -5843,7 +5863,7 @@ IDE_Morph.prototype.switchToScene = function ( this.stage.pauseGenericHatBlocks(); } this.createCorral(!refreshAlbum); // keep scenes - this.selectSprite(this.scene.currentSprite); + this.selectSprite(this.scene.currentSprite, true); this.corral.album.updateSelection(); this.fixLayout(); this.corral.album.contents.children.forEach(function (morph) { @@ -5858,6 +5878,7 @@ IDE_Morph.prototype.switchToScene = function ( this.categories.fixLayout(); this.fixLayout(); this.flushBlocksCache(); + this.categories.refreshEmpty(); this.currentSprite.palette(this.currentCategory); this.refreshPalette(true); } @@ -6057,6 +6078,12 @@ IDE_Morph.prototype.flushPaletteCache = function (category) { } }); } + this.stage.categoriesCache = null; + this.stage.children.forEach(m => { + if (m instanceof SpriteMorph) { + m.categoriesCache = null; + } + }); }; IDE_Morph.prototype.toggleZebraColoring = function () { @@ -6297,6 +6324,7 @@ IDE_Morph.prototype.toggleStageSize = function (isSmall, forcedRatio) { IDE_Morph.prototype.toggleUnifiedPalette = function () { this.setUnifiedPalette(!this.scene.unifiedPalette); + this.recordUnsavedChanges(); }; IDE_Morph.prototype.setUnifiedPalette = function (bool) { @@ -6314,9 +6342,9 @@ IDE_Morph.prototype.setUnifiedPalette = function (bool) { this.categories.fixLayout(); this.fixLayout(); this.flushBlocksCache(); + this.categories.refreshEmpty(); this.currentSprite.palette(this.currentCategory); this.refreshPalette(true); - this.recordUnsavedChanges(); return true; }; @@ -6504,6 +6532,7 @@ IDE_Morph.prototype.reflectLanguage = function (lang, callback, noSave) { SpriteMorph.prototype.initBlocks(); this.spriteBar.tabBar.tabTo('scripts'); this.createCategories(); + this.categories.refreshEmpty(); this.createCorralBar(); this.fixLayout(); if (this.loadNewProject) { @@ -6618,6 +6647,7 @@ IDE_Morph.prototype.setBlocksScale = function (num) { SpriteMorph.prototype.initBlocks(); this.spriteBar.tabBar.tabTo('scripts'); this.createCategories(); + this.categories.refreshEmpty(); this.createCorralBar(); this.fixLayout(); this.openProjectString(projectData); diff --git a/src/objects.js b/src/objects.js index 54085d8d..99ebb83f 100644 --- a/src/objects.js +++ b/src/objects.js @@ -87,7 +87,7 @@ BlockVisibilityDialogMorph*/ /*jshint esversion: 6*/ -modules.objects = '2021-November-15'; +modules.objects = '2021-November-19'; var SpriteMorph; var StageMorph; @@ -1870,6 +1870,7 @@ SpriteMorph.prototype.init = function (globals) { this.primitivesCache = {}; // not to be serialized (!) this.paletteCache = {}; // not to be serialized (!) + this.categoriesCache = null; // not to be serialized (!) this.rotationOffset = ZERO; // not to be serialized (!) this.idx = 0; // not to be serialized (!) - used for de-serialization @@ -1935,6 +1936,7 @@ SpriteMorph.prototype.fullCopy = function (forClone) { c.freqPlayer = null; c.primitivesCache = {}; c.paletteCache = {}; + c.categoriesCache = {}; c.imageData = {}; c.cachedColorDimensions = c.color[this.penColorModel](); arr = []; @@ -2957,6 +2959,7 @@ SpriteMorph.prototype.makeBlock = function () { this.customBlocks.push(definition); } ide.flushPaletteCache(); + ide.categories.refreshEmpty(); ide.refreshPalette(); ide.recordUnsavedChanges(); new BlockEditorMorph(definition, this).popUp(); @@ -3171,7 +3174,7 @@ SpriteMorph.prototype.freshPalette = function (category) { // SpriteMorph utilities for showing & hiding blocks in the palette SpriteMorph.prototype.allPaletteBlocks = function () { - // private - only to be used for showing & hiding blocks im the palette + // private - only to be used for showing & hiding blocks in the palette var blocks = SpriteMorph.prototype.allCategories().reduce( (blocks, category) => { let primitives = this.blockTemplates(category, true), @@ -3259,6 +3262,21 @@ SpriteMorph.prototype.changeBlockVisibility = function (aBlock, hideIt, quick) { ide.refreshPalette(); }; +SpriteMorph.prototype.emptyCategories = function () { + // return a dictionary that indicates for each category whether + // it has any shown blocks in it (true) or is empty (false) + var hasBlocks = (any) => any instanceof BlockMorph && + !this.isHidingBlock(any); + if (this.categoriesCache === null) { + this.categoriesCache = {}; + SpriteMorph.prototype.allCategories().forEach(category => + this.categoriesCache[category] = + this.getPrimitiveTemplates(category).some(hasBlocks) || + this.customBlockTemplatesForCategory(category).some(hasBlocks)); + } + return this.categoriesCache; +}; + // SpriteMorph blocks searching SpriteMorph.prototype.blocksMatching = function ( @@ -7772,6 +7790,7 @@ StageMorph.prototype.init = function (globals) { this.keysPressed = {}; // for handling keyboard events, do not persist this.primitivesCache = {}; // not to be serialized (!) this.paletteCache = {}; // not to be serialized (!) + this.categoriesCache = null; // not to be serialized (!) this.lastAnswer = ''; // last user input, do not persist this.activeSounds = []; // do not persist @@ -9343,6 +9362,9 @@ StageMorph.prototype.changeCustomBlockVisibility StageMorph.prototype.changeVarBlockVisibility = SpriteMorph.prototype.changeVarBlockVisibility; +StageMorph.prototype.emptyCategories = + SpriteMorph.prototype.emptyCategories; + // StageMorph neighbor detection StageMorph.prototype.neighbors = SpriteMorph.prototype.neighbors; diff --git a/sw.js b/sw.js index 4b1398a2..cee2f850 100644 --- a/sw.js +++ b/sw.js @@ -1,4 +1,4 @@ -var snapVersion = '7-dev211118' +var snapVersion = '7-dev211119' var cacheName = 'snap-pwa', filesToCache = [