scratch-blocks 2.0.1 → 2.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +140 -0
- package/commitlint.config.js +2 -2
- package/dist/main.mjs +1 -2
- package/dist/types/msg/scratch_msgs.d.ts.map +1 -1
- package/dist/types/src/block_reporting.d.ts.map +1 -1
- package/dist/types/src/blocks/colour.d.ts +0 -19
- package/dist/types/src/blocks/colour.d.ts.map +1 -1
- package/dist/types/src/blocks/control.d.ts +0 -19
- package/dist/types/src/blocks/control.d.ts.map +1 -1
- package/dist/types/src/blocks/data.d.ts +0 -19
- package/dist/types/src/blocks/data.d.ts.map +1 -1
- package/dist/types/src/blocks/event.d.ts +0 -19
- package/dist/types/src/blocks/event.d.ts.map +1 -1
- package/dist/types/src/blocks/looks.d.ts +0 -19
- package/dist/types/src/blocks/looks.d.ts.map +1 -1
- package/dist/types/src/blocks/math.d.ts +0 -19
- package/dist/types/src/blocks/math.d.ts.map +1 -1
- package/dist/types/src/blocks/matrix.d.ts +0 -19
- package/dist/types/src/blocks/matrix.d.ts.map +1 -1
- package/dist/types/src/blocks/motion.d.ts +0 -19
- package/dist/types/src/blocks/motion.d.ts.map +1 -1
- package/dist/types/src/blocks/note.d.ts +0 -19
- package/dist/types/src/blocks/note.d.ts.map +1 -1
- package/dist/types/src/blocks/operators.d.ts +0 -19
- package/dist/types/src/blocks/operators.d.ts.map +1 -1
- package/dist/types/src/blocks/procedures.d.ts +6 -9
- package/dist/types/src/blocks/procedures.d.ts.map +1 -1
- package/dist/types/src/blocks/sensing.d.ts +0 -19
- package/dist/types/src/blocks/sensing.d.ts.map +1 -1
- package/dist/types/src/blocks/sound.d.ts +0 -19
- package/dist/types/src/blocks/sound.d.ts.map +1 -1
- package/dist/types/src/blocks/text.d.ts +0 -19
- package/dist/types/src/blocks/text.d.ts.map +1 -1
- package/dist/types/src/blocks/vertical_extensions.d.ts +0 -19
- package/dist/types/src/blocks/vertical_extensions.d.ts.map +1 -1
- package/dist/types/src/checkable_continuous_flyout.d.ts +2 -7
- package/dist/types/src/checkable_continuous_flyout.d.ts.map +1 -1
- package/dist/types/src/checkbox_bubble.d.ts +13 -12
- package/dist/types/src/checkbox_bubble.d.ts.map +1 -1
- package/dist/types/src/colours.d.ts.map +1 -1
- package/dist/types/src/constants.d.ts +0 -7
- package/dist/types/src/constants.d.ts.map +1 -1
- package/dist/types/src/context_menu_items.d.ts +0 -5
- package/dist/types/src/context_menu_items.d.ts.map +1 -1
- package/dist/types/src/data_category.d.ts +2 -4
- package/dist/types/src/data_category.d.ts.map +1 -1
- package/dist/types/src/events/events_block_comment_base.d.ts +2 -3
- package/dist/types/src/events/events_block_comment_base.d.ts.map +1 -1
- package/dist/types/src/events/events_block_comment_change.d.ts +0 -5
- package/dist/types/src/events/events_block_comment_change.d.ts.map +1 -1
- package/dist/types/src/events/events_block_comment_collapse.d.ts +0 -5
- package/dist/types/src/events/events_block_comment_collapse.d.ts.map +1 -1
- package/dist/types/src/events/events_block_comment_create.d.ts +0 -5
- package/dist/types/src/events/events_block_comment_create.d.ts.map +1 -1
- package/dist/types/src/events/events_block_comment_delete.d.ts +0 -5
- package/dist/types/src/events/events_block_comment_delete.d.ts.map +1 -1
- package/dist/types/src/events/events_block_comment_move.d.ts +0 -5
- package/dist/types/src/events/events_block_comment_move.d.ts.map +1 -1
- package/dist/types/src/events/events_block_comment_resize.d.ts +0 -5
- package/dist/types/src/events/events_block_comment_resize.d.ts.map +1 -1
- package/dist/types/src/events/events_block_drag_end.d.ts +1 -2
- package/dist/types/src/events/events_block_drag_end.d.ts.map +1 -1
- package/dist/types/src/events/events_block_drag_outside.d.ts +1 -2
- package/dist/types/src/events/events_block_drag_outside.d.ts.map +1 -1
- package/dist/types/src/events/events_scratch_variable_create.d.ts +0 -5
- package/dist/types/src/events/events_scratch_variable_create.d.ts.map +1 -1
- package/dist/types/src/fields/field_colour_slider.d.ts +7 -31
- package/dist/types/src/fields/field_colour_slider.d.ts.map +1 -1
- package/dist/types/src/fields/field_matrix.d.ts +0 -19
- package/dist/types/src/fields/field_matrix.d.ts.map +1 -1
- package/dist/types/src/fields/field_note.d.ts +8 -23
- package/dist/types/src/fields/field_note.d.ts.map +1 -1
- package/dist/types/src/fields/field_textinput_removable.d.ts +2 -4
- package/dist/types/src/fields/field_textinput_removable.d.ts.map +1 -1
- package/dist/types/src/fields/field_variable_getter.d.ts +0 -19
- package/dist/types/src/fields/field_variable_getter.d.ts.map +1 -1
- package/dist/types/src/fields/field_vertical_separator.d.ts +0 -19
- package/dist/types/src/fields/field_vertical_separator.d.ts.map +1 -1
- package/dist/types/src/fields/scratch_field_angle.d.ts +0 -19
- package/dist/types/src/fields/scratch_field_angle.d.ts.map +1 -1
- package/dist/types/src/fields/scratch_field_dropdown.d.ts +0 -5
- package/dist/types/src/fields/scratch_field_dropdown.d.ts.map +1 -1
- package/dist/types/src/fields/scratch_field_number.d.ts +0 -19
- package/dist/types/src/fields/scratch_field_number.d.ts.map +1 -1
- package/dist/types/src/fields/scratch_field_variable.d.ts +5 -8
- package/dist/types/src/fields/scratch_field_variable.d.ts.map +1 -1
- package/dist/types/src/flyout_checkbox_icon.d.ts +2 -3
- package/dist/types/src/flyout_checkbox_icon.d.ts.map +1 -1
- package/dist/types/src/glows.d.ts +1 -3
- package/dist/types/src/glows.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +50 -51
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/procedures.d.ts +6 -8
- package/dist/types/src/procedures.d.ts.map +1 -1
- package/dist/types/src/recyclable_block_flyout_inflater.d.ts +3 -5
- package/dist/types/src/recyclable_block_flyout_inflater.d.ts.map +1 -1
- package/dist/types/src/renderer/bowler_hat.d.ts +2 -3
- package/dist/types/src/renderer/bowler_hat.d.ts.map +1 -1
- package/dist/types/src/renderer/cat/cat_face.d.ts +6 -5
- package/dist/types/src/renderer/cat/cat_face.d.ts.map +1 -1
- package/dist/types/src/renderer/cat/constants.d.ts +2 -2
- package/dist/types/src/renderer/cat/constants.d.ts.map +1 -1
- package/dist/types/src/renderer/cat/drawer.d.ts +4 -5
- package/dist/types/src/renderer/cat/drawer.d.ts.map +1 -1
- package/dist/types/src/renderer/cat/path_object.d.ts +2 -3
- package/dist/types/src/renderer/cat/path_object.d.ts.map +1 -1
- package/dist/types/src/renderer/cat/render_info.d.ts +3 -4
- package/dist/types/src/renderer/cat/render_info.d.ts.map +1 -1
- package/dist/types/src/renderer/cat/renderer.d.ts +7 -8
- package/dist/types/src/renderer/cat/renderer.d.ts.map +1 -1
- package/dist/types/src/renderer/constants.d.ts +41 -0
- package/dist/types/src/renderer/constants.d.ts.map +1 -0
- package/dist/types/src/renderer/drawer.d.ts +7 -6
- package/dist/types/src/renderer/drawer.d.ts.map +1 -1
- package/dist/types/src/renderer/path_object.d.ts +1 -3
- package/dist/types/src/renderer/path_object.d.ts.map +1 -1
- package/dist/types/src/renderer/render_info.d.ts +3 -4
- package/dist/types/src/renderer/render_info.d.ts.map +1 -1
- package/dist/types/src/renderer/renderer.d.ts +9 -16
- package/dist/types/src/renderer/renderer.d.ts.map +1 -1
- package/dist/types/src/scratch_block_paster.d.ts +0 -5
- package/dist/types/src/scratch_block_paster.d.ts.map +1 -1
- package/dist/types/src/scratch_blocks_utils.d.ts +0 -20
- package/dist/types/src/scratch_blocks_utils.d.ts.map +1 -1
- package/dist/types/src/scratch_comment_bubble.d.ts +3 -6
- package/dist/types/src/scratch_comment_bubble.d.ts.map +1 -1
- package/dist/types/src/scratch_comment_icon.d.ts +3 -4
- package/dist/types/src/scratch_comment_icon.d.ts.map +1 -1
- package/dist/types/src/scratch_connection_checker.d.ts +0 -5
- package/dist/types/src/scratch_connection_checker.d.ts.map +1 -1
- package/dist/types/src/scratch_continuous_category.d.ts +5 -5
- package/dist/types/src/scratch_continuous_category.d.ts.map +1 -1
- package/dist/types/src/scratch_continuous_toolbox.d.ts +3 -6
- package/dist/types/src/scratch_continuous_toolbox.d.ts.map +1 -1
- package/dist/types/src/scratch_dragger.d.ts +2 -11
- package/dist/types/src/scratch_dragger.d.ts.map +1 -1
- package/dist/types/src/scratch_insertion_marker_previewer.d.ts +0 -5
- package/dist/types/src/scratch_insertion_marker_previewer.d.ts.map +1 -1
- package/dist/types/src/scratch_variable_map.d.ts +0 -5
- package/dist/types/src/scratch_variable_map.d.ts.map +1 -1
- package/dist/types/src/scratch_variable_model.d.ts +2 -3
- package/dist/types/src/scratch_variable_model.d.ts.map +1 -1
- package/dist/types/src/scratch_zoom_controls.d.ts +4 -6
- package/dist/types/src/scratch_zoom_controls.d.ts.map +1 -1
- package/dist/types/src/shadows.d.ts +2 -2
- package/dist/types/src/shadows.d.ts.map +1 -1
- package/dist/types/src/status_indicator_label.d.ts +4 -6
- package/dist/types/src/status_indicator_label.d.ts.map +1 -1
- package/dist/types/src/status_indicator_label_flyout_inflater.d.ts +1 -6
- package/dist/types/src/status_indicator_label_flyout_inflater.d.ts.map +1 -1
- package/dist/types/src/variables.d.ts +4 -8
- package/dist/types/src/variables.d.ts.map +1 -1
- package/dist/types/src/xml.d.ts +2 -3
- package/dist/types/src/xml.d.ts.map +1 -1
- package/dist/types/tests/jsunit/block_test.d.ts.map +1 -1
- package/dist/types/tests/jsunit/connection_db_test.d.ts +3 -3
- package/dist/types/tests/jsunit/connection_db_test.d.ts.map +1 -1
- package/dist/types/tests/jsunit/connection_test.d.ts.map +1 -1
- package/dist/types/tests/jsunit/event_test.d.ts.map +1 -1
- package/dist/types/tests/jsunit/extensions_test.d.ts.map +1 -1
- package/dist/types/tests/jsunit/field_number_test.d.ts.map +1 -1
- package/dist/types/tests/jsunit/field_test.d.ts.map +1 -1
- package/dist/types/tests/jsunit/field_variable_getter_test.d.ts.map +1 -1
- package/dist/types/tests/jsunit/field_variable_test.d.ts.map +1 -1
- package/dist/types/tests/jsunit/gesture_test.d.ts.map +1 -1
- package/dist/types/tests/jsunit/input_test.d.ts +1 -0
- package/dist/types/tests/jsunit/input_test.d.ts.map +1 -1
- package/dist/types/tests/jsunit/json_test.d.ts.map +1 -1
- package/dist/types/tests/jsunit/names_test.d.ts.map +1 -1
- package/dist/types/tests/jsunit/procedure_test.d.ts.map +1 -1
- package/dist/types/tests/jsunit/scratch_block_comment_test.d.ts.map +1 -1
- package/dist/types/tests/jsunit/svg_test.d.ts.map +1 -1
- package/dist/types/tests/jsunit/test_utilities.d.ts.map +1 -1
- package/dist/types/tests/jsunit/utils_test.d.ts.map +1 -1
- package/dist/types/tests/jsunit/variable_map_test.d.ts.map +1 -1
- package/dist/types/tests/jsunit/variable_model_test.d.ts.map +1 -1
- package/dist/types/tests/jsunit/widget_div_test.d.ts.map +1 -1
- package/dist/types/tests/jsunit/workspace_comment_test.d.ts.map +1 -1
- package/dist/types/tests/jsunit/workspace_test.d.ts.map +1 -1
- package/dist/types/tests/jsunit/workspace_undo_redo_test.d.ts.map +1 -1
- package/dist/types/tests/jsunit/xml_test.d.ts.map +1 -1
- package/dist/types/tests/workspace_svg/workspace_svg_test.d.ts.map +1 -1
- package/eslint.config.mjs +69 -0
- package/i18n/create_scratch_msgs.js +44 -45
- package/i18n/js_to_json.js +40 -32
- package/i18n/json_to_js.js +37 -37
- package/i18n/sync_tx_translations.js +64 -65
- package/i18n/test_scratch_msgs.js +66 -63
- package/msg/js/en.js +289 -287
- package/msg/json/en.json +284 -284
- package/msg/messages.js +289 -287
- package/msg/scratch_msgs.js +22959 -22970
- package/package.json +13 -10
- package/prettier.config.mjs +3 -0
- package/release.config.js +7 -7
- package/renovate.json5 +7 -9
- package/src/block_reporting.ts +16 -19
- package/src/blocks/colour.ts +12 -15
- package/src/blocks/control.ts +171 -174
- package/src/blocks/data.ts +233 -272
- package/src/blocks/event.ts +121 -123
- package/src/blocks/looks.ts +165 -167
- package/src/blocks/math.ts +44 -46
- package/src/blocks/matrix.ts +11 -13
- package/src/blocks/motion.ts +151 -153
- package/src/blocks/note.ts +11 -13
- package/src/blocks/operators.ts +158 -160
- package/src/blocks/procedures.ts +421 -511
- package/src/blocks/sensing.ts +163 -165
- package/src/blocks/sound.ts +58 -60
- package/src/blocks/text.ts +10 -12
- package/src/blocks/vertical_extensions.ts +86 -102
- package/src/checkable_continuous_flyout.ts +25 -42
- package/src/checkbox_bubble.ts +83 -100
- package/src/colours.ts +35 -37
- package/src/constants.ts +22 -29
- package/src/context_menu_items.ts +59 -84
- package/src/css.ts +3 -4
- package/src/data_category.ts +137 -251
- package/src/events/events_block_comment_base.ts +23 -30
- package/src/events/events_block_comment_change.ts +21 -42
- package/src/events/events_block_comment_collapse.ts +27 -36
- package/src/events/events_block_comment_create.ts +32 -46
- package/src/events/events_block_comment_delete.ts +12 -19
- package/src/events/events_block_comment_move.ts +27 -52
- package/src/events/events_block_comment_resize.ts +28 -55
- package/src/events/events_block_drag_end.ts +16 -26
- package/src/events/events_block_drag_outside.ts +12 -22
- package/src/events/events_scratch_variable_create.ts +37 -42
- package/src/fields/field_colour_slider.ts +186 -216
- package/src/fields/field_matrix.ts +202 -270
- package/src/fields/field_note.ts +277 -375
- package/src/fields/field_textinput_removable.ts +25 -40
- package/src/fields/field_variable_getter.ts +26 -31
- package/src/fields/field_vertical_separator.ts +19 -24
- package/src/fields/scratch_field_angle.ts +151 -187
- package/src/fields/scratch_field_dropdown.ts +15 -19
- package/src/fields/scratch_field_number.ts +125 -181
- package/src/fields/scratch_field_variable.ts +57 -75
- package/src/flyout_checkbox_icon.ts +18 -28
- package/src/glows.ts +52 -59
- package/src/index.ts +119 -133
- package/src/procedures.ts +150 -209
- package/src/recyclable_block_flyout_inflater.ts +14 -25
- package/src/renderer/bowler_hat.ts +6 -8
- package/src/renderer/cat/cat_face.ts +98 -99
- package/src/renderer/cat/constants.ts +67 -87
- package/src/renderer/cat/drawer.ts +21 -27
- package/src/renderer/cat/path_object.ts +3 -5
- package/src/renderer/cat/render_info.ts +5 -8
- package/src/renderer/cat/renderer.ts +12 -16
- package/src/renderer/constants.ts +34 -49
- package/src/renderer/drawer.ts +35 -51
- package/src/renderer/path_object.ts +4 -10
- package/src/renderer/render_info.ts +39 -56
- package/src/renderer/renderer.ts +17 -30
- package/src/scratch_block_paster.ts +12 -20
- package/src/scratch_blocks_utils.ts +4 -7
- package/src/scratch_comment_bubble.ts +76 -105
- package/src/scratch_comment_icon.ts +75 -124
- package/src/scratch_connection_checker.ts +7 -17
- package/src/scratch_continuous_category.ts +24 -28
- package/src/scratch_continuous_toolbox.ts +20 -27
- package/src/scratch_dragger.ts +42 -81
- package/src/scratch_insertion_marker_previewer.ts +6 -11
- package/src/scratch_variable_map.ts +5 -12
- package/src/scratch_variable_model.ts +6 -13
- package/src/scratch_zoom_controls.ts +101 -156
- package/src/shadows.ts +32 -37
- package/src/status_indicator_label.ts +54 -67
- package/src/status_indicator_label_flyout_inflater.ts +11 -21
- package/src/variables.ts +92 -141
- package/src/xml.ts +21 -35
- package/tsconfig.json +3 -7
- package/types/continuous-toolbox.d.ts +1 -1
- package/dist/main.mjs.LICENSE.txt +0 -163
|
@@ -1,18 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @license
|
|
3
2
|
* Copyright 2024 Google LLC
|
|
4
3
|
* SPDX-License-Identifier: Apache-2.0
|
|
5
4
|
*/
|
|
6
|
-
|
|
7
|
-
import
|
|
8
|
-
import { ConstantProvider } from "./constants";
|
|
5
|
+
import * as Blockly from 'blockly/core'
|
|
6
|
+
import { ConstantProvider } from './constants'
|
|
9
7
|
|
|
10
8
|
export class BowlerHat extends Blockly.blockRendering.Hat {
|
|
11
9
|
constructor(constants: ConstantProvider) {
|
|
12
|
-
super(constants)
|
|
10
|
+
super(constants)
|
|
13
11
|
// Calculated dynamically by computeBounds_().
|
|
14
|
-
this.width = 0
|
|
15
|
-
this.height = constants.BOWLER_HAT_HEIGHT
|
|
16
|
-
this.ascenderHeight = this.height
|
|
12
|
+
this.width = 0
|
|
13
|
+
this.height = constants.BOWLER_HAT_HEIGHT
|
|
14
|
+
this.ascenderHeight = this.height
|
|
17
15
|
}
|
|
18
16
|
}
|
|
@@ -1,16 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @license
|
|
3
2
|
* Copyright 2026 Scratch Foundation
|
|
4
3
|
* SPDX-License-Identifier: Apache-2.0
|
|
5
4
|
*/
|
|
5
|
+
import * as Blockly from 'blockly/core'
|
|
6
|
+
import { type ConstantProvider, type CatPathState, PathCapType, PathEarState } from './constants'
|
|
7
|
+
import { type RenderInfo } from './render_info'
|
|
8
|
+
import { type CatScratchRenderer } from './renderer'
|
|
6
9
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
import { type ConstantProvider, type CatPathState, PathCapType, PathEarState } from "./constants";
|
|
10
|
-
import { type CatScratchRenderer } from "./renderer";
|
|
11
|
-
import { type RenderInfo } from "./render_info";
|
|
12
|
-
|
|
13
|
-
const Svg = Blockly.utils.Svg;
|
|
10
|
+
const Svg = Blockly.utils.Svg
|
|
14
11
|
|
|
15
12
|
enum FacePart {
|
|
16
13
|
MOUTH,
|
|
@@ -24,11 +21,11 @@ enum FacePart {
|
|
|
24
21
|
|
|
25
22
|
const setVisibility = (element: SVGElement, visible: boolean) => {
|
|
26
23
|
if (visible) {
|
|
27
|
-
element.style.removeProperty(
|
|
24
|
+
element.style.removeProperty('visibility')
|
|
28
25
|
} else {
|
|
29
|
-
element.style.setProperty(
|
|
26
|
+
element.style.setProperty('visibility', 'hidden')
|
|
30
27
|
}
|
|
31
|
-
}
|
|
28
|
+
}
|
|
32
29
|
|
|
33
30
|
/**
|
|
34
31
|
* Manages the SVG elements for the cat face.
|
|
@@ -36,65 +33,67 @@ const setVisibility = (element: SVGElement, visible: boolean) => {
|
|
|
36
33
|
* Owned by the PathObject with similar lifetime.
|
|
37
34
|
*/
|
|
38
35
|
export class CatFace {
|
|
39
|
-
faceGroup_
|
|
40
|
-
parts_ = {} as Record<FacePart, SVGElement
|
|
41
|
-
pathEarState: CatPathState
|
|
42
|
-
constants_: ConstantProvider
|
|
43
|
-
renderer_: CatScratchRenderer
|
|
44
|
-
block_: Blockly.BlockSvg
|
|
36
|
+
faceGroup_!: SVGElement
|
|
37
|
+
parts_ = {} as Record<FacePart, SVGElement>
|
|
38
|
+
pathEarState: CatPathState
|
|
39
|
+
constants_: ConstantProvider
|
|
40
|
+
renderer_: CatScratchRenderer
|
|
41
|
+
block_: Blockly.BlockSvg
|
|
45
42
|
|
|
46
43
|
constructor(info: RenderInfo) {
|
|
47
|
-
this.constants_ = info.constants_
|
|
48
|
-
this.renderer_ = info.renderer_
|
|
49
|
-
this.block_ = info.block_
|
|
44
|
+
this.constants_ = info.constants_
|
|
45
|
+
this.renderer_ = info.renderer_
|
|
46
|
+
this.block_ = info.block_
|
|
50
47
|
this.pathEarState = {
|
|
51
48
|
capType: info.isBowlerHatBlock() ? PathCapType.BOWLER : PathCapType.CAP,
|
|
52
49
|
ear1State: PathEarState.UP,
|
|
53
50
|
ear2State: PathEarState.UP,
|
|
54
|
-
}
|
|
51
|
+
}
|
|
55
52
|
}
|
|
56
53
|
|
|
57
54
|
/**
|
|
58
55
|
* Initializes the face SVG elements if they haven't been created yet.
|
|
56
|
+
* @param parent The SVG element to attach the face geometry to.
|
|
59
57
|
*/
|
|
60
58
|
init(parent: SVGElement) {
|
|
61
|
-
if (this.faceGroup_) return
|
|
62
|
-
this.buildFaceGeometry_(parent)
|
|
63
|
-
this.setupBlinking_()
|
|
64
|
-
this.setupEarFlicks_()
|
|
59
|
+
if (this.faceGroup_) return
|
|
60
|
+
this.buildFaceGeometry_(parent)
|
|
61
|
+
this.setupBlinking_()
|
|
62
|
+
this.setupEarFlicks_()
|
|
65
63
|
}
|
|
66
64
|
|
|
67
65
|
/**
|
|
68
66
|
* Updates the transform of the entire face group.
|
|
67
|
+
* @param transform The SVG transform attribute value to apply.
|
|
69
68
|
*/
|
|
70
69
|
setTransform(transform: string) {
|
|
71
70
|
if (this.faceGroup_) {
|
|
72
|
-
this.faceGroup_.setAttribute(
|
|
71
|
+
this.faceGroup_.setAttribute('transform', transform)
|
|
73
72
|
}
|
|
74
73
|
}
|
|
75
74
|
|
|
76
75
|
private setupBlinking_() {
|
|
77
|
-
const blinkDuration = 100
|
|
78
|
-
let ignoreBlink = false
|
|
76
|
+
const blinkDuration = 100
|
|
77
|
+
let ignoreBlink = false
|
|
79
78
|
|
|
80
79
|
// TODO: Would it be better to use CSS for this?
|
|
81
|
-
Blockly.browserEvents.bind(this.block_.pathObject.svgPath,
|
|
82
|
-
if (ignoreBlink) return
|
|
83
|
-
ignoreBlink = true
|
|
84
|
-
setVisibility(this.parts_[FacePart.EYE_1_OPEN], false)
|
|
85
|
-
setVisibility(this.parts_[FacePart.EYE_2_OPEN], false)
|
|
86
|
-
setVisibility(this.parts_[FacePart.EYE_1_CLOSED], true)
|
|
87
|
-
setVisibility(this.parts_[FacePart.EYE_2_CLOSED], true)
|
|
80
|
+
Blockly.browserEvents.bind(this.block_.pathObject.svgPath, 'mouseenter', this, () => {
|
|
81
|
+
if (ignoreBlink) return
|
|
82
|
+
ignoreBlink = true
|
|
83
|
+
setVisibility(this.parts_[FacePart.EYE_1_OPEN], false)
|
|
84
|
+
setVisibility(this.parts_[FacePart.EYE_2_OPEN], false)
|
|
85
|
+
setVisibility(this.parts_[FacePart.EYE_1_CLOSED], true)
|
|
86
|
+
setVisibility(this.parts_[FacePart.EYE_2_CLOSED], true)
|
|
88
87
|
setTimeout(() => {
|
|
89
|
-
setVisibility(this.parts_[FacePart.EYE_1_OPEN], true)
|
|
90
|
-
setVisibility(this.parts_[FacePart.EYE_2_OPEN], true)
|
|
91
|
-
setVisibility(this.parts_[FacePart.EYE_1_CLOSED], false)
|
|
92
|
-
setVisibility(this.parts_[FacePart.EYE_2_CLOSED], false)
|
|
93
|
-
}, blinkDuration)
|
|
88
|
+
setVisibility(this.parts_[FacePart.EYE_1_OPEN], true)
|
|
89
|
+
setVisibility(this.parts_[FacePart.EYE_2_OPEN], true)
|
|
90
|
+
setVisibility(this.parts_[FacePart.EYE_1_CLOSED], false)
|
|
91
|
+
setVisibility(this.parts_[FacePart.EYE_2_CLOSED], false)
|
|
92
|
+
}, blinkDuration)
|
|
94
93
|
setTimeout(() => {
|
|
95
|
-
ignoreBlink = false
|
|
96
|
-
}, 2 * blinkDuration)
|
|
97
|
-
})
|
|
94
|
+
ignoreBlink = false
|
|
95
|
+
}, 2 * blinkDuration)
|
|
96
|
+
})
|
|
98
97
|
}
|
|
99
98
|
|
|
100
99
|
/**
|
|
@@ -103,65 +102,65 @@ export class CatFace {
|
|
|
103
102
|
* Not necessary for face changes (blinking).
|
|
104
103
|
*/
|
|
105
104
|
private triggerRedraw() {
|
|
106
|
-
this.renderer_.render(this.block_)
|
|
105
|
+
this.renderer_.render(this.block_)
|
|
107
106
|
}
|
|
108
107
|
|
|
109
108
|
private setupEarFlicks_() {
|
|
110
|
-
const flickDuration = 50
|
|
111
|
-
let ignoreFlick1 = false
|
|
112
|
-
let ignoreFlick2 = false
|
|
113
|
-
|
|
114
|
-
Blockly.browserEvents.bind(this.parts_[FacePart.EAR_1_INSIDE],
|
|
115
|
-
if (ignoreFlick1) return
|
|
116
|
-
ignoreFlick1 = true
|
|
117
|
-
setVisibility(this.parts_[FacePart.EAR_1_INSIDE], false)
|
|
118
|
-
this.pathEarState.ear1State = PathEarState.DOWN
|
|
119
|
-
this.triggerRedraw()
|
|
109
|
+
const flickDuration = 50
|
|
110
|
+
let ignoreFlick1 = false
|
|
111
|
+
let ignoreFlick2 = false
|
|
112
|
+
|
|
113
|
+
Blockly.browserEvents.bind(this.parts_[FacePart.EAR_1_INSIDE], 'mouseenter', this, () => {
|
|
114
|
+
if (ignoreFlick1) return
|
|
115
|
+
ignoreFlick1 = true
|
|
116
|
+
setVisibility(this.parts_[FacePart.EAR_1_INSIDE], false)
|
|
117
|
+
this.pathEarState.ear1State = PathEarState.DOWN
|
|
118
|
+
this.triggerRedraw()
|
|
120
119
|
setTimeout(() => {
|
|
121
|
-
setVisibility(this.parts_[FacePart.EAR_1_INSIDE], true)
|
|
122
|
-
this.pathEarState.ear1State = PathEarState.UP
|
|
123
|
-
this.triggerRedraw()
|
|
124
|
-
}, flickDuration)
|
|
120
|
+
setVisibility(this.parts_[FacePart.EAR_1_INSIDE], true)
|
|
121
|
+
this.pathEarState.ear1State = PathEarState.UP
|
|
122
|
+
this.triggerRedraw()
|
|
123
|
+
}, flickDuration)
|
|
125
124
|
setTimeout(() => {
|
|
126
|
-
ignoreFlick1 = false
|
|
127
|
-
}, 2 * flickDuration)
|
|
128
|
-
})
|
|
129
|
-
Blockly.browserEvents.bind(this.parts_[FacePart.EAR_2_INSIDE],
|
|
130
|
-
if (ignoreFlick2) return
|
|
131
|
-
ignoreFlick2 = true
|
|
132
|
-
setVisibility(this.parts_[FacePart.EAR_2_INSIDE], false)
|
|
133
|
-
this.pathEarState.ear2State = PathEarState.DOWN
|
|
134
|
-
this.triggerRedraw()
|
|
125
|
+
ignoreFlick1 = false
|
|
126
|
+
}, 2 * flickDuration)
|
|
127
|
+
})
|
|
128
|
+
Blockly.browserEvents.bind(this.parts_[FacePart.EAR_2_INSIDE], 'mouseenter', this, () => {
|
|
129
|
+
if (ignoreFlick2) return
|
|
130
|
+
ignoreFlick2 = true
|
|
131
|
+
setVisibility(this.parts_[FacePart.EAR_2_INSIDE], false)
|
|
132
|
+
this.pathEarState.ear2State = PathEarState.DOWN
|
|
133
|
+
this.triggerRedraw()
|
|
135
134
|
setTimeout(() => {
|
|
136
|
-
setVisibility(this.parts_[FacePart.EAR_2_INSIDE], true)
|
|
137
|
-
this.pathEarState.ear2State = PathEarState.UP
|
|
138
|
-
this.triggerRedraw()
|
|
139
|
-
}, flickDuration)
|
|
135
|
+
setVisibility(this.parts_[FacePart.EAR_2_INSIDE], true)
|
|
136
|
+
this.pathEarState.ear2State = PathEarState.UP
|
|
137
|
+
this.triggerRedraw()
|
|
138
|
+
}, flickDuration)
|
|
140
139
|
setTimeout(() => {
|
|
141
|
-
ignoreFlick2 = false
|
|
142
|
-
}, 2 * flickDuration)
|
|
143
|
-
})
|
|
140
|
+
ignoreFlick2 = false
|
|
141
|
+
}, 2 * flickDuration)
|
|
142
|
+
})
|
|
144
143
|
}
|
|
145
144
|
|
|
146
145
|
private buildFaceGeometry_(parent: SVGElement) {
|
|
147
146
|
const face = Blockly.utils.dom.createSvgElement(
|
|
148
147
|
Svg.G,
|
|
149
148
|
{
|
|
150
|
-
fill:
|
|
149
|
+
fill: '#000000',
|
|
151
150
|
// transform set in setTransform()
|
|
152
151
|
},
|
|
153
|
-
parent
|
|
154
|
-
)
|
|
155
|
-
this.faceGroup_ = face
|
|
152
|
+
parent,
|
|
153
|
+
)
|
|
154
|
+
this.faceGroup_ = face
|
|
156
155
|
|
|
157
156
|
this.parts_[FacePart.MOUTH] = Blockly.utils.dom.createSvgElement(
|
|
158
157
|
Svg.PATH,
|
|
159
158
|
{
|
|
160
|
-
|
|
159
|
+
'fill-opacity': this.constants_.FACE_OPACITY,
|
|
161
160
|
d: this.constants_.MOUTH_PATH,
|
|
162
161
|
},
|
|
163
|
-
face
|
|
164
|
-
)
|
|
162
|
+
face,
|
|
163
|
+
)
|
|
165
164
|
|
|
166
165
|
this.parts_[FacePart.EAR_1_INSIDE] = Blockly.utils.dom.createSvgElement(
|
|
167
166
|
Svg.PATH,
|
|
@@ -169,8 +168,8 @@ export class CatFace {
|
|
|
169
168
|
fill: this.constants_.EAR_INSIDE_COLOR,
|
|
170
169
|
d: this.constants_.EAR_1_INSIDE_PATH,
|
|
171
170
|
},
|
|
172
|
-
face
|
|
173
|
-
)
|
|
171
|
+
face,
|
|
172
|
+
)
|
|
174
173
|
|
|
175
174
|
this.parts_[FacePart.EAR_2_INSIDE] = Blockly.utils.dom.createSvgElement(
|
|
176
175
|
Svg.PATH,
|
|
@@ -178,49 +177,49 @@ export class CatFace {
|
|
|
178
177
|
fill: this.constants_.EAR_INSIDE_COLOR,
|
|
179
178
|
d: this.constants_.EAR_2_INSIDE_PATH,
|
|
180
179
|
},
|
|
181
|
-
face
|
|
182
|
-
)
|
|
180
|
+
face,
|
|
181
|
+
)
|
|
183
182
|
|
|
184
183
|
this.parts_[FacePart.EYE_1_OPEN] = Blockly.utils.dom.createSvgElement(
|
|
185
184
|
Svg.CIRCLE,
|
|
186
185
|
{
|
|
187
|
-
|
|
186
|
+
'fill-opacity': this.constants_.FACE_OPACITY,
|
|
188
187
|
cx: this.constants_.EYE_1_X,
|
|
189
188
|
cy: this.constants_.EYE_1_Y,
|
|
190
189
|
r: this.constants_.OPEN_EYE_RADIUS,
|
|
191
190
|
},
|
|
192
|
-
face
|
|
193
|
-
)
|
|
191
|
+
face,
|
|
192
|
+
)
|
|
194
193
|
|
|
195
194
|
this.parts_[FacePart.EYE_1_CLOSED] = Blockly.utils.dom.createSvgElement(
|
|
196
195
|
Svg.PATH,
|
|
197
196
|
{
|
|
198
|
-
|
|
197
|
+
'fill-opacity': this.constants_.FACE_OPACITY,
|
|
199
198
|
d: this.constants_.CLOSED_EYE_1_PATH,
|
|
200
199
|
},
|
|
201
|
-
face
|
|
202
|
-
)
|
|
203
|
-
setVisibility(this.parts_[FacePart.EYE_1_CLOSED], false)
|
|
200
|
+
face,
|
|
201
|
+
)
|
|
202
|
+
setVisibility(this.parts_[FacePart.EYE_1_CLOSED], false)
|
|
204
203
|
|
|
205
204
|
this.parts_[FacePart.EYE_2_OPEN] = Blockly.utils.dom.createSvgElement(
|
|
206
205
|
Svg.CIRCLE,
|
|
207
206
|
{
|
|
208
|
-
|
|
207
|
+
'fill-opacity': this.constants_.FACE_OPACITY,
|
|
209
208
|
cx: this.constants_.EYE_2_X,
|
|
210
209
|
cy: this.constants_.EYE_2_Y,
|
|
211
210
|
r: this.constants_.OPEN_EYE_RADIUS,
|
|
212
211
|
},
|
|
213
|
-
face
|
|
214
|
-
)
|
|
212
|
+
face,
|
|
213
|
+
)
|
|
215
214
|
|
|
216
215
|
this.parts_[FacePart.EYE_2_CLOSED] = Blockly.utils.dom.createSvgElement(
|
|
217
216
|
Svg.PATH,
|
|
218
217
|
{
|
|
219
|
-
|
|
218
|
+
'fill-opacity': this.constants_.FACE_OPACITY,
|
|
220
219
|
d: this.constants_.CLOSED_EYE_2_PATH,
|
|
221
220
|
},
|
|
222
|
-
face
|
|
223
|
-
)
|
|
224
|
-
setVisibility(this.parts_[FacePart.EYE_2_CLOSED], false)
|
|
221
|
+
face,
|
|
222
|
+
)
|
|
223
|
+
setVisibility(this.parts_[FacePart.EYE_2_CLOSED], false)
|
|
225
224
|
}
|
|
226
225
|
}
|
|
@@ -1,112 +1,95 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @license
|
|
3
2
|
* Copyright 2026 Scratch Foundation
|
|
4
3
|
* SPDX-License-Identifier: Apache-2.0
|
|
5
4
|
*/
|
|
6
|
-
|
|
7
|
-
import { ConstantProvider as ClassicConstantProvider } from "../constants";
|
|
5
|
+
import { ConstantProvider as ClassicConstantProvider } from '../constants'
|
|
8
6
|
|
|
9
7
|
export enum PathCapType {
|
|
10
|
-
CAP =
|
|
11
|
-
BOWLER =
|
|
8
|
+
CAP = 'CAP',
|
|
9
|
+
BOWLER = 'BOWLER',
|
|
12
10
|
}
|
|
13
11
|
|
|
14
12
|
export enum PathEarState {
|
|
15
|
-
DOWN =
|
|
16
|
-
UP =
|
|
13
|
+
DOWN = 'DOWN',
|
|
14
|
+
UP = 'UP',
|
|
17
15
|
}
|
|
18
16
|
|
|
19
17
|
export interface CatPathState {
|
|
20
|
-
capType: PathCapType
|
|
21
|
-
ear1State: PathEarState
|
|
22
|
-
ear2State: PathEarState
|
|
18
|
+
capType: PathCapType
|
|
19
|
+
ear1State: PathEarState // Left ear in LTR, right in RTL
|
|
20
|
+
ear2State: PathEarState // Right ear in LTR, left in RTL
|
|
23
21
|
}
|
|
24
22
|
|
|
25
23
|
export class ConstantProvider extends ClassicConstantProvider {
|
|
26
|
-
START_HAT_HEIGHT = 31.5
|
|
27
|
-
START_HAT_WIDTH = 96
|
|
24
|
+
START_HAT_HEIGHT = 31.5
|
|
25
|
+
START_HAT_WIDTH = 96
|
|
28
26
|
|
|
29
|
-
BOWLER_HAT_HEIGHT = 35
|
|
27
|
+
BOWLER_HAT_HEIGHT = 35
|
|
30
28
|
|
|
31
|
-
FACE_OPACITY = 0.6
|
|
29
|
+
FACE_OPACITY = 0.6
|
|
32
30
|
|
|
33
|
-
EYE_1_X = 59.2
|
|
34
|
-
EYE_1_Y = -3.3
|
|
35
|
-
EYE_2_X = 29.1
|
|
36
|
-
EYE_2_Y = -3.3
|
|
37
|
-
OPEN_EYE_RADIUS = 3.4
|
|
31
|
+
EYE_1_X = 59.2
|
|
32
|
+
EYE_1_Y = -3.3
|
|
33
|
+
EYE_2_X = 29.1
|
|
34
|
+
EYE_2_Y = -3.3
|
|
35
|
+
OPEN_EYE_RADIUS = 3.4
|
|
38
36
|
CLOSED_EYE_1_PATH =
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
37
|
+
'M25.2-1.1c0.1,0,0.2,0,0.2,0l8.3-2.1l-7-4.8' +
|
|
38
|
+
'c-0.5-0.3-1.1-0.2-1.4,0.3s-0.2,1.1,0.3,1.4L29-4.1l-4,1' +
|
|
39
|
+
'c-0.5,0.1-0.9,0.7-0.7,1.2C24.3-1.4,24.7-1.1,25.2-1.1z'
|
|
42
40
|
CLOSED_EYE_2_PATH =
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
41
|
+
'M62.4-1.1c-0.1,0-0.2,0-0.2,0l-8.3-2.1l7-4.8' +
|
|
42
|
+
'c0.5-0.3,1.1-0.2,1.4,0.3s0.2,1.1-0.3,1.4l-3.4,2.3l4,1' +
|
|
43
|
+
'c0.5,0.1,0.9,0.7,0.7,1.2C63.2-1.4,62.8-1.1,62.4-1.1z'
|
|
46
44
|
|
|
47
45
|
MOUTH_PATH =
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
EAR_INSIDE_COLOR =
|
|
46
|
+
'M45.6,0.1c-0.9,0-1.7-0.3-2.3-0.9' +
|
|
47
|
+
'c-0.6,0.6-1.3,0.9-2.2,0.9c-0.9,0-1.8-0.3-2.3-0.9c-1-1.1-1.1-2.6-1.1-2.8' +
|
|
48
|
+
'c0-0.5,0.5-1,1-1l0,0c0.6,0,1,0.5,1,1c0,0.4,0.1,1.7,1.4,1.7' +
|
|
49
|
+
'c0.5,0,0.7-0.2,0.8-0.3c0.3-0.3,0.4-1,0.4-1.3c0-0.1,0-0.1,0-0.2' +
|
|
50
|
+
'c0-0.5,0.5-1,1-1l0,0c0.5,0,1,0.4,1,1c0,0,0,0.1,0,0.2' +
|
|
51
|
+
'c0,0.3,0.1,0.9,0.4,1.2C44.8-2.2,45-2,45.5-2s0.7-0.2,0.8-0.3' +
|
|
52
|
+
'c0.3-0.4,0.4-1.1,0.3-1.3c0-0.5,0.4-1,0.9-1.1c0.5,0,1,0.4,1.1,0.9' +
|
|
53
|
+
'c0,0.2,0.1,1.8-0.8,2.8C47.5-0.4,46.8,0.1,45.6,0.1z'
|
|
54
|
+
|
|
55
|
+
EAR_INSIDE_COLOR = '#FFD5E6'
|
|
58
56
|
EAR_1_INSIDE_PATH =
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
57
|
+
'M22.4-15.6c-1.7-4.2-4.5-9.1-5.8-8.5' +
|
|
58
|
+
'c-1.6,0.8-5.4,7.9-5,15.4c0,0.6,0.7,0.7,1.1,0.5c3-1.6,6.4-2.8,8.6-3.6' +
|
|
59
|
+
'C22.8-12.3,23.2-13.7,22.4-15.6z'
|
|
62
60
|
EAR_2_INSIDE_PATH =
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
CAP_START_PATH =
|
|
68
|
-
CAP_MIDDLE_PATH =
|
|
69
|
-
CAP_END_PATH =
|
|
70
|
-
|
|
71
|
-
CAP_EAR_1_UP_PATH =
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
BOWLER_MIDDLE_PATH = "h33";
|
|
82
|
-
BOWLER_END_PATH = "a 20,20 0 0,1 20,20";
|
|
83
|
-
BOWLER_EAR_1_UP_PATH =
|
|
84
|
-
"c0,-7.1 3.7,-13.3 9.3,-16.9" +
|
|
85
|
-
"c1.7,-7.5 5.4,-13.2 7.6,-14.2" +
|
|
86
|
-
"c2.6,-1.3 10,6 14.6,11.1";
|
|
87
|
-
BOWLER_EAR_2_UP_PATH =
|
|
88
|
-
"c4.6,-5.1 11.9,-12.4 14.6,-11.1" +
|
|
89
|
-
"c1.9,0.9 4.9,5.2 6.8,11.1" +
|
|
90
|
-
"h7.8";
|
|
61
|
+
'M73.1-15.6c1.7-4.2,4.5-9.1,5.8-8.5' +
|
|
62
|
+
'c1.6,0.8,5.4,7.9,5,15.4c0,0.6-0.7,0.7-1.1,0.5c-3-1.6-6.4-2.8-8.6-3.6' +
|
|
63
|
+
'C72.8-12.3,72.4-13.7,73.1-15.6z'
|
|
64
|
+
|
|
65
|
+
CAP_START_PATH = 'c2.6,-2.3 5.5,-4.3 8.5,-6.2'
|
|
66
|
+
CAP_MIDDLE_PATH = 'c8.4,-1.3 17,-1.3 25.4,0'
|
|
67
|
+
CAP_END_PATH = 'c3,1.8 5.9,3.9 8.5,6.1'
|
|
68
|
+
|
|
69
|
+
CAP_EAR_1_UP_PATH = 'c-1,-12.5 5.3,-23.3 8.4,-24.8' + 'c3.7,-1.8 16.5,13.1 18.4,15.4'
|
|
70
|
+
CAP_EAR_2_UP_PATH = 'c1.9,-2.3 14.7,-17.2 18.4,-15.4' + 'c3.1,1.5 9.4,12.3 8.4,24.8'
|
|
71
|
+
CAP_EAR_1_DOWN_PATH = 'c-5.8,-4.8 -8,-18 -4.9,-19.5' + 'c3.7,-1.8 24.5,11.1 31.7,10.1'
|
|
72
|
+
CAP_EAR_2_DOWN_PATH = 'c7.2,1 28,-11.9 31.7,-10.1' + 'c3.1,1.5 0.9,14.7 -4.9,19.5'
|
|
73
|
+
|
|
74
|
+
BOWLER_START_PATH = '' // opening curve depends on whether ear 1 is up or down
|
|
75
|
+
BOWLER_MIDDLE_PATH = 'h33'
|
|
76
|
+
BOWLER_END_PATH = 'a 20,20 0 0,1 20,20'
|
|
77
|
+
BOWLER_EAR_1_UP_PATH = 'c0,-7.1 3.7,-13.3 9.3,-16.9' + 'c1.7,-7.5 5.4,-13.2 7.6,-14.2' + 'c2.6,-1.3 10,6 14.6,11.1'
|
|
78
|
+
BOWLER_EAR_2_UP_PATH = 'c4.6,-5.1 11.9,-12.4 14.6,-11.1' + 'c1.9,0.9 4.9,5.2 6.8,11.1' + 'h7.8'
|
|
91
79
|
BOWLER_EAR_1_DOWN_PATH =
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
"c2.1,-1 9.6,2.6 17,5.8" +
|
|
95
|
-
"h10.9";
|
|
96
|
-
BOWLER_EAR_2_DOWN_PATH =
|
|
97
|
-
"h11" +
|
|
98
|
-
"c7.4,-3.2 14.8,-6.8 16.9,-5.8" +
|
|
99
|
-
"c1.2,0.6 1.6,2.9 1.3,5.8";
|
|
80
|
+
'c0,-4.6 1.6,-8.9 4.3,-12.3' + 'c-2.4,-5.6 -2.9,-12.4 -0.7,-13.4' + 'c2.1,-1 9.6,2.6 17,5.8' + 'h10.9'
|
|
81
|
+
BOWLER_EAR_2_DOWN_PATH = 'h11' + 'c7.4,-3.2 14.8,-6.8 16.9,-5.8' + 'c1.2,0.6 1.6,2.9 1.3,5.8'
|
|
100
82
|
|
|
101
83
|
// This number was determined experimentally:
|
|
102
84
|
// - The 17 came from zooming in on a "define" block and iterating to get a near-vertical edge.
|
|
103
85
|
// - The .7 came from measuring the width of the other parts of the SVG path.
|
|
104
|
-
BOWLER_WIDTH_MAGIC = 17.7
|
|
86
|
+
BOWLER_WIDTH_MAGIC = 17.7
|
|
105
87
|
|
|
106
88
|
/**
|
|
107
89
|
* Make the starting portion of a block's hat.
|
|
108
90
|
* The return value will be stored as START_HAT.
|
|
109
91
|
* In the case of cat blocks, this is just a placeholder for sizing.
|
|
92
|
+
* @returns An object containing the hat's height and width dimensions.
|
|
110
93
|
*/
|
|
111
94
|
override makeStartHat() {
|
|
112
95
|
return {
|
|
@@ -117,20 +100,17 @@ export class ConstantProvider extends ClassicConstantProvider {
|
|
|
117
100
|
ear1State: PathEarState.UP,
|
|
118
101
|
ear2State: PathEarState.UP,
|
|
119
102
|
}),
|
|
120
|
-
}
|
|
103
|
+
}
|
|
121
104
|
}
|
|
122
105
|
|
|
123
106
|
makeCatPath(width: number, state: CatPathState) {
|
|
124
|
-
const pathStart = this[`${state.capType}_START_PATH`]
|
|
125
|
-
const pathEar1 =
|
|
126
|
-
|
|
127
|
-
const
|
|
128
|
-
const
|
|
129
|
-
|
|
130
|
-
const
|
|
131
|
-
|
|
132
|
-
: ""; // caps don't need an internal spacer like bowlers do
|
|
133
|
-
const pathEnd = this[`${state.capType}_END_PATH`];
|
|
134
|
-
return `${pathStart}${pathEar1}${pathMiddle}${pathEar2}${spacer}${pathEnd}`;
|
|
107
|
+
const pathStart = this[`${state.capType}_START_PATH`]
|
|
108
|
+
const pathEar1 = this[`${state.capType}_EAR_1_${state.ear1State}_PATH`]
|
|
109
|
+
const pathMiddle = this[`${state.capType}_MIDDLE_PATH`]
|
|
110
|
+
const pathEar2 = this[`${state.capType}_EAR_2_${state.ear2State}_PATH`]
|
|
111
|
+
const spacer =
|
|
112
|
+
state.capType === PathCapType.BOWLER ? `l ${width - this.START_HAT_WIDTH - this.BOWLER_WIDTH_MAGIC} 0` : '' // caps don't need an internal spacer like bowlers do
|
|
113
|
+
const pathEnd = this[`${state.capType}_END_PATH`]
|
|
114
|
+
return `${pathStart}${pathEar1}${pathMiddle}${pathEar2}${spacer}${pathEnd}`
|
|
135
115
|
}
|
|
136
116
|
}
|
|
@@ -1,24 +1,21 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @license
|
|
3
2
|
* Copyright 2026 Scratch Foundation
|
|
4
3
|
* SPDX-License-Identifier: Apache-2.0
|
|
5
4
|
*/
|
|
6
|
-
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
import { type
|
|
10
|
-
import { type
|
|
11
|
-
import { type RenderInfo } from "./render_info";
|
|
12
|
-
import { CatFace } from "./cat_face";
|
|
5
|
+
import { Drawer as ClassicDrawer } from '../drawer'
|
|
6
|
+
import { CatFace } from './cat_face'
|
|
7
|
+
import { type ConstantProvider } from './constants'
|
|
8
|
+
import { type PathObject } from './path_object'
|
|
9
|
+
import { type RenderInfo } from './render_info'
|
|
13
10
|
|
|
14
11
|
export class Drawer extends ClassicDrawer {
|
|
15
|
-
constants_: ConstantProvider
|
|
16
|
-
info_: RenderInfo
|
|
12
|
+
declare constants_: ConstantProvider
|
|
13
|
+
declare info_: RenderInfo
|
|
17
14
|
|
|
18
15
|
override draw() {
|
|
19
16
|
// Make sure the face exists if we need it.
|
|
20
17
|
if (this.block_.hat) {
|
|
21
|
-
const pathObject = this.block_.pathObject as PathObject
|
|
18
|
+
const pathObject = this.block_.pathObject as PathObject
|
|
22
19
|
|
|
23
20
|
if (!pathObject.catFace) {
|
|
24
21
|
// Initialize the persistent face view.
|
|
@@ -26,38 +23,35 @@ export class Drawer extends ClassicDrawer {
|
|
|
26
23
|
// Drawer and RenderInfo only exist during `Renderer.render(block)`.
|
|
27
24
|
// Block, PathObject, and CatFace last for the lifetime of the block.
|
|
28
25
|
// ConstantsProvider and the Renderer last for the lifetime of the workspace.
|
|
29
|
-
pathObject.catFace = new CatFace(this.info_)
|
|
30
|
-
pathObject.catFace.init(this.block_.getSvgRoot())
|
|
26
|
+
pathObject.catFace = new CatFace(this.info_)
|
|
27
|
+
pathObject.catFace.init(this.block_.getSvgRoot())
|
|
31
28
|
}
|
|
32
29
|
}
|
|
33
30
|
|
|
34
|
-
super.draw()
|
|
31
|
+
super.draw()
|
|
35
32
|
}
|
|
36
33
|
|
|
37
34
|
override drawInternals_() {
|
|
38
|
-
super.drawInternals_()
|
|
35
|
+
super.drawInternals_()
|
|
39
36
|
|
|
40
|
-
const pathObject = this.block_.pathObject as PathObject
|
|
41
|
-
const catFace = pathObject.catFace
|
|
37
|
+
const pathObject = this.block_.pathObject as PathObject
|
|
38
|
+
const catFace = pathObject.catFace
|
|
42
39
|
if (catFace) {
|
|
43
40
|
// Update the transform for the whole group
|
|
44
|
-
const transformParts: string[] = []
|
|
41
|
+
const transformParts: string[] = []
|
|
45
42
|
if (this.info_.RTL) {
|
|
46
|
-
transformParts.push(
|
|
43
|
+
transformParts.push('scale(-1 1)')
|
|
47
44
|
}
|
|
48
|
-
transformParts.push(`translate(0, ${this.info_.startY})`)
|
|
49
|
-
catFace.setTransform(transformParts.join(
|
|
45
|
+
transformParts.push(`translate(0, ${this.info_.startY})`)
|
|
46
|
+
catFace.setTransform(transformParts.join(' '))
|
|
50
47
|
}
|
|
51
48
|
}
|
|
52
49
|
|
|
53
50
|
override makeReplacementTop_() {
|
|
54
51
|
if (!this.block_.hat) {
|
|
55
|
-
return super.makeReplacementTop_()
|
|
52
|
+
return super.makeReplacementTop_()
|
|
56
53
|
}
|
|
57
|
-
const pathObject = this.block_.pathObject as PathObject
|
|
58
|
-
return this.constants_.makeCatPath(
|
|
59
|
-
this.info_.width,
|
|
60
|
-
pathObject.catFace.pathEarState
|
|
61
|
-
);
|
|
54
|
+
const pathObject = this.block_.pathObject as PathObject
|
|
55
|
+
return this.constants_.makeCatPath(this.info_.width, pathObject.catFace!.pathEarState)
|
|
62
56
|
}
|
|
63
57
|
}
|
|
@@ -1,16 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @license
|
|
3
2
|
* Copyright 2026 Scratch Foundation
|
|
4
3
|
* SPDX-License-Identifier: Apache-2.0
|
|
5
4
|
*/
|
|
6
|
-
|
|
7
|
-
import {
|
|
8
|
-
import { type CatFace } from "./cat_face";
|
|
5
|
+
import { PathObject as ClassicPathObject } from '../path_object'
|
|
6
|
+
import { type CatFace } from './cat_face'
|
|
9
7
|
|
|
10
8
|
export class PathObject extends ClassicPathObject {
|
|
11
9
|
/**
|
|
12
10
|
* The face view for this block.
|
|
13
11
|
* Only valid if this block has a hat and therefore should have a face.
|
|
14
12
|
*/
|
|
15
|
-
catFace?: CatFace
|
|
13
|
+
catFace?: CatFace
|
|
16
14
|
}
|