From 129f99e5e2a9604f07b39399297312a989815222 Mon Sep 17 00:00:00 2001 From: Mike Harvey Date: Mon, 13 May 2024 17:17:40 -0400 Subject: [PATCH 1/5] feat: support fixed field height, custom colors, hidden buttons, custom button text --- plugins/field-bitmap/README.md | 9 ++- plugins/field-bitmap/src/field-bitmap.ts | 91 ++++++++++++++++++------ plugins/field-bitmap/test/index.js | 36 ++++++++++ 3 files changed, 112 insertions(+), 24 deletions(-) diff --git a/plugins/field-bitmap/README.md b/plugins/field-bitmap/README.md index c425b9faf3..26b2318538 100644 --- a/plugins/field-bitmap/README.md +++ b/plugins/field-bitmap/README.md @@ -20,7 +20,7 @@ npm install @blockly/field-bitmap --save ## Usage -This field accepts up to 3 parameters: +This field accepts up to 6 parameters: - `"value"` to specify an initial value. Must be a 2D rectangular array of 1s and 0s. If not provided, the default is an empty grid of the specified size. @@ -28,6 +28,13 @@ This field accepts up to 3 parameters: If not provided, the default is a width of 5. - `"height"` to specify an initial height, if there is no initial value. If not provided, the default is a height of 5. +- `fieldHeight"` to specify a static field height. If provided, the individual pixels + will be resized to fit inside the field. Good for larger images. +- `"colors"` to override the default colors, Default values: + `{filled: '#363d80', empty: '#fff'}` +- `"buttons"` to provide translated string for buttons, or to hide buttons. + Default values: + `{showRandomize: true, showClear: true, randomizeLabel: 'Randomize', clearLabel: 'Clear',}` ### JavaScript diff --git a/plugins/field-bitmap/src/field-bitmap.ts b/plugins/field-bitmap/src/field-bitmap.ts index 3819a0aa4b..e1190ab105 100644 --- a/plugins/field-bitmap/src/field-bitmap.ts +++ b/plugins/field-bitmap/src/field-bitmap.ts @@ -8,10 +8,17 @@ import * as Blockly from 'blockly/core'; export const DEFAULT_HEIGHT = 5; export const DEFAULT_WIDTH = 5; -const PIXEL_SIZE = 15; -const FILLED_PIXEL_COLOR = '#363d80'; -const EMPTY_PIXEL_COLOR = '#fff'; - +const DEFAULT_PIXEL_SIZE = 15; +const DEFAULT_PIXEL_COLORS: PixelColors = { + empty: '#fff', + filled: '#363d80', +}; +const DEFAULT_BUTTON_OPTIONS: ButtonOptions = { + showRandomize: true, + showClear: true, + randomizeLabel: 'Randomize', + clearLabel: 'Clear', +}; /** * Field for inputting a small bitmap image. * Includes a grid of clickable pixels that's exported as a bitmap. @@ -31,6 +38,9 @@ export class FieldBitmap extends Blockly.Field { /** Stateful variables */ private mouseIsDown = false; private valToPaintWith?: number; + buttonOptions: ButtonOptions; + pixelSize: number; + pixelColors: {empty: string; filled: string}; /** * Constructor for the bitmap field. @@ -48,6 +58,8 @@ export class FieldBitmap extends Blockly.Field { this.SERIALIZABLE = true; this.CURSOR = 'default'; + this.buttonOptions = {...DEFAULT_BUTTON_OPTIONS, ...config?.buttons}; + this.pixelColors = {...DEFAULT_PIXEL_COLORS, ...config?.colors}; // Configure value, height, and width const currentValue = this.getValue(); @@ -60,6 +72,11 @@ export class FieldBitmap extends Blockly.Field { // Set a default empty value this.setValue(this.getEmptyArray()); } + if (config?.fieldHeight) { + this.pixelSize = config.fieldHeight / this.imgHeight; + } else { + this.pixelSize = DEFAULT_PIXEL_SIZE; + } } /** @@ -186,13 +203,13 @@ export class FieldBitmap extends Blockly.Field { if (this.blockDisplayPixels) { this.blockDisplayPixels[r][c].style.fill = pixel - ? FILLED_PIXEL_COLOR - : EMPTY_PIXEL_COLOR; + ? this.pixelColors.filled + : this.pixelColors.empty; } if (this.editorPixels) { this.editorPixels[r][c].style.background = pixel - ? FILLED_PIXEL_COLOR - : EMPTY_PIXEL_COLOR; + ? this.pixelColors.filled + : this.pixelColors.empty; } }); } @@ -268,7 +285,9 @@ export class FieldBitmap extends Blockly.Field { // Load the current pixel color const isOn = this.getPixel(r, c); - button.style.background = isOn ? FILLED_PIXEL_COLOR : EMPTY_PIXEL_COLOR; + button.style.background = isOn + ? this.pixelColors.filled + : this.pixelColors.empty; // Handle clicking a pixel this.bindEvent(button, 'mousedown', () => { @@ -285,16 +304,28 @@ export class FieldBitmap extends Blockly.Field { } // Add control buttons below the pixel grid - this.addControlButton(dropdownEditor, 'Randomize', this.randomizePixels); - this.addControlButton(dropdownEditor, 'Clear', this.clearPixels); + if (this.buttonOptions.showRandomize) { + this.addControlButton( + dropdownEditor, + this.buttonOptions.randomizeLabel, + this.randomizePixels, + ); + } + if (this.buttonOptions.showClear) { + this.addControlButton( + dropdownEditor, + this.buttonOptions.clearLabel, + this.clearPixels, + ); + } if (this.blockDisplayPixels) { this.forAllCells((r, c) => { const pixel = this.getPixel(r, c); if (this.editorPixels) { this.editorPixels[r][c].style.background = pixel - ? FILLED_PIXEL_COLOR - : EMPTY_PIXEL_COLOR; + ? this.pixelColors.filled + : this.pixelColors.empty; } }); } @@ -316,11 +347,11 @@ export class FieldBitmap extends Blockly.Field { const square = Blockly.utils.dom.createSvgElement( 'rect', { - x: c * PIXEL_SIZE, - y: r * PIXEL_SIZE, - width: PIXEL_SIZE, - height: PIXEL_SIZE, - fill: EMPTY_PIXEL_COLOR, + x: c * this.pixelSize, + y: r * this.pixelSize, + width: this.pixelSize, + height: this.pixelSize, + fill: this.pixelColors.empty, fill_opacity: 1, // eslint-disable-line }, this.getSvgRoot(), @@ -337,8 +368,8 @@ export class FieldBitmap extends Blockly.Field { // eslint-disable-next-line protected override updateSize_() { { - const newWidth = PIXEL_SIZE * this.imgWidth; - const newHeight = PIXEL_SIZE * this.imgHeight; + const newWidth = this.pixelSize * this.imgWidth; + const newHeight = this.pixelSize * this.imgHeight; if (this.borderRect_) { this.borderRect_.setAttribute('width', String(newWidth)); this.borderRect_.setAttribute('height', String(newHeight)); @@ -552,10 +583,24 @@ export class FieldBitmap extends Blockly.Field { } } +interface ButtonOptions { + readonly showRandomize: boolean; + readonly showClear: boolean; + readonly randomizeLabel: string; + readonly clearLabel: string; +} +interface PixelColors { + readonly empty: string; + readonly filled: string; +} + export interface FieldBitmapFromJsonConfig extends Blockly.FieldConfig { value?: number[][]; width?: number; height?: number; + buttons?: ButtonOptions; + fieldHeight?: number; + colors?: PixelColors; } Blockly.fieldRegistry.register('field_bitmap', FieldBitmap); @@ -579,11 +624,11 @@ Blockly.Css.register(` flex-direction: row; padding: 0; margin: 0; - height: ${PIXEL_SIZE} + height: ${DEFAULT_PIXEL_SIZE} } .pixelButton { - width: ${PIXEL_SIZE}px; - height: ${PIXEL_SIZE}px; + width: ${DEFAULT_PIXEL_SIZE}px; + height: ${DEFAULT_PIXEL_SIZE}px; border: 1px solid #000; } .pixelDisplay { diff --git a/plugins/field-bitmap/test/index.js b/plugins/field-bitmap/test/index.js index cf15532be0..40d8d75458 100644 --- a/plugins/field-bitmap/test/index.js +++ b/plugins/field-bitmap/test/index.js @@ -36,6 +36,42 @@ const toolbox = generateFieldTestBlocks('field_bitmap', [ value: undefined, }, }, + { + label: 'Static field height, custom colors, no buttons', + args: { + value: [ + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0], + [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0], + [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0], + [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0], + [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0], + [0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0], + [0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0], + [0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0], + [0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0], + [0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0], + [0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0], + [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0], + [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0], + [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0], + [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0], + [0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0], + [0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + ], + fieldHeight: 50, + buttons: { + showRandomize: false, + showClear: false, + }, + colors: { + filled: '#4888f4', + empty: '#cad2dc', + }, + }, + }, ]); /** From 872bd89c5ec2a42f77c084c815d19b261bf9d27f Mon Sep 17 00:00:00 2001 From: Mike Harvey Date: Tue, 14 May 2024 07:59:29 -0400 Subject: [PATCH 2/5] fix: use existing Blockly.Msg system for translations --- plugins/field-bitmap/README.md | 4 ++-- plugins/field-bitmap/src/field-bitmap.ts | 11 +++++------ 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/plugins/field-bitmap/README.md b/plugins/field-bitmap/README.md index 26b2318538..12052a3b12 100644 --- a/plugins/field-bitmap/README.md +++ b/plugins/field-bitmap/README.md @@ -32,9 +32,9 @@ This field accepts up to 6 parameters: will be resized to fit inside the field. Good for larger images. - `"colors"` to override the default colors, Default values: `{filled: '#363d80', empty: '#fff'}` -- `"buttons"` to provide translated string for buttons, or to hide buttons. +- `"buttons"` to hide the "Randomize" and/or "Clear" buttons. Default values: - `{showRandomize: true, showClear: true, randomizeLabel: 'Randomize', clearLabel: 'Clear',}` + `{showRandomize: true, showClear: true}` ### JavaScript diff --git a/plugins/field-bitmap/src/field-bitmap.ts b/plugins/field-bitmap/src/field-bitmap.ts index e1190ab105..c064fcce6d 100644 --- a/plugins/field-bitmap/src/field-bitmap.ts +++ b/plugins/field-bitmap/src/field-bitmap.ts @@ -6,6 +6,9 @@ import * as Blockly from 'blockly/core'; +Blockly.Msg['BUTTON_LABEL_RANDOMIZE'] = 'Randomize'; +Blockly.Msg['BUTTON_LABEL_CLEAR'] = 'Clear'; + export const DEFAULT_HEIGHT = 5; export const DEFAULT_WIDTH = 5; const DEFAULT_PIXEL_SIZE = 15; @@ -16,8 +19,6 @@ const DEFAULT_PIXEL_COLORS: PixelColors = { const DEFAULT_BUTTON_OPTIONS: ButtonOptions = { showRandomize: true, showClear: true, - randomizeLabel: 'Randomize', - clearLabel: 'Clear', }; /** * Field for inputting a small bitmap image. @@ -307,14 +308,14 @@ export class FieldBitmap extends Blockly.Field { if (this.buttonOptions.showRandomize) { this.addControlButton( dropdownEditor, - this.buttonOptions.randomizeLabel, + Blockly.Msg['BUTTON_LABEL_RANDOMIZE'], this.randomizePixels, ); } if (this.buttonOptions.showClear) { this.addControlButton( dropdownEditor, - this.buttonOptions.clearLabel, + Blockly.Msg['BUTTON_LABEL_CLEAR'], this.clearPixels, ); } @@ -586,8 +587,6 @@ export class FieldBitmap extends Blockly.Field { interface ButtonOptions { readonly showRandomize: boolean; readonly showClear: boolean; - readonly randomizeLabel: string; - readonly clearLabel: string; } interface PixelColors { readonly empty: string; From fbb797e2242982de8d4c6773870644a46c4d09d3 Mon Sep 17 00:00:00 2001 From: Mike Harvey Date: Tue, 14 May 2024 15:13:18 -0400 Subject: [PATCH 3/5] fix: code review feedback --- plugins/field-bitmap/README.md | 13 +++--- plugins/field-bitmap/src/field-bitmap.ts | 52 ++++++++++++------------ plugins/field-bitmap/test/index.js | 6 +-- 3 files changed, 37 insertions(+), 34 deletions(-) diff --git a/plugins/field-bitmap/README.md b/plugins/field-bitmap/README.md index 12052a3b12..e6a05201c4 100644 --- a/plugins/field-bitmap/README.md +++ b/plugins/field-bitmap/README.md @@ -29,12 +29,15 @@ This field accepts up to 6 parameters: - `"height"` to specify an initial height, if there is no initial value. If not provided, the default is a height of 5. - `fieldHeight"` to specify a static field height. If provided, the individual pixels - will be resized to fit inside the field. Good for larger images. -- `"colors"` to override the default colors, Default values: + will be resized to fit inside the field. This only affects the field as it is + scene on a block and not the pop-up editor. Good for larger images. (_Note: If this + results in fractional pixel sizes, the overall field height may not exactly match + the specified value on all browsers._) +- `"colours"` to override the default colours, Default values: `{filled: '#363d80', empty: '#fff'}` -- `"buttons"` to hide the "Randomize" and/or "Clear" buttons. - Default values: - `{showRandomize: true, showClear: true}` +- `"showButtons"` to show or hide the "Randomize" and/or "Clear" buttons. If either is + omitted, the button will be shown. Default values: + `{randomize: true, clear: true}` ### JavaScript diff --git a/plugins/field-bitmap/src/field-bitmap.ts b/plugins/field-bitmap/src/field-bitmap.ts index c064fcce6d..838e66d0db 100644 --- a/plugins/field-bitmap/src/field-bitmap.ts +++ b/plugins/field-bitmap/src/field-bitmap.ts @@ -12,13 +12,13 @@ Blockly.Msg['BUTTON_LABEL_CLEAR'] = 'Clear'; export const DEFAULT_HEIGHT = 5; export const DEFAULT_WIDTH = 5; const DEFAULT_PIXEL_SIZE = 15; -const DEFAULT_PIXEL_COLORS: PixelColors = { +const DEFAULT_PIXEL_COLOURS: PixelColours = { empty: '#fff', filled: '#363d80', }; -const DEFAULT_BUTTON_OPTIONS: ButtonOptions = { - showRandomize: true, - showClear: true, +const DEFAULT_BUTTONS: Buttons = { + randomize: true, + clear: true, }; /** * Field for inputting a small bitmap image. @@ -39,9 +39,9 @@ export class FieldBitmap extends Blockly.Field { /** Stateful variables */ private mouseIsDown = false; private valToPaintWith?: number; - buttonOptions: ButtonOptions; + buttonOptions: Buttons; pixelSize: number; - pixelColors: {empty: string; filled: string}; + pixelColours: {empty: string; filled: string}; /** * Constructor for the bitmap field. @@ -59,8 +59,8 @@ export class FieldBitmap extends Blockly.Field { this.SERIALIZABLE = true; this.CURSOR = 'default'; - this.buttonOptions = {...DEFAULT_BUTTON_OPTIONS, ...config?.buttons}; - this.pixelColors = {...DEFAULT_PIXEL_COLORS, ...config?.colors}; + this.buttonOptions = {...DEFAULT_BUTTONS, ...config?.buttons}; + this.pixelColours = {...DEFAULT_PIXEL_COLOURS, ...config?.colours}; // Configure value, height, and width const currentValue = this.getValue(); @@ -204,13 +204,13 @@ export class FieldBitmap extends Blockly.Field { if (this.blockDisplayPixels) { this.blockDisplayPixels[r][c].style.fill = pixel - ? this.pixelColors.filled - : this.pixelColors.empty; + ? this.pixelColours.filled + : this.pixelColours.empty; } if (this.editorPixels) { this.editorPixels[r][c].style.background = pixel - ? this.pixelColors.filled - : this.pixelColors.empty; + ? this.pixelColours.filled + : this.pixelColours.empty; } }); } @@ -284,11 +284,11 @@ export class FieldBitmap extends Blockly.Field { this.editorPixels[r].push(button); rowDiv.appendChild(button); - // Load the current pixel color + // Load the current pixel colour const isOn = this.getPixel(r, c); button.style.background = isOn - ? this.pixelColors.filled - : this.pixelColors.empty; + ? this.pixelColours.filled + : this.pixelColours.empty; // Handle clicking a pixel this.bindEvent(button, 'mousedown', () => { @@ -305,14 +305,14 @@ export class FieldBitmap extends Blockly.Field { } // Add control buttons below the pixel grid - if (this.buttonOptions.showRandomize) { + if (this.buttonOptions.randomize) { this.addControlButton( dropdownEditor, Blockly.Msg['BUTTON_LABEL_RANDOMIZE'], this.randomizePixels, ); } - if (this.buttonOptions.showClear) { + if (this.buttonOptions.clear) { this.addControlButton( dropdownEditor, Blockly.Msg['BUTTON_LABEL_CLEAR'], @@ -325,8 +325,8 @@ export class FieldBitmap extends Blockly.Field { const pixel = this.getPixel(r, c); if (this.editorPixels) { this.editorPixels[r][c].style.background = pixel - ? this.pixelColors.filled - : this.pixelColors.empty; + ? this.pixelColours.filled + : this.pixelColours.empty; } }); } @@ -352,7 +352,7 @@ export class FieldBitmap extends Blockly.Field { y: r * this.pixelSize, width: this.pixelSize, height: this.pixelSize, - fill: this.pixelColors.empty, + fill: this.pixelColours.empty, fill_opacity: 1, // eslint-disable-line }, this.getSvgRoot(), @@ -584,11 +584,11 @@ export class FieldBitmap extends Blockly.Field { } } -interface ButtonOptions { - readonly showRandomize: boolean; - readonly showClear: boolean; +interface Buttons { + readonly randomize: boolean; + readonly clear: boolean; } -interface PixelColors { +interface PixelColours { readonly empty: string; readonly filled: string; } @@ -597,9 +597,9 @@ export interface FieldBitmapFromJsonConfig extends Blockly.FieldConfig { value?: number[][]; width?: number; height?: number; - buttons?: ButtonOptions; + buttons?: Buttons; fieldHeight?: number; - colors?: PixelColors; + colours?: PixelColours; } Blockly.fieldRegistry.register('field_bitmap', FieldBitmap); diff --git a/plugins/field-bitmap/test/index.js b/plugins/field-bitmap/test/index.js index 40d8d75458..9967b95fc1 100644 --- a/plugins/field-bitmap/test/index.js +++ b/plugins/field-bitmap/test/index.js @@ -63,10 +63,10 @@ const toolbox = generateFieldTestBlocks('field_bitmap', [ ], fieldHeight: 50, buttons: { - showRandomize: false, - showClear: false, + randomize: false, + clear: false, }, - colors: { + colours: { filled: '#4888f4', empty: '#cad2dc', }, From 6c8a28735523df7f2994fee26272d1463c9e4132 Mon Sep 17 00:00:00 2001 From: Mike Harvey <43474485+mikeharv@users.noreply.github.com> Date: Wed, 15 May 2024 09:26:10 -0400 Subject: [PATCH 4/5] Update plugins/field-bitmap/README.md fix: typo in documentation Co-authored-by: Christopher Allen --- plugins/field-bitmap/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/field-bitmap/README.md b/plugins/field-bitmap/README.md index e6a05201c4..d219f45be7 100644 --- a/plugins/field-bitmap/README.md +++ b/plugins/field-bitmap/README.md @@ -30,7 +30,7 @@ This field accepts up to 6 parameters: If not provided, the default is a height of 5. - `fieldHeight"` to specify a static field height. If provided, the individual pixels will be resized to fit inside the field. This only affects the field as it is - scene on a block and not the pop-up editor. Good for larger images. (_Note: If this + seen on a block and not the pop-up editor. Good for larger images. (_Note: If this results in fractional pixel sizes, the overall field height may not exactly match the specified value on all browsers._) - `"colours"` to override the default colours, Default values: From b438d282ea1d58ec6cfcd7c67c4db70991d81ed7 Mon Sep 17 00:00:00 2001 From: Mike Harvey <43474485+mikeharv@users.noreply.github.com> Date: Wed, 15 May 2024 09:26:53 -0400 Subject: [PATCH 5/5] Update plugins/field-bitmap/README.md fix: update property name in documentation Co-authored-by: Christopher Allen --- plugins/field-bitmap/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/field-bitmap/README.md b/plugins/field-bitmap/README.md index d219f45be7..3b8cee4efd 100644 --- a/plugins/field-bitmap/README.md +++ b/plugins/field-bitmap/README.md @@ -35,7 +35,7 @@ This field accepts up to 6 parameters: the specified value on all browsers._) - `"colours"` to override the default colours, Default values: `{filled: '#363d80', empty: '#fff'}` -- `"showButtons"` to show or hide the "Randomize" and/or "Clear" buttons. If either is +- `"buttons"` to show or hide the "Randomize" and/or "Clear" buttons. If either is omitted, the button will be shown. Default values: `{randomize: true, clear: true}`