├── tutorials ├── 1.md └── 2.md ├── media ├── 1x1.gif ├── click.mp3 ├── click.ogg ├── click.wav ├── save.png ├── delete.mp3 ├── delete.ogg ├── delete.png ├── delete.wav ├── pilcrow.png ├── quote0.png ├── quote1.png ├── sprites.png ├── upload.png ├── disconnect.mp3 ├── disconnect.ogg ├── disconnect.wav ├── download.png ├── handclosed.cur ├── handdelete.cur ├── handopen.cur ├── paia-logo.icns ├── paia-logo.ico ├── paia-logo.png ├── dropdown-arrow.svg ├── sprites.svg └── pingpong.svg ├── .gitmodules ├── .gitignore ├── requirements.txt ├── js ├── externs │ ├── goog-externs.js │ ├── generator-externs.js │ └── block-externs.js ├── msg │ └── json │ │ ├── constants.json │ │ └── synonyms.json ├── core │ ├── interfaces │ │ ├── i_registrable.js │ │ ├── i_movable.js │ │ ├── i_deletable.js │ │ ├── i_deletearea.js │ │ ├── i_bounded_element.js │ │ ├── i_styleable.js │ │ ├── i_copyable.js │ │ ├── i_selectable.js │ │ ├── i_accessibility.js │ │ └── i_toolbox.js │ ├── blocks.js │ ├── keyboard_nav │ │ ├── action.js │ │ ├── tab_navigate_cursor.js │ │ ├── flyout_cursor.js │ │ └── marker.js │ ├── msg.js │ ├── utils │ │ ├── global.js │ │ ├── idgenerator.js │ │ ├── size.js │ │ ├── rect.js │ │ ├── math.js │ │ ├── object.js │ │ ├── xml.js │ │ ├── metrics.js │ │ └── coordinate.js │ ├── theme │ │ ├── dark.js │ │ ├── classic.js │ │ ├── tritanopia.js │ │ ├── zelos.js │ │ ├── deuteranopia.js │ │ ├── modern.js │ │ └── highcontrast.js │ ├── renderers │ │ ├── minimalist │ │ │ ├── constants.js │ │ │ ├── drawer.js │ │ │ ├── info.js │ │ │ └── renderer.js │ │ ├── measurables │ │ │ └── base.js │ │ ├── zelos │ │ │ └── measurables │ │ │ │ ├── row_elements.js │ │ │ │ ├── inputs.js │ │ │ │ └── rows.js │ │ ├── thrasos │ │ │ └── renderer.js │ │ ├── geras │ │ │ ├── constants.js │ │ │ └── measurables │ │ │ │ └── inputs.js │ │ └── common │ │ │ └── block_rendering.js │ ├── workspace_events.js │ ├── ui_events.js │ ├── field_registry.js │ ├── flyout_dragger.js │ ├── field_label_serializable.js │ ├── events_abstract.js │ ├── workspace_dragger.js │ ├── variable_model.js │ └── requires.js ├── generators │ ├── lua │ │ ├── variables_dynamic.js │ │ ├── variables.js │ │ └── colour.js │ ├── php │ │ ├── variables_dynamic.js │ │ ├── variables.js │ │ └── colour.js │ ├── dart │ │ ├── variables_dynamic.js │ │ └── variables.js │ ├── python │ │ ├── variables_dynamic.js │ │ ├── plot.js │ │ ├── variables.js │ │ ├── ndarrays.js │ │ ├── dicts.js │ │ ├── file.js │ │ └── colour.js │ └── javascript │ │ ├── variables_dynamic.js │ │ └── variables.js ├── game_msg │ ├── template.js │ ├── easy_game.js │ ├── arkanoid.js │ ├── maze_car.js │ ├── racingcar.js │ └── pingpong.js ├── ui_msg │ ├── zh-hant.js │ └── en.js ├── mlgame │ ├── easy_game.json │ ├── arkanoid.json │ ├── maze_car.json │ ├── racingcar.json │ └── pingpong.json ├── blocks │ ├── plot.js │ ├── file.js │ └── colour.js └── i18n │ ├── tests.py │ └── dedup_json.py ├── xml └── blocks │ ├── arkanoid.xml │ ├── easy_game.xml │ ├── racingcar.xml │ ├── pingpong.xml │ └── maze_car.xml ├── preload.js ├── python ├── interpreter.py └── examples │ ├── arkanoid │ ├── 3. model_training.py │ ├── 4. model_playing.py │ ├── 1. start.py │ └── 2. manual.py │ ├── maze_car │ ├── 3. model_training.py │ ├── 4. model_playing.py │ ├── 1. start.py │ └── 2. manual.py │ ├── pingpong │ ├── 3. model_training.py │ ├── 4. model_playing.py │ ├── 1. start.py │ └── 2. manual.py │ ├── racingcar │ ├── 3. model_training.py │ ├── 4. model_playing.py │ ├── 1. start.py │ └── 2. manual.py │ └── easy_game │ └── 1. start.py ├── README.md ├── renderer.js ├── main.js └── package.json /tutorials/1.md: -------------------------------------------------------------------------------- 1 | # Tutorial 1 2 | 3 | ## Step 1 4 | 5 | ## Step 2 -------------------------------------------------------------------------------- /tutorials/2.md: -------------------------------------------------------------------------------- 1 | # Tutorial 2 2 | 3 | ## Step 1 4 | 5 | ## Step 2 -------------------------------------------------------------------------------- /media/1x1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jason53415/blockly-app/HEAD/media/1x1.gif -------------------------------------------------------------------------------- /media/click.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jason53415/blockly-app/HEAD/media/click.mp3 -------------------------------------------------------------------------------- /media/click.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jason53415/blockly-app/HEAD/media/click.ogg -------------------------------------------------------------------------------- /media/click.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jason53415/blockly-app/HEAD/media/click.wav -------------------------------------------------------------------------------- /media/save.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jason53415/blockly-app/HEAD/media/save.png -------------------------------------------------------------------------------- /media/delete.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jason53415/blockly-app/HEAD/media/delete.mp3 -------------------------------------------------------------------------------- /media/delete.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jason53415/blockly-app/HEAD/media/delete.ogg -------------------------------------------------------------------------------- /media/delete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jason53415/blockly-app/HEAD/media/delete.png -------------------------------------------------------------------------------- /media/delete.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jason53415/blockly-app/HEAD/media/delete.wav -------------------------------------------------------------------------------- /media/pilcrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jason53415/blockly-app/HEAD/media/pilcrow.png -------------------------------------------------------------------------------- /media/quote0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jason53415/blockly-app/HEAD/media/quote0.png -------------------------------------------------------------------------------- /media/quote1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jason53415/blockly-app/HEAD/media/quote1.png -------------------------------------------------------------------------------- /media/sprites.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jason53415/blockly-app/HEAD/media/sprites.png -------------------------------------------------------------------------------- /media/upload.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jason53415/blockly-app/HEAD/media/upload.png -------------------------------------------------------------------------------- /media/disconnect.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jason53415/blockly-app/HEAD/media/disconnect.mp3 -------------------------------------------------------------------------------- /media/disconnect.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jason53415/blockly-app/HEAD/media/disconnect.ogg -------------------------------------------------------------------------------- /media/disconnect.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jason53415/blockly-app/HEAD/media/disconnect.wav -------------------------------------------------------------------------------- /media/download.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jason53415/blockly-app/HEAD/media/download.png -------------------------------------------------------------------------------- /media/handclosed.cur: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jason53415/blockly-app/HEAD/media/handclosed.cur -------------------------------------------------------------------------------- /media/handdelete.cur: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jason53415/blockly-app/HEAD/media/handdelete.cur -------------------------------------------------------------------------------- /media/handopen.cur: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jason53415/blockly-app/HEAD/media/handopen.cur -------------------------------------------------------------------------------- /media/paia-logo.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jason53415/blockly-app/HEAD/media/paia-logo.icns -------------------------------------------------------------------------------- /media/paia-logo.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jason53415/blockly-app/HEAD/media/paia-logo.ico -------------------------------------------------------------------------------- /media/paia-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jason53415/blockly-app/HEAD/media/paia-logo.png -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "MLGame"] 2 | path = MLGame 3 | url = https://github.com/jason53415/MLGame.git 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules/ 2 | /out/ 3 | __pycache__/ 4 | /python/build/ 5 | /python/dist/ 6 | /python/*.spec 7 | /venv/ -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | box2d-py==2.3.8 2 | pygame==2.0.1 3 | pyinstaller==4.2 4 | scikit-learn==0.24.1 5 | matplotlib==3.3.4 6 | pynput==1.7.3 7 | -------------------------------------------------------------------------------- /js/externs/goog-externs.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2019 Google LLC 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | /** 8 | * @fileoverview Externs for goog. 9 | * @externs 10 | */ 11 | 12 | /** 13 | * @type {!Object} 14 | */ 15 | var goog = {}; 16 | -------------------------------------------------------------------------------- /xml/blocks/arkanoid.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /xml/blocks/easy_game.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /xml/blocks/racingcar.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /xml/blocks/pingpong.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /js/externs/generator-externs.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2020 Google LLC 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | /** 8 | * @fileoverview Externs for Blockly generators. 9 | * @externs 10 | */ 11 | 12 | goog.provide('Blockly'); 13 | goog.provide('Blockly.Generator'); 14 | goog.provide('Blockly.utils.global'); 15 | goog.provide('Blockly.utils.string'); 16 | 17 | var Blockly; 18 | -------------------------------------------------------------------------------- /js/msg/json/constants.json: -------------------------------------------------------------------------------- 1 | { 2 | "LOGIC_HUE": "100", 3 | "LOOPS_HUE": "140", 4 | "MATH_HUE": "170", 5 | "TEXTS_HUE": "190", 6 | "LISTS_HUE": "210", 7 | "DICTS_HUE": "230", 8 | "NDARRAY_HUE": "250", 9 | "MODEL_HUE": "270", 10 | "COLOUR_HUE": "20", 11 | "VARIABLES_HUE": "290", 12 | "VARIABLES_DYNAMIC_HUE": "300", 13 | "PROCEDURES_HUE": "310", 14 | "PLOT_HUE": "335", 15 | "FILE_HUE": "360", 16 | "MLGAME_HUE": "20" 17 | } -------------------------------------------------------------------------------- /preload.js: -------------------------------------------------------------------------------- 1 | // All of the Node.js APIs are available in the preload process. 2 | // It has the same sandbox as a Chrome extension. 3 | window.addEventListener('DOMContentLoaded', () => { 4 | const replaceText = (selector, text) => { 5 | const element = document.getElementById(selector) 6 | if (element) element.innerText = text 7 | } 8 | 9 | for (const type of ['chrome', 'node', 'electron']) { 10 | replaceText(`${type}-version`, process.versions[type]) 11 | } 12 | }) 13 | -------------------------------------------------------------------------------- /python/interpreter.py: -------------------------------------------------------------------------------- 1 | import multiprocessing 2 | import sys 3 | import os 4 | import io 5 | 6 | if __name__ == '__main__': 7 | multiprocessing.freeze_support() 8 | script = sys.argv[1] 9 | wd = os.path.dirname(script) 10 | sys.path.append(wd) 11 | sys.argv.pop(0) 12 | sys.stdout = io.TextIOWrapper(open(sys.stdout.fileno(), 'wb', 0), encoding='utf-8', write_through=True) 13 | os.environ['PYGAME_HIDE_SUPPORT_PROMPT'] = "1" 14 | exec(open(script, "r", encoding='utf-8').read(), globals(), locals()) 15 | -------------------------------------------------------------------------------- /python/examples/arkanoid/3. model_training.py: -------------------------------------------------------------------------------- 1 | import pickle 2 | import os 3 | from sklearn import neighbors 4 | 5 | with open(os.path.join(os.path.dirname(__file__), 'feature.pickle'), 'rb') as f: 6 | positions = pickle.load(f) 7 | with open(os.path.join(os.path.dirname(__file__), 'target.pickle'), 'rb') as f: 8 | actions = pickle.load(f) 9 | model = neighbors.KNeighborsRegressor(5, weights='uniform') 10 | model.fit(positions, actions) 11 | with open(os.path.join(os.path.dirname(__file__), 'model.pickle'), 'wb') as f: 12 | pickle.dump(model, f) -------------------------------------------------------------------------------- /python/examples/maze_car/3. model_training.py: -------------------------------------------------------------------------------- 1 | import pickle 2 | import os 3 | from sklearn import neighbors 4 | 5 | with open(os.path.join(os.path.dirname(__file__), 'feature.pickle'), 'rb') as f: 6 | sensor_values = pickle.load(f) 7 | with open(os.path.join(os.path.dirname(__file__), 'target.pickle'), 'rb') as f: 8 | PWMs = pickle.load(f) 9 | model = neighbors.KNeighborsRegressor(5, weights='uniform') 10 | model.fit(sensor_values, PWMs) 11 | with open(os.path.join(os.path.dirname(__file__), 'model.pickle'), 'wb') as f: 12 | pickle.dump(model, f) -------------------------------------------------------------------------------- /python/examples/pingpong/3. model_training.py: -------------------------------------------------------------------------------- 1 | import pickle 2 | import os 3 | from sklearn import tree 4 | 5 | with open(os.path.join(os.path.dirname(__file__), 'feature.pickle'), 'rb') as f: 6 | ball_position = pickle.load(f) 7 | with open(os.path.join(os.path.dirname(__file__), 'target.pickle'), 'rb') as f: 8 | action = pickle.load(f) 9 | model = tree.DecisionTreeRegressor(max_depth=5, min_samples_split=2) 10 | model.fit(ball_position, action) 11 | with open(os.path.join(os.path.dirname(__file__), 'model.pickle'), 'wb') as f: 12 | pickle.dump(model, f) -------------------------------------------------------------------------------- /js/core/interfaces/i_registrable.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2020 Google LLC 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | /** 8 | * @fileoverview The interface for a Blockly component that can be registered. 9 | * (Ex. Toolbox, Fields, Renderers) 10 | * @author aschmiedt@google.com (Abby Schmiedt) 11 | */ 12 | 13 | 'use strict'; 14 | 15 | goog.provide('Blockly.IRegistrable'); 16 | 17 | 18 | /** 19 | * The interface for a Blockly component that can be registered. 20 | * @interface 21 | * */ 22 | Blockly.IRegistrable = function() {}; 23 | -------------------------------------------------------------------------------- /media/dropdown-arrow.svg: -------------------------------------------------------------------------------- 1 | dropdown-arrow -------------------------------------------------------------------------------- /python/examples/racingcar/3. model_training.py: -------------------------------------------------------------------------------- 1 | import pickle 2 | import os 3 | from sklearn import neighbors 4 | 5 | with open(os.path.join(os.path.dirname(__file__), 'feature.pickle'), 'rb') as f: 6 | player_car_position = pickle.load(f) 7 | with open(os.path.join(os.path.dirname(__file__), 'target.pickle'), 'rb') as f: 8 | action = pickle.load(f) 9 | model = neighbors.KNeighborsRegressor(5, weights='uniform') 10 | model.fit(player_car_position, action) 11 | with open(os.path.join(os.path.dirname(__file__), 'model.pickle'), 'wb') as f: 12 | pickle.dump(model, f) -------------------------------------------------------------------------------- /xml/blocks/maze_car.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 100 9 | 10 | 11 | 12 | 13 | 100 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /js/core/blocks.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2013 Google LLC 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | /** 8 | * @fileoverview A mapping of block type names to block prototype objects. 9 | * @author spertus@google.com (Ellen Spertus) 10 | */ 11 | 'use strict'; 12 | 13 | /** 14 | * A mapping of block type names to block prototype objects. 15 | * @name Blockly.Blocks 16 | */ 17 | goog.provide('Blockly.Blocks'); 18 | 19 | /** 20 | * A mapping of block type names to block prototype objects. 21 | * @type {!Object.} 22 | */ 23 | Blockly.Blocks = Object.create(null); 24 | -------------------------------------------------------------------------------- /js/core/interfaces/i_movable.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2019 Google LLC 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | /** 8 | * @fileoverview The interface for an object that is movable. 9 | * @author samelh@google.com (Sam El-Husseini) 10 | */ 11 | 12 | 'use strict'; 13 | 14 | goog.provide('Blockly.IMovable'); 15 | 16 | 17 | /** 18 | * The interface for an object that is movable. 19 | * @interface 20 | */ 21 | Blockly.IMovable = function() {}; 22 | 23 | /** 24 | * Get whether this is movable or not. 25 | * @return {boolean} True if movable. 26 | */ 27 | Blockly.IMovable.prototype.isMovable; 28 | -------------------------------------------------------------------------------- /js/generators/lua/variables_dynamic.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2018 Google LLC 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | /** 8 | * @fileoverview Generating Lua for dynamic variable blocks. 9 | * @author fenichel@google.com (Rachel Fenichel) 10 | */ 11 | 'use strict'; 12 | 13 | goog.provide('Blockly.Lua.variablesDynamic'); 14 | 15 | goog.require('Blockly.Lua'); 16 | goog.require('Blockly.Lua.variables'); 17 | 18 | 19 | // Lua is dynamically typed. 20 | Blockly.Lua['variables_get_dynamic'] = Blockly.Lua['variables_get']; 21 | Blockly.Lua['variables_set_dynamic'] = Blockly.Lua['variables_set']; 22 | -------------------------------------------------------------------------------- /js/generators/php/variables_dynamic.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2018 Google LLC 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | /** 8 | * @fileoverview Generating PHP for dynamic variable blocks. 9 | * @author fenichel@google.com (Rachel Fenichel) 10 | */ 11 | 'use strict'; 12 | 13 | goog.provide('Blockly.PHP.variablesDynamic'); 14 | 15 | goog.require('Blockly.PHP'); 16 | goog.require('Blockly.PHP.variables'); 17 | 18 | 19 | // PHP is dynamically typed. 20 | Blockly.PHP['variables_get_dynamic'] = Blockly.PHP['variables_get']; 21 | Blockly.PHP['variables_set_dynamic'] = Blockly.PHP['variables_set']; 22 | -------------------------------------------------------------------------------- /js/game_msg/template.js: -------------------------------------------------------------------------------- 1 | Blockly.Msg["MLPLAY_GAME_STATUS_OPTIONS"] = [ 2 | ["%{BKY_TEMPLATE_GAME_STATUS_1}", "STATUS_1"], 3 | ["%{BKY_TEMPLATE_GAME_STATUS_2}", "STATUS_2"] 4 | ]; 5 | Blockly.Msg["MLPLAY_GET_INFO_OPTIONS"] = [ 6 | ["%{BKY_TEMPLATE_SCENE_INFO_1}", "INFO_1"], 7 | ["%{BKY_TEMPLATE_SCENE_INFO_2}", "INFO_2"] 8 | ]; 9 | Blockly.Msg["MLPLAY_GET_CONSTANT_OPTIONS"] = [ 10 | ["%{BKY_TEMPLATE_CONSTANT_1}", "1/0"], 11 | ["%{BKY_TEMPLATE_CONSTANT_2}", "2/100"] 12 | ]; 13 | Blockly.Msg["MLPLAY_RETURN_ACTION_OPTIONS"] = [ 14 | ["%{BKY_TEMPLATE_ACTION_1}", "ACTION_1"], 15 | ["%{BKY_TEMPLATE_ACTION_2}", "ACTION_2"] 16 | ]; 17 | -------------------------------------------------------------------------------- /python/examples/easy_game/1. start.py: -------------------------------------------------------------------------------- 1 | import random 2 | 3 | 4 | class MLPlay: 5 | def __init__(self): 6 | print("Initial ml script") 7 | 8 | def update(self, scene_info: dict): 9 | """ 10 | Generate the command according to the received scene information 11 | """ 12 | # print("AI received data from game :", scene_info) 13 | 14 | actions = ["UP", "DOWN", "LEFT", "RIGHT", "NONE"] 15 | 16 | return random.sample(actions, 1) 17 | 18 | def reset(self): 19 | """ 20 | Reset the status 21 | """ 22 | print("reset ml script") 23 | pass 24 | -------------------------------------------------------------------------------- /js/generators/dart/variables_dynamic.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2018 Google LLC 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | /** 8 | * @fileoverview Generating Dart for dynamic variable blocks. 9 | * @author fenichel@google.com (Rachel Fenichel) 10 | */ 11 | 'use strict'; 12 | 13 | goog.provide('Blockly.Dart.variablesDynamic'); 14 | 15 | goog.require('Blockly.Dart'); 16 | goog.require('Blockly.Dart.variables'); 17 | 18 | 19 | // Dart is dynamically typed. 20 | Blockly.Dart['variables_get_dynamic'] = Blockly.Dart['variables_get']; 21 | Blockly.Dart['variables_set_dynamic'] = Blockly.Dart['variables_set']; 22 | -------------------------------------------------------------------------------- /js/core/interfaces/i_deletable.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2019 Google LLC 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | /** 8 | * @fileoverview The interface for an object that is deletable. 9 | * @author samelh@google.com (Sam El-Husseini) 10 | */ 11 | 12 | 'use strict'; 13 | 14 | goog.provide('Blockly.IDeletable'); 15 | 16 | 17 | /** 18 | * The interface for an object that can be deleted. 19 | * @interface 20 | */ 21 | Blockly.IDeletable = function() {}; 22 | 23 | /** 24 | * Get whether this object is deletable or not. 25 | * @return {boolean} True if deletable. 26 | */ 27 | Blockly.IDeletable.prototype.isDeletable; 28 | -------------------------------------------------------------------------------- /js/generators/python/variables_dynamic.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2018 Google LLC 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | /** 8 | * @fileoverview Generating Python for dynamic variable blocks. 9 | * @author fenichel@google.com (Rachel Fenichel) 10 | */ 11 | 'use strict'; 12 | 13 | goog.provide('Blockly.Python.variablesDynamic'); 14 | 15 | goog.require('Blockly.Python'); 16 | goog.require('Blockly.Python.variables'); 17 | 18 | 19 | // Python is dynamically typed. 20 | Blockly.Python['variables_get_dynamic'] = Blockly.Python['variables_get']; 21 | Blockly.Python['variables_set_dynamic'] = Blockly.Python['variables_set']; 22 | -------------------------------------------------------------------------------- /js/core/keyboard_nav/action.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2019 Google LLC 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | /** 8 | * @fileoverview The class representing an action. 9 | * Used primarily for keyboard navigation. 10 | */ 11 | 'use strict'; 12 | 13 | goog.provide('Blockly.Action'); 14 | 15 | 16 | /** 17 | * Class for a single action. 18 | * An action describes user intent. (ex go to next or go to previous) 19 | * @param {string} name The name of the action. 20 | * @param {string} desc The description of the action. 21 | * @constructor 22 | */ 23 | Blockly.Action = function(name, desc) { 24 | this.name = name; 25 | this.desc = desc; 26 | }; 27 | -------------------------------------------------------------------------------- /js/generators/javascript/variables_dynamic.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2018 Google LLC 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | /** 8 | * @fileoverview Generating JavaScript for dynamic variable blocks. 9 | * @author fenichel@google.com (Rachel Fenichel) 10 | */ 11 | 'use strict'; 12 | 13 | goog.provide('Blockly.JavaScript.variablesDynamic'); 14 | 15 | goog.require('Blockly.JavaScript'); 16 | goog.require('Blockly.JavaScript.variables'); 17 | 18 | 19 | // JavaScript is dynamically typed. 20 | Blockly.JavaScript['variables_get_dynamic'] = 21 | Blockly.JavaScript['variables_get']; 22 | Blockly.JavaScript['variables_set_dynamic'] = 23 | Blockly.JavaScript['variables_set']; 24 | -------------------------------------------------------------------------------- /js/core/interfaces/i_deletearea.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2020 Google LLC 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | /** 8 | * @fileoverview The interface for a component that can delete a block that is 9 | * dropped on top of it. 10 | * @author aschmiedt@google.com (Abby Schmiedt) 11 | */ 12 | 13 | 'use strict'; 14 | 15 | goog.provide('Blockly.IDeleteArea'); 16 | 17 | 18 | /** 19 | * Interface for a component that can delete a block that is dropped on top of it. 20 | * @interface 21 | */ 22 | Blockly.IDeleteArea = function() {}; 23 | 24 | /** 25 | * Return the deletion rectangle. 26 | * @return {Blockly.utils.Rect} Rectangle in which to delete. 27 | */ 28 | Blockly.IDeleteArea.prototype.getClientRect; 29 | -------------------------------------------------------------------------------- /js/generators/python/plot.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | goog.provide('Blockly.Python.plot'); 4 | 5 | goog.require('Blockly.Python'); 6 | 7 | Blockly.Python['plot_plot'] = function(block) { 8 | // Plot. 9 | Blockly.Python.definitions_['import_plt'] = 'import matplotlib.pyplot as plt'; 10 | var x = Blockly.Python.valueToCode(block, 'X', 11 | Blockly.Python.ORDER_NONE) || '[]'; 12 | var y = Blockly.Python.valueToCode(block, 'Y', 13 | Blockly.Python.ORDER_NONE) || '[]'; 14 | var marker = block.getFieldValue('MARKER'); 15 | var line = block.getFieldValue('LINE'); 16 | var color = block.getFieldValue('COLOR'); 17 | var code = 'plt.plot(' + x + ', ' + y + ', "' + marker + line + '", color="' + color + '")\n' + 18 | 'plt.show()\n'; 19 | return code; 20 | }; -------------------------------------------------------------------------------- /js/externs/block-externs.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2020 Google LLC 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | /** 8 | * @fileoverview Externs for Blockly blocks. 9 | * @externs 10 | */ 11 | 12 | goog.provide('Blockly'); 13 | goog.provide('Blockly.Blocks'); 14 | goog.provide('Blockly.Comment'); 15 | goog.provide('Blockly.FieldCheckbox'); 16 | goog.provide('Blockly.FieldColour'); 17 | goog.provide('Blockly.FieldDropdown'); 18 | goog.provide('Blockly.FieldImage'); 19 | goog.provide('Blockly.FieldLabel'); 20 | goog.provide('Blockly.FieldMultilineInput'); 21 | goog.provide('Blockly.FieldNumber'); 22 | goog.provide('Blockly.FieldTextInput'); 23 | goog.provide('Blockly.FieldVariable'); 24 | goog.provide('Blockly.Mutator'); 25 | goog.provide('Blockly.Warning'); 26 | 27 | var Blockly; -------------------------------------------------------------------------------- /js/core/interfaces/i_bounded_element.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2020 Google LLC 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | /** 8 | * @fileoverview The interface for a bounded element. 9 | * @author samelh@google.com (Sam El-Husseini) 10 | */ 11 | 12 | 'use strict'; 13 | 14 | goog.provide('Blockly.IBoundedElement'); 15 | 16 | goog.requireType('Blockly.utils.Rect'); 17 | 18 | 19 | /** 20 | * A bounded element interface. 21 | * @interface 22 | */ 23 | Blockly.IBoundedElement = function() {}; 24 | 25 | /** 26 | * Returns the coordinates of a bounded element describing the dimensions of the 27 | * element. 28 | * Coordinate system: workspace coordinates. 29 | * @return {!Blockly.utils.Rect} Object with coordinates of the bounded element. 30 | */ 31 | Blockly.IBoundedElement.prototype.getBoundingRectangle; 32 | -------------------------------------------------------------------------------- /js/core/msg.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2013 Google LLC 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | /** 8 | * @fileoverview Empty name space for the Message singleton. 9 | * @author scr@google.com (Sheridan Rawlins) 10 | */ 11 | 'use strict'; 12 | 13 | /** 14 | * Name space for the Msg singleton. 15 | * Msg gets populated in the message files. 16 | */ 17 | goog.provide('Blockly.Msg'); 18 | 19 | goog.require('Blockly.utils.global'); 20 | 21 | 22 | /** 23 | * Exported so that if Blockly is compiled with ADVANCED_COMPILATION, 24 | * the Blockly.Msg object exists for message files included in script tags. 25 | */ 26 | if (!Blockly.utils.global['Blockly']) { 27 | Blockly.utils.global['Blockly'] = {}; 28 | } 29 | if (!Blockly.utils.global['Blockly']['Msg']) { 30 | Blockly.utils.global['Blockly']['Msg'] = Blockly.Msg; 31 | } 32 | -------------------------------------------------------------------------------- /python/examples/racingcar/4. model_playing.py: -------------------------------------------------------------------------------- 1 | import pickle 2 | import os 3 | 4 | class MLPlay: 5 | def __init__(self, player): 6 | self.player = player 7 | self.other_cars_position = [] 8 | with open(os.path.join(os.path.dirname(__file__), 'model.pickle'), 'rb') as f: 9 | self.model = pickle.load(f) 10 | def update(self, scene_info): 11 | if scene_info['status'] == "RUNNING": 12 | self.action = self.model.predict([[scene_info['x'], scene_info['y']]]) 13 | if self.action == 1: 14 | return ['SPEED'] 15 | elif self.action == 2: 16 | return ['BRAKE'] 17 | elif self.action == 3: 18 | return ['MOVE_LEFT'] 19 | elif self.action == 4: 20 | return ['MOVE_RIGHT'] 21 | def reset(self): 22 | pass -------------------------------------------------------------------------------- /python/examples/pingpong/4. model_playing.py: -------------------------------------------------------------------------------- 1 | import pickle 2 | import os 3 | 4 | class MLPlay: 5 | def __init__(self, side): 6 | self.ball_served = False 7 | self.side = side 8 | with open(os.path.join(os.path.dirname(__file__), 'model.pickle'), 'rb') as f: 9 | self.model = pickle.load(f) 10 | def update(self, scene_info): 11 | if scene_info['status'] != "GAME_ALIVE": 12 | return "RESET" 13 | if not self.ball_served: 14 | self.ball_served = True 15 | return "SERVE_TO_LEFT" 16 | else: 17 | self.action = self.model.predict([[scene_info['ball'][0], scene_info['ball'][1]]]) 18 | if self.action == 1: 19 | return "MOVE_LEFT" 20 | else: 21 | return "SERVE_TO_RIGHT" 22 | def reset(self): 23 | self.ball_served = False -------------------------------------------------------------------------------- /python/examples/arkanoid/4. model_playing.py: -------------------------------------------------------------------------------- 1 | import pickle 2 | import os 3 | 4 | class MLPlay: 5 | def __init__(self): 6 | self.ball_served = False 7 | with open(os.path.join(os.path.dirname(__file__), 'model.pickle'), 'rb') as f: 8 | self.model = pickle.load(f) 9 | def update(self, scene_info): 10 | if scene_info['status'] == "GAME_PASS" or scene_info['status'] == "GAME_OVER": 11 | return "RESET" 12 | if not self.ball_served: 13 | self.ball_served = True 14 | return "SERVE_TO_LEFT" 15 | else: 16 | self.action = self.model.predict([[scene_info['ball'][0], scene_info['ball'][1]]]) 17 | 18 | if self.action == 1: 19 | return "MOVE_LEFT" 20 | else: 21 | return "MOVE_RIGHT" 22 | def reset(self): 23 | self.ball_served = False -------------------------------------------------------------------------------- /js/core/utils/global.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2019 Google LLC 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | /** 8 | * @fileoverview Provides a reference to the global object. 9 | * @author samelh@google.com (Sam El-Husseini) 10 | */ 11 | 'use strict'; 12 | 13 | /** 14 | * @name Blockly.utils.global 15 | * @namespace 16 | */ 17 | goog.provide('Blockly.utils.global'); 18 | 19 | 20 | /** 21 | * Reference to the global object. 22 | * 23 | * More info on this implementation here: 24 | * https://docs.google.com/document/d/1NAeW4Wk7I7FV0Y2tcUFvQdGMc89k2vdgSXInw8_nvCI/edit 25 | */ 26 | Blockly.utils.global = function() { 27 | if (typeof self === 'object') { 28 | return self; 29 | } 30 | if (typeof window === 'object') { 31 | return window; 32 | } 33 | if (typeof global === 'object') { 34 | return global; 35 | } 36 | return this; 37 | }(); 38 | -------------------------------------------------------------------------------- /js/core/interfaces/i_styleable.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2020 Google LLC 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | /** 8 | * @fileoverview The interface for an object that a style can be added to. 9 | * @author aschmiedt@google.com (Abby Schmiedt) 10 | */ 11 | 12 | 'use strict'; 13 | 14 | goog.provide('Blockly.IStyleable'); 15 | 16 | 17 | /** 18 | * Interface for an object that a style can be added to. 19 | * @interface 20 | */ 21 | Blockly.IStyleable = function() {}; 22 | 23 | /** 24 | * Adds a style on the toolbox. Usually used to change the cursor. 25 | * @param {string} style The name of the class to add. 26 | */ 27 | Blockly.IStyleable.prototype.addStyle; 28 | 29 | /** 30 | * Removes a style from the toolbox. Usually used to change the cursor. 31 | * @param {string} style The name of the class to remove. 32 | */ 33 | Blockly.IStyleable.prototype.removeStyle; 34 | -------------------------------------------------------------------------------- /js/core/theme/dark.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2019 Google LLC 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | /** 8 | * @fileoverview Dark theme. 9 | * @author samelh@google.com (Sam El-Husseini) 10 | */ 11 | 'use strict'; 12 | 13 | goog.provide('Blockly.Themes.Dark'); 14 | 15 | goog.require('Blockly.Theme'); 16 | 17 | Blockly.Themes.Dark = Blockly.Theme.defineTheme('dark', { 18 | 'base': Blockly.Themes.Classic, 19 | 'componentStyles': { 20 | 'workspaceBackgroundColour': '#1e1e1e', 21 | 'toolboxBackgroundColour': '#333', 22 | 'toolboxForegroundColour': '#fff', 23 | 'flyoutBackgroundColour': '#252526', 24 | 'flyoutForegroundColour': '#ccc', 25 | 'flyoutOpacity': 1, 26 | 'scrollbarColour': '#797979', 27 | 'insertionMarkerColour': '#fff', 28 | 'insertionMarkerOpacity': 0.3, 29 | 'scrollbarOpacity': 0.4, 30 | 'cursorColour': '#d0d0d0' 31 | } 32 | }); 33 | -------------------------------------------------------------------------------- /js/core/renderers/minimalist/constants.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2019 Google LLC 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | /** 8 | * @fileoverview An object that provides constants for rendering blocks in the 9 | * minimalist renderer. 10 | */ 11 | 'use strict'; 12 | 13 | goog.provide('Blockly.minimalist.ConstantProvider'); 14 | 15 | goog.require('Blockly.blockRendering.ConstantProvider'); 16 | goog.require('Blockly.utils.object'); 17 | 18 | 19 | /** 20 | * An object that provides constants for rendering blocks in the sample. 21 | * @constructor 22 | * @package 23 | * @extends {Blockly.blockRendering.ConstantProvider} 24 | */ 25 | Blockly.minimalist.ConstantProvider = function() { 26 | Blockly.minimalist.ConstantProvider.superClass_.constructor.call(this); 27 | }; 28 | Blockly.utils.object.inherits(Blockly.minimalist.ConstantProvider, 29 | Blockly.blockRendering.ConstantProvider); 30 | -------------------------------------------------------------------------------- /js/core/interfaces/i_copyable.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2019 Google LLC 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | /** 8 | * @fileoverview The interface for an object that is copyable. 9 | * @author samelh@google.com (Sam El-Husseini) 10 | */ 11 | 12 | 'use strict'; 13 | 14 | goog.provide('Blockly.ICopyable'); 15 | 16 | goog.requireType('Blockly.ISelectable'); 17 | goog.requireType('Blockly.WorkspaceSvg'); 18 | 19 | 20 | /** 21 | * @extends {Blockly.ISelectable} 22 | * @interface 23 | */ 24 | Blockly.ICopyable = function() {}; 25 | 26 | /** 27 | * Encode for copying. 28 | * @return {!Blockly.ICopyable.CopyData} Copy metadata. 29 | */ 30 | Blockly.ICopyable.prototype.toCopyData; 31 | 32 | /** 33 | * Copy Metadata. 34 | * @typedef {{ 35 | * xml:!Element, 36 | * source:Blockly.WorkspaceSvg, 37 | * typeCounts:?Object 38 | * }} 39 | */ 40 | Blockly.ICopyable.CopyData; 41 | -------------------------------------------------------------------------------- /python/examples/arkanoid/1. start.py: -------------------------------------------------------------------------------- 1 | """ 2 | The template of the main script of the machine learning process 3 | """ 4 | 5 | class MLPlay: 6 | def __init__(self): 7 | """ 8 | Constructor 9 | """ 10 | self.ball_served = False 11 | 12 | def update(self, scene_info): 13 | """ 14 | Generate the command according to the received `scene_info`. 15 | """ 16 | # Make the caller to invoke `reset()` for the next round. 17 | if (scene_info["status"] == "GAME_OVER" or 18 | scene_info["status"] == "GAME_PASS"): 19 | return "RESET" 20 | 21 | if not self.ball_served: 22 | self.ball_served = True 23 | command = "SERVE_TO_LEFT" 24 | else: 25 | command = "MOVE_LEFT" 26 | 27 | return command 28 | 29 | def reset(self): 30 | """ 31 | Reset the status 32 | """ 33 | self.ball_served = False -------------------------------------------------------------------------------- /js/core/utils/idgenerator.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2019 Google LLC 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | /** 8 | * @fileoverview Generator for unique element IDs. 9 | * For UUIDs use Blockly.utils.genUid. The ID generator should primarily be 10 | * used for IDs that end up in the DOM. 11 | * @author samelh@google.com (Sam El-Husseini) 12 | */ 13 | 'use strict'; 14 | 15 | goog.provide('Blockly.utils.IdGenerator'); 16 | 17 | 18 | /** 19 | * Next unique ID to use. 20 | * @type {number} 21 | * @private 22 | */ 23 | Blockly.utils.IdGenerator.nextId_ = 0; 24 | 25 | /** 26 | * Gets the next unique ID. 27 | * IDs are compatible with the HTML4 id attribute restrictions: 28 | * Use only ASCII letters, digits, '_', '-' and '.' 29 | * @return {string} The next unique identifier. 30 | */ 31 | Blockly.utils.IdGenerator.getNextUniqueId = function() { 32 | return 'blockly-' + (Blockly.utils.IdGenerator.nextId_++).toString(36); 33 | }; 34 | -------------------------------------------------------------------------------- /python/examples/pingpong/1. start.py: -------------------------------------------------------------------------------- 1 | """ 2 | The template of the script for the machine learning process in game pingpong 3 | """ 4 | 5 | class MLPlay: 6 | def __init__(self, side): 7 | """ 8 | Constructor 9 | 10 | @param side A string "1P" or "2P" indicates that the `MLPlay` is used by 11 | which side. 12 | """ 13 | self.ball_served = False 14 | self.side = side 15 | 16 | def update(self, scene_info): 17 | """ 18 | Generate the command according to the received scene information 19 | """ 20 | if scene_info["status"] != "GAME_ALIVE": 21 | return "RESET" 22 | 23 | if not self.ball_served: 24 | self.ball_served = True 25 | return "SERVE_TO_LEFT" 26 | else: 27 | return "MOVE_LEFT" 28 | 29 | def reset(self): 30 | """ 31 | Reset the status 32 | """ 33 | self.ball_served = False 34 | -------------------------------------------------------------------------------- /js/generators/lua/variables.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2016 Google LLC 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | /** 8 | * @fileoverview Generating Lua for variable blocks. 9 | * @author rodrigoq@google.com (Rodrigo Queiro) 10 | */ 11 | 'use strict'; 12 | 13 | goog.provide('Blockly.Lua.variables'); 14 | 15 | goog.require('Blockly.Lua'); 16 | 17 | 18 | Blockly.Lua['variables_get'] = function(block) { 19 | // Variable getter. 20 | var code = Blockly.Lua.variableDB_.getName(block.getFieldValue('VAR'), 21 | Blockly.VARIABLE_CATEGORY_NAME); 22 | return [code, Blockly.Lua.ORDER_ATOMIC]; 23 | }; 24 | 25 | Blockly.Lua['variables_set'] = function(block) { 26 | // Variable setter. 27 | var argument0 = Blockly.Lua.valueToCode(block, 'VALUE', 28 | Blockly.Lua.ORDER_NONE) || '0'; 29 | var varName = Blockly.Lua.variableDB_.getName( 30 | block.getFieldValue('VAR'), Blockly.VARIABLE_CATEGORY_NAME); 31 | return varName + ' = ' + argument0 + '\n'; 32 | }; 33 | -------------------------------------------------------------------------------- /js/core/interfaces/i_selectable.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2019 Google LLC 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | /** 8 | * @fileoverview The interface for an object that is selectable. 9 | * @author samelh@google.com (Sam El-Husseini) 10 | */ 11 | 12 | 'use strict'; 13 | 14 | goog.provide('Blockly.ISelectable'); 15 | 16 | goog.requireType('Blockly.IDeletable'); 17 | goog.requireType('Blockly.IMovable'); 18 | 19 | 20 | /** 21 | * The interface for an object that is selectable. 22 | * @extends {Blockly.IDeletable} 23 | * @extends {Blockly.IMovable} 24 | * @interface 25 | */ 26 | Blockly.ISelectable = function() {}; 27 | 28 | /** 29 | * @type {string} 30 | */ 31 | Blockly.ISelectable.prototype.id; 32 | 33 | /** 34 | * Select this. Highlight it visually. 35 | * @return {void} 36 | */ 37 | Blockly.ISelectable.prototype.select; 38 | 39 | /** 40 | * Unselect this. Unhighlight it visually. 41 | * @return {void} 42 | */ 43 | Blockly.ISelectable.prototype.unselect; 44 | -------------------------------------------------------------------------------- /js/generators/dart/variables.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2014 Google LLC 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | /** 8 | * @fileoverview Generating Dart for variable blocks. 9 | * @author fraser@google.com (Neil Fraser) 10 | */ 11 | 'use strict'; 12 | 13 | goog.provide('Blockly.Dart.variables'); 14 | 15 | goog.require('Blockly.Dart'); 16 | 17 | 18 | Blockly.Dart['variables_get'] = function(block) { 19 | // Variable getter. 20 | var code = Blockly.Dart.variableDB_.getName(block.getFieldValue('VAR'), 21 | Blockly.VARIABLE_CATEGORY_NAME); 22 | return [code, Blockly.Dart.ORDER_ATOMIC]; 23 | }; 24 | 25 | Blockly.Dart['variables_set'] = function(block) { 26 | // Variable setter. 27 | var argument0 = Blockly.Dart.valueToCode(block, 'VALUE', 28 | Blockly.Dart.ORDER_ASSIGNMENT) || '0'; 29 | var varName = Blockly.Dart.variableDB_.getName(block.getFieldValue('VAR'), 30 | Blockly.VARIABLE_CATEGORY_NAME); 31 | return varName + ' = ' + argument0 + ';\n'; 32 | }; 33 | -------------------------------------------------------------------------------- /js/generators/php/variables.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2015 Google LLC 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | /** 8 | * @fileoverview Generating PHP for variable blocks. 9 | * @author daarond@gmail.com (Daaron Dwyer) 10 | */ 11 | 'use strict'; 12 | 13 | goog.provide('Blockly.PHP.variables'); 14 | 15 | goog.require('Blockly.PHP'); 16 | 17 | 18 | Blockly.PHP['variables_get'] = function(block) { 19 | // Variable getter. 20 | var code = Blockly.PHP.variableDB_.getName(block.getFieldValue('VAR'), 21 | Blockly.VARIABLE_CATEGORY_NAME); 22 | return [code, Blockly.PHP.ORDER_ATOMIC]; 23 | }; 24 | 25 | Blockly.PHP['variables_set'] = function(block) { 26 | // Variable setter. 27 | var argument0 = Blockly.PHP.valueToCode(block, 'VALUE', 28 | Blockly.PHP.ORDER_ASSIGNMENT) || '0'; 29 | var varName = Blockly.PHP.variableDB_.getName( 30 | block.getFieldValue('VAR'), Blockly.VARIABLE_CATEGORY_NAME); 31 | return varName + ' = ' + argument0 + ';\n'; 32 | }; 33 | -------------------------------------------------------------------------------- /js/generators/python/variables.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2012 Google LLC 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | /** 8 | * @fileoverview Generating Python for variable blocks. 9 | * @author q.neutron@gmail.com (Quynh Neutron) 10 | */ 11 | 'use strict'; 12 | 13 | goog.provide('Blockly.Python.variables'); 14 | 15 | goog.require('Blockly.Python'); 16 | 17 | 18 | Blockly.Python['variables_get'] = function(block) { 19 | // Variable getter. 20 | var code = Blockly.Python.variableDB_.getName(block.getFieldValue('VAR'), 21 | Blockly.VARIABLE_CATEGORY_NAME); 22 | return [code, Blockly.Python.ORDER_ATOMIC]; 23 | }; 24 | 25 | Blockly.Python['variables_set'] = function(block) { 26 | // Variable setter. 27 | var argument0 = Blockly.Python.valueToCode(block, 'VALUE', 28 | Blockly.Python.ORDER_NONE) || '0'; 29 | var varName = Blockly.Python.variableDB_.getName(block.getFieldValue('VAR'), 30 | Blockly.VARIABLE_CATEGORY_NAME); 31 | return varName + ' = ' + argument0 + '\n'; 32 | }; 33 | -------------------------------------------------------------------------------- /js/core/renderers/minimalist/drawer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2019 Google LLC 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | /** 8 | * @fileoverview Minimalist rendering drawer. 9 | */ 10 | 'use strict'; 11 | 12 | goog.provide('Blockly.minimalist.Drawer'); 13 | 14 | goog.require('Blockly.blockRendering.Drawer'); 15 | goog.require('Blockly.utils.object'); 16 | goog.require('Blockly.minimalist.RenderInfo'); 17 | 18 | 19 | /** 20 | * An object that draws a block based on the given rendering information. 21 | * @param {!Blockly.BlockSvg} block The block to render. 22 | * @param {!Blockly.minimalist.RenderInfo} info An object containing all 23 | * information needed to render this block. 24 | * @package 25 | * @constructor 26 | * @extends {Blockly.blockRendering.Drawer} 27 | */ 28 | Blockly.minimalist.Drawer = function(block, info) { 29 | Blockly.minimalist.Drawer.superClass_.constructor.call(this, block, info); 30 | }; 31 | Blockly.utils.object.inherits(Blockly.minimalist.Drawer, 32 | Blockly.blockRendering.Drawer); 33 | -------------------------------------------------------------------------------- /python/examples/maze_car/4. model_playing.py: -------------------------------------------------------------------------------- 1 | import pickle 2 | import os 3 | 4 | class MLPlay: 5 | def __init__(self, player): 6 | self.f_sensor_value = 0 7 | self.r_sensor_value = 0 8 | self.l_sensor_value = 0 9 | self.left_PWM = 0 10 | self.right_PWM = 0 11 | self.sensor_values = [] 12 | self.PWMs = [] 13 | with open(os.path.join(os.path.dirname(__file__), 'model.pickle'), 'rb') as f: 14 | self.model = pickle.load(f) 15 | def update(self, scene_info): 16 | self.f_sensor_value = scene_info['F_sensor'] 17 | self.l_sensor_value = scene_info['L_sensor'] 18 | self.r_sensor_value = scene_info['R_sensor'] 19 | self.sensor_values = [[self.f_sensor_value, self.l_sensor_value, self.r_sensor_value]] 20 | self.PWMs = self.model.predict(self.sensor_values) 21 | 22 | self.left_PWM = self.PWMs[0][0] 23 | self.right_PWM = self.PWMs[0][1] 24 | return [{'left_PWM': self.left_PWM, 'right_PWM': self.right_PWM}] 25 | def reset(self): 26 | pass -------------------------------------------------------------------------------- /js/generators/javascript/variables.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2012 Google LLC 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | /** 8 | * @fileoverview Generating JavaScript for variable blocks. 9 | * @author fraser@google.com (Neil Fraser) 10 | */ 11 | 'use strict'; 12 | 13 | goog.provide('Blockly.JavaScript.variables'); 14 | 15 | goog.require('Blockly.JavaScript'); 16 | 17 | 18 | Blockly.JavaScript['variables_get'] = function(block) { 19 | // Variable getter. 20 | var code = Blockly.JavaScript.variableDB_.getName(block.getFieldValue('VAR'), 21 | Blockly.VARIABLE_CATEGORY_NAME); 22 | return [code, Blockly.JavaScript.ORDER_ATOMIC]; 23 | }; 24 | 25 | Blockly.JavaScript['variables_set'] = function(block) { 26 | // Variable setter. 27 | var argument0 = Blockly.JavaScript.valueToCode(block, 'VALUE', 28 | Blockly.JavaScript.ORDER_ASSIGNMENT) || '0'; 29 | var varName = Blockly.JavaScript.variableDB_.getName( 30 | block.getFieldValue('VAR'), Blockly.VARIABLE_CATEGORY_NAME); 31 | return varName + ' = ' + argument0 + ';\n'; 32 | }; 33 | -------------------------------------------------------------------------------- /js/msg/json/synonyms.json: -------------------------------------------------------------------------------- 1 | {"CONTROLS_WHILEUNTIL_INPUT_DO": "CONTROLS_REPEAT_INPUT_DO", "CONTROLS_FOR_INPUT_DO": "CONTROLS_REPEAT_INPUT_DO", "CONTROLS_FOREACH_INPUT_DO": "CONTROLS_REPEAT_INPUT_DO", "CONTROLS_IF_MSG_THEN": "CONTROLS_REPEAT_INPUT_DO", "CONTROLS_IF_IF_TITLE_IF": "CONTROLS_IF_MSG_IF", "CONTROLS_IF_ELSEIF_TITLE_ELSEIF": "CONTROLS_IF_MSG_ELSEIF", "CONTROLS_IF_ELSE_TITLE_ELSE": "CONTROLS_IF_MSG_ELSE", "MATH_CHANGE_TITLE_ITEM": "VARIABLES_DEFAULT_NAME", "TEXT_CREATE_JOIN_ITEM_TITLE_ITEM": "VARIABLES_DEFAULT_NAME", "TEXT_APPEND_VARIABLE": "VARIABLES_DEFAULT_NAME", "LISTS_CREATE_WITH_ITEM_TITLE": "VARIABLES_DEFAULT_NAME", "LISTS_INDEX_OF_INPUT_IN_LIST": "LISTS_INLIST", "LISTS_GET_INDEX_HELPURL": "LISTS_INDEX_OF_HELPURL", "LISTS_GET_INDEX_INPUT_IN_LIST": "LISTS_INLIST", "LISTS_SET_INDEX_INPUT_IN_LIST": "LISTS_INLIST", "LISTS_GET_SUBLIST_INPUT_IN_LIST": "LISTS_INLIST", "PROCEDURES_DEFRETURN_TITLE": "PROCEDURES_DEFNORETURN_TITLE", "PROCEDURES_DEFRETURN_PROCEDURE": "PROCEDURES_DEFNORETURN_PROCEDURE", "PROCEDURES_DEFRETURN_DO": "PROCEDURES_DEFNORETURN_DO", "PROCEDURES_DEFRETURN_COMMENT": "PROCEDURES_DEFNORETURN_COMMENT"} -------------------------------------------------------------------------------- /python/examples/racingcar/1. start.py: -------------------------------------------------------------------------------- 1 | class MLPlay: 2 | def __init__(self, player): 3 | self.player = player 4 | if self.player == "player1": 5 | self.player_no = 0 6 | elif self.player == "player2": 7 | self.player_no = 1 8 | elif self.player == "player3": 9 | self.player_no = 2 10 | elif self.player == "player4": 11 | self.player_no = 3 12 | self.other_cars_position = [] 13 | self.coins_pos = [] 14 | print("Initial ml script") 15 | 16 | def update(self, scene_info: dict): 17 | """ 18 | Generate the command according to the received scene information 19 | """ 20 | if scene_info["status"] == "RUNNING": 21 | self.car_pos = (scene_info["x"], scene_info["y"]) 22 | 23 | self.other_cars_position = scene_info["cars_pos"] 24 | if scene_info.__contains__("coin"): 25 | self.coin_pos = scene_info["coin"] 26 | 27 | return ["SPEED"] 28 | 29 | def reset(self): 30 | """ 31 | Reset the status 32 | """ 33 | print("reset ml script") 34 | pass 35 | -------------------------------------------------------------------------------- /js/core/renderers/measurables/base.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2019 Google LLC 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | /** 8 | * @fileoverview Methods for graphically rendering a block as SVG. 9 | * @author fenichel@google.com (Rachel Fenichel) 10 | */ 11 | 12 | 'use strict'; 13 | 14 | goog.provide('Blockly.blockRendering.Measurable'); 15 | 16 | goog.require('Blockly.blockRendering.Types'); 17 | 18 | 19 | /** 20 | * The base class to represent a part of a block that takes up space during 21 | * rendering. The constructor for each non-spacer Measurable records the size 22 | * of the block element (e.g. field, statement input). 23 | * @param {!Blockly.blockRendering.ConstantProvider} constants The rendering 24 | * constants provider. 25 | * @package 26 | * @constructor 27 | */ 28 | Blockly.blockRendering.Measurable = function(constants) { 29 | this.width = 0; 30 | this.height = 0; 31 | this.type = Blockly.blockRendering.Types.NONE; 32 | 33 | this.xPos = 0; 34 | this.centerline = 0; 35 | 36 | /** 37 | * The renderer's constant provider. 38 | * @type {!Blockly.blockRendering.ConstantProvider} 39 | * @protected 40 | */ 41 | this.constants_ = constants; 42 | 43 | this.notchOffset = this.constants_.NOTCH_OFFSET_LEFT; 44 | }; 45 | -------------------------------------------------------------------------------- /js/core/renderers/zelos/measurables/row_elements.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2019 Google LLC 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | /** 8 | * @fileoverview Zelos specific objects representing elements in a row of a 9 | * rendered block. 10 | * @author samelh@google.com (Sam El-Husseini) 11 | */ 12 | 13 | goog.provide('Blockly.zelos.RightConnectionShape'); 14 | 15 | goog.require('Blockly.blockRendering.Measurable'); 16 | goog.require('Blockly.blockRendering.Types'); 17 | goog.require('Blockly.utils.object'); 18 | 19 | 20 | /** 21 | * An object containing information about the space a right connection shape 22 | * takes up during rendering. 23 | * @param {!Blockly.blockRendering.ConstantProvider} constants The rendering 24 | * constants provider. 25 | * @package 26 | * @constructor 27 | * @extends {Blockly.blockRendering.Measurable} 28 | */ 29 | Blockly.zelos.RightConnectionShape = function(constants) { 30 | Blockly.zelos.RightConnectionShape.superClass_.constructor.call(this, constants); 31 | this.type |= Blockly.blockRendering.Types.getType('RIGHT_CONNECTION'); 32 | // Size is dynamic 33 | this.height = 0; 34 | this.width = 0; 35 | }; 36 | Blockly.utils.object.inherits(Blockly.zelos.RightConnectionShape, 37 | Blockly.blockRendering.Measurable); 38 | -------------------------------------------------------------------------------- /python/examples/maze_car/1. start.py: -------------------------------------------------------------------------------- 1 | class MLPlay: 2 | def __init__(self, player): 3 | self.player_no = player[6] 4 | self.r_sensor_value = 0 5 | self.l_sensor_value = 0 6 | self.f_sensor_value = 0 7 | self.control_list = [{"left_PWM" : 0, "right_PWM" : 0}] 8 | print("Initial ml script") 9 | 10 | def update(self, scene_info: dict): 11 | """ 12 | Generate the command according to the received scene information 13 | """ 14 | self.r_sensor_value = scene_info["R_sensor"] 15 | self.l_sensor_value = scene_info["L_sensor"] 16 | self.f_sensor_value = scene_info["F_sensor"] 17 | if self.f_sensor_value >30: 18 | self.control_list[0]["left_PWM"] = 50 19 | self.control_list[0]["right_PWM"] = 50 20 | if self.r_sensor_value >30: 21 | self.control_list[0]["left_PWM"] = 100 22 | if self.l_sensor_value >30: 23 | self.control_list[0]["right_PWM"] = 100 24 | if self.f_sensor_value <10: 25 | self.control_list[0]["left_PWM"] = -50 26 | self.control_list[0]["right_PWM"] = -50 27 | return self.control_list 28 | 29 | def reset(self): 30 | """ 31 | Reset the status 32 | """ 33 | print("reset ml script") 34 | pass 35 | -------------------------------------------------------------------------------- /js/ui_msg/zh-hant.js: -------------------------------------------------------------------------------- 1 | var MSG = { 2 | title: "積木程式", 3 | blocks: "積木", 4 | examples: "範例程式", 5 | lang: "語言", 6 | options: "選項", 7 | linkTooltip: "儲存積木組並提供連結。", 8 | runTooltip: "於工作區中執行積木組所定義的程式。", 9 | badCode: "程式錯誤:\n%1", 10 | timeout: "超過最大執行數。", 11 | discard: "捨棄所有積木", 12 | download: "儲存 Python 檔", 13 | runMLGame: "玩遊戲", 14 | runPython: "執行 Python 檔", 15 | openXml: "開啟 XML 檔", 16 | openPython: "開啟 Python 檔", 17 | downloadXml: "儲存 XML 檔", 18 | en: "英文", 19 | zh_hant: "中文", 20 | catLogic: "邏輯", 21 | catLoops: "迴圈", 22 | catMath: "數學式", 23 | catText: "文字", 24 | catLists: "清單", 25 | catDicts: "字典", 26 | catNdarrays: "多維陣列", 27 | catColour: "顏色", 28 | catFile: "檔案", 29 | catPlot: "繪圖", 30 | catModel: "模型", 31 | catVariables: "變數", 32 | catFunctions: "函式", 33 | listVariable: "清單", 34 | ndarrayVariable: "多維陣列", 35 | textVariable: "文字", 36 | dictVariable: "字典", 37 | modelVariable: "模型", 38 | objVariable: "物件", 39 | filename: "檔案名稱", 40 | trainData: "訓練資料", 41 | testData: "測試資料", 42 | trainTarget: "訓練目標", 43 | testTarget: "測試目標", 44 | httpRequestError: "命令出現錯誤。", 45 | linkAlert: "透過此連結分享您的積木組:\n\n%1", 46 | hashError: "對不起,「%1」並未對應任何已保存的程式。", 47 | xmlError: "未能載入您保存的檔案。或許它是由其他版本的Blockly創建?", 48 | badXml: "解析 XML 時出現錯誤:\n%1\n\n選擇'確定'以放棄您的更改,或選擇'取消'以進一步編輯 XML。" 49 | }; 50 | -------------------------------------------------------------------------------- /js/mlgame/easy_game.json: -------------------------------------------------------------------------------- 1 | { 2 | "GAME_STATUS": [ 3 | ["GAME_ALIVE", "alive", "存活"], 4 | ["GAME_PASS", "pass", "通關"], 5 | ["GAME_OVER", "over", "失敗"] 6 | ], 7 | "SCENE_INFO": [ 8 | ["scene_info['frame']", "# frame", "# 幀數"], 9 | ["scene_info['status']", "game status", "遊戲狀態"], 10 | ["scene_info['ball_x']", "x coordinate of ball", "球的 x 座標"], 11 | ["scene_info['ball_y']", "y coordinate of ball", "球的 y 座標"], 12 | ["scene_info['score']", "x coordinate of platform", "平台的 x 座標"], 13 | ["scene_info['foods']", "list of foods positions", "點點的位置清單"], 14 | ["scene_info", "dictionary of all information", "包含所有資訊的字典"] 15 | ], 16 | "CONSTANT": [ 17 | [0, "left boundary", "左邊界"], 18 | [800, "right boundary", "右邊界"], 19 | [0, "top boundary", "上邊界"], 20 | [600, "bottom boundary", "下邊界"], 21 | [50, "ball width", "球身的寬度"], 22 | [50, "ball height", "球身的高度"], 23 | [8, "food width", "食物的寬度"], 24 | [8, "food height", "食物的高度"] 25 | ], 26 | "ACTION": [ 27 | ["['UP']", "moving up", "向上移動"], 28 | ["['DOWN']", "moving down", "向下移動"], 29 | ["['LEFT']", "moving left", "向左移動"], 30 | ["['RIGHT']", "moving right", "向右移動"], 31 | ["['NONE']", "doing nothing", "不動作"] 32 | 33 | ] 34 | } -------------------------------------------------------------------------------- /js/core/renderers/thrasos/renderer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2019 Google LLC 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | /** 8 | * @fileoverview Thrasos renderer. 9 | * @author fenichel@google.com (Rachel Fenichel) 10 | */ 11 | 'use strict'; 12 | 13 | goog.provide('Blockly.thrasos.Renderer'); 14 | 15 | goog.require('Blockly.blockRendering'); 16 | goog.require('Blockly.blockRendering.Renderer'); 17 | goog.require('Blockly.thrasos.RenderInfo'); 18 | goog.require('Blockly.utils.object'); 19 | 20 | /** 21 | * The thrasos renderer. 22 | * @param {string} name The renderer name. 23 | * @package 24 | * @constructor 25 | * @extends {Blockly.blockRendering.Renderer} 26 | */ 27 | Blockly.thrasos.Renderer = function(name) { 28 | Blockly.thrasos.Renderer.superClass_.constructor.call(this, name); 29 | }; 30 | Blockly.utils.object.inherits(Blockly.thrasos.Renderer, 31 | Blockly.blockRendering.Renderer); 32 | 33 | /** 34 | * Create a new instance of the renderer's render info object. 35 | * @param {!Blockly.BlockSvg} block The block to measure. 36 | * @return {!Blockly.thrasos.RenderInfo} The render info object. 37 | * @protected 38 | * @override 39 | */ 40 | Blockly.thrasos.Renderer.prototype.makeRenderInfo_ = function(block) { 41 | return new Blockly.thrasos.RenderInfo(this, block); 42 | }; 43 | 44 | 45 | Blockly.blockRendering.register('thrasos', Blockly.thrasos.Renderer); 46 | -------------------------------------------------------------------------------- /js/core/utils/size.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2019 Google LLC 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | /** 8 | * @fileoverview Utility methods for size calculation. 9 | * These methods are not specific to Blockly, and could be factored out into 10 | * a JavaScript framework such as Closure. 11 | * @author samelh@google.com (Sam El-Husseini) 12 | */ 13 | 'use strict'; 14 | 15 | /** 16 | * @name Blockly.utils.Size 17 | * @namespace 18 | */ 19 | goog.provide('Blockly.utils.Size'); 20 | 21 | 22 | /** 23 | * Class for representing sizes consisting of a width and height. 24 | * @param {number} width Width. 25 | * @param {number} height Height. 26 | * @struct 27 | * @constructor 28 | */ 29 | Blockly.utils.Size = function(width, height) { 30 | /** 31 | * Width 32 | * @type {number} 33 | */ 34 | this.width = width; 35 | 36 | /** 37 | * Height 38 | * @type {number} 39 | */ 40 | this.height = height; 41 | }; 42 | 43 | /** 44 | * Compares sizes for equality. 45 | * @param {Blockly.utils.Size} a A Size. 46 | * @param {Blockly.utils.Size} b A Size. 47 | * @return {boolean} True iff the sizes have equal widths and equal 48 | * heights, or if both are null. 49 | */ 50 | Blockly.utils.Size.equals = function(a, b) { 51 | if (a == b) { 52 | return true; 53 | } 54 | if (!a || !b) { 55 | return false; 56 | } 57 | return a.width == b.width && a.height == b.height; 58 | }; 59 | -------------------------------------------------------------------------------- /js/game_msg/easy_game.js: -------------------------------------------------------------------------------- 1 | Blockly.Msg["MLPLAY_GAME_STATUS_OPTIONS"] = [ 2 | ["%{BKY_EASY_GAME_GAME_STATUS_1}", "GAME_ALIVE"], 3 | ["%{BKY_EASY_GAME_GAME_STATUS_2}", "GAME_PASS"], 4 | ["%{BKY_EASY_GAME_GAME_STATUS_3}", "GAME_OVER"] 5 | ]; 6 | Blockly.Msg["MLPLAY_GET_INFO_OPTIONS"] = [ 7 | ["%{BKY_EASY_GAME_SCENE_INFO_1}", "scene_info['frame']"], 8 | ["%{BKY_EASY_GAME_SCENE_INFO_2}", "scene_info['status']"], 9 | ["%{BKY_EASY_GAME_SCENE_INFO_3}", "scene_info['ball_x']"], 10 | ["%{BKY_EASY_GAME_SCENE_INFO_4}", "scene_info['ball_y']"], 11 | ["%{BKY_EASY_GAME_SCENE_INFO_5}", "scene_info['score']"], 12 | ["%{BKY_EASY_GAME_SCENE_INFO_6}", "scene_info['foods']"], 13 | ["%{BKY_EASY_GAME_SCENE_INFO_7}", "scene_info"] 14 | ]; 15 | Blockly.Msg["MLPLAY_GET_CONSTANT_OPTIONS"] = [ 16 | ["%{BKY_EASY_GAME_CONSTANT_1}", "1/0"], 17 | ["%{BKY_EASY_GAME_CONSTANT_2}", "2/800"], 18 | ["%{BKY_EASY_GAME_CONSTANT_3}", "3/0"], 19 | ["%{BKY_EASY_GAME_CONSTANT_4}", "4/600"], 20 | ["%{BKY_EASY_GAME_CONSTANT_5}", "5/50"], 21 | ["%{BKY_EASY_GAME_CONSTANT_6}", "6/50"], 22 | ["%{BKY_EASY_GAME_CONSTANT_7}", "7/8"], 23 | ["%{BKY_EASY_GAME_CONSTANT_8}", "8/8"] 24 | ]; 25 | Blockly.Msg["MLPLAY_RETURN_ACTION_OPTIONS"] = [ 26 | ["%{BKY_EASY_GAME_ACTION_1}", "['UP']"], 27 | ["%{BKY_EASY_GAME_ACTION_2}", "['DOWN']"], 28 | ["%{BKY_EASY_GAME_ACTION_3}", "['LEFT']"], 29 | ["%{BKY_EASY_GAME_ACTION_4}", "['RIGHT']"], 30 | ["%{BKY_EASY_GAME_ACTION_5}", "['NONE']"] 31 | ]; 32 | -------------------------------------------------------------------------------- /js/core/renderers/minimalist/info.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2019 Google LLC 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | /** 8 | * @fileoverview Minimalist render info object. 9 | */ 10 | 'use strict'; 11 | 12 | goog.provide('Blockly.minimalist'); 13 | goog.provide('Blockly.minimalist.RenderInfo'); 14 | 15 | goog.require('Blockly.utils.object'); 16 | 17 | 18 | /** 19 | * An object containing all sizing information needed to draw this block. 20 | * 21 | * This measure pass does not propagate changes to the block (although fields 22 | * may choose to rerender when getSize() is called). However, calling it 23 | * repeatedly may be expensive. 24 | * 25 | * @param {!Blockly.minimalist.Renderer} renderer The renderer in use. 26 | * @param {!Blockly.BlockSvg} block The block to measure. 27 | * @constructor 28 | * @package 29 | * @extends {Blockly.blockRendering.RenderInfo} 30 | */ 31 | Blockly.minimalist.RenderInfo = function(renderer, block) { 32 | Blockly.minimalist.RenderInfo.superClass_.constructor.call(this, renderer, block); 33 | 34 | }; 35 | Blockly.utils.object.inherits(Blockly.minimalist.RenderInfo, 36 | Blockly.blockRendering.RenderInfo); 37 | 38 | /** 39 | * Get the block renderer in use. 40 | * @return {!Blockly.minimalist.Renderer} The block renderer in use. 41 | * @package 42 | */ 43 | Blockly.minimalist.RenderInfo.prototype.getRenderer = function() { 44 | return /** @type {!Blockly.minimalist.Renderer} */ (this.renderer_); 45 | }; 46 | -------------------------------------------------------------------------------- /js/core/utils/rect.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2019 Google LLC 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | /** 8 | * @fileoverview Utility methods for rectangle manipulation. 9 | * These methods are not specific to Blockly, and could be factored out into 10 | * a JavaScript framework such as Closure. 11 | * @author fraser@google.com (Neil Fraser) 12 | */ 13 | 'use strict'; 14 | 15 | /** 16 | * @name Blockly.utils.Rect 17 | * @namespace 18 | */ 19 | goog.provide('Blockly.utils.Rect'); 20 | 21 | 22 | /** 23 | * Class for representing rectangular regions. 24 | * @param {number} top Top. 25 | * @param {number} bottom Bottom. 26 | * @param {number} left Left. 27 | * @param {number} right Right. 28 | * @struct 29 | * @constructor 30 | */ 31 | Blockly.utils.Rect = function(top, bottom, left, right) { 32 | /** @type {number} */ 33 | this.top = top; 34 | 35 | /** @type {number} */ 36 | this.bottom = bottom; 37 | 38 | /** @type {number} */ 39 | this.left = left; 40 | 41 | /** @type {number} */ 42 | this.right = right; 43 | }; 44 | 45 | /** 46 | * Tests whether this rectangle contains a x/y coordinate. 47 | * 48 | * @param {number} x The x coordinate to test for containment. 49 | * @param {number} y The y coordinate to test for containment. 50 | * @return {boolean} Whether this rectangle contains given coordinate. 51 | */ 52 | Blockly.utils.Rect.prototype.contains = function(x, y) { 53 | return x >= this.left && x <= this.right && y >= this.top && y <= this.bottom; 54 | }; 55 | -------------------------------------------------------------------------------- /js/core/keyboard_nav/tab_navigate_cursor.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2019 Google LLC 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | /** 8 | * @fileoverview The class representing a cursor that is used to navigate 9 | * between tab navigable fields. 10 | * @author samelh@google.com (Sam El-Husseini) 11 | */ 12 | 'use strict'; 13 | 14 | goog.provide('Blockly.TabNavigateCursor'); 15 | 16 | goog.require('Blockly.ASTNode'); 17 | goog.require('Blockly.BasicCursor'); 18 | goog.require('Blockly.utils.object'); 19 | 20 | 21 | /** 22 | * A cursor for navigating between tab navigable fields. 23 | * @constructor 24 | * @extends {Blockly.BasicCursor} 25 | */ 26 | Blockly.TabNavigateCursor = function() { 27 | Blockly.TabNavigateCursor.superClass_.constructor.call(this); 28 | }; 29 | Blockly.utils.object.inherits(Blockly.TabNavigateCursor, Blockly.BasicCursor); 30 | 31 | /** 32 | * Skip all nodes except for tab navigable fields. 33 | * @param {Blockly.ASTNode} node The AST node to check whether it is valid. 34 | * @return {boolean} True if the node should be visited, false otherwise. 35 | * @override 36 | */ 37 | Blockly.TabNavigateCursor.prototype.validNode_ = function(node) { 38 | var isValid = false; 39 | var type = node && node.getType(); 40 | if (node) { 41 | var location = /** @type {Blockly.Field} */ (node.getLocation()); 42 | if (type == Blockly.ASTNode.types.FIELD && 43 | location && location.isTabNavigable() && location.isClickable()) { 44 | isValid = true; 45 | } 46 | } 47 | return isValid; 48 | }; 49 | -------------------------------------------------------------------------------- /js/mlgame/arkanoid.json: -------------------------------------------------------------------------------- 1 | { 2 | "GAME_STATUS": [ 3 | ["GAME_ALIVE", "alive", "存活"], 4 | ["GAME_PASS", "pass", "通關"], 5 | ["GAME_OVER", "over", "失敗"] 6 | ], 7 | "SCENE_INFO": [ 8 | ["scene_info['frame']", "# frame", "# 幀數"], 9 | ["scene_info['status']", "game status", "遊戲狀態"], 10 | ["scene_info['ball'][0]", "x coordinate of ball", "球的 x 座標"], 11 | ["scene_info['ball'][1]", "y coordinate of ball", "球的 y 座標"], 12 | ["scene_info['platform'][0]", "x coordinate of platform", "平台的 x 座標"], 13 | ["scene_info['platform'][1]", "y coordinate of platform", "平台的 y 座標"], 14 | ["scene_info['bricks']", "list of brick positions", "磚塊的位置清單"], 15 | ["scene_info['hard_bricks']", "list of hard brick positions", "堅硬磚塊的位置清單"], 16 | ["scene_info", "dictionary of all information", "包含所有資訊的字典"] 17 | ], 18 | "CONSTANT": [ 19 | [0, "left boundary", "左邊界"], 20 | [200, "right boundary", "右邊界"], 21 | [0, "top boundary", "上邊界"], 22 | [500, "bottom boundary", "下邊界"], 23 | [40, "platform width", "平台寬度"], 24 | [5, "platform height", "平台高度"], 25 | [25, "brick width", "磚塊寬度"], 26 | [10, "brick height", "磚塊高度"] 27 | ], 28 | "ACTION": [ 29 | ["SERVE_TO_LEFT", "serving left", "向左發球"], 30 | ["SERVE_TO_RIGHT", "serving right", "向右發球"], 31 | ["MOVE_LEFT", "moving left", "向左移動"], 32 | ["MOVE_RIGHT", "moving right", "向右移動"], 33 | ["NONE", "doing nothing", "不動作"], 34 | ["RESET", "reset", "重置"] 35 | ] 36 | } -------------------------------------------------------------------------------- /js/mlgame/maze_car.json: -------------------------------------------------------------------------------- 1 | { 2 | "INIT_INFO": [ 3 | ["player", "player number", "玩家編號"] 4 | ], 5 | "PLAYER_STATUS": [ 6 | ["player1", "1P", "1P"], 7 | ["player2", "2P", "2P"], 8 | ["player3", "3P", "3P"], 9 | ["player4", "4P", "4P"], 10 | ["player5", "5P", "5P"], 11 | ["player6", "6P", "6P"] 12 | ], 13 | "GAME_STATUS": [ 14 | ["GAME_ALIVE", "alive", "存活"], 15 | ["GAME_PASS", "pass", "通關"], 16 | ["GAME_OVER", "over", "失敗"] 17 | ], 18 | "SCENE_INFO": [ 19 | ["scene_info['frame']", "# frame", "# 幀數"], 20 | ["scene_info['status']", "game status", "遊戲狀態"], 21 | ["scene_info['x']", "x position of the car", "車子的 x 座標"], 22 | ["scene_info['y']", "y position of the car", "車子的 y 座標"], 23 | ["scene_info['angle']", "angle of the car", "車子的角度"], 24 | ["scene_info['end']", "end position", "終點位置"], 25 | ["scene_info['R_sensor']", "right sensor value", "右超聲波值"], 26 | ["scene_info['F_sensor']", "front sensor value", "前超聲波值"], 27 | ["scene_info['L_sensor']", "left sensor value", "左超聲波值"], 28 | ["scene_info['R_T_sensor']", "right front sensor value", "右前超聲波值"], 29 | ["scene_info['L_T_sensor']", "left front sensor value", "左前超聲波值"] 30 | ], 31 | "CONSTANT": [ 32 | [0, "left boundary", "左邊界"], 33 | [820, "right boundary", "右邊界"], 34 | [0, "top boundary", "上邊界"], 35 | [520, "bottom boundary", "下邊界"] 36 | ], 37 | "ACTION": [ 38 | ["RESET", "reset", "重置"] 39 | ] 40 | } 41 | -------------------------------------------------------------------------------- /js/core/renderers/zelos/measurables/inputs.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2020 Google LLC 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | /** 8 | * @fileoverview Zelos specific objects representing inputs with connections on 9 | * a rendered block. 10 | * @author samelh@google.com (Sam El-Husseini) 11 | */ 12 | 13 | goog.provide('Blockly.zelos.StatementInput'); 14 | 15 | goog.require('Blockly.blockRendering.StatementInput'); 16 | goog.require('Blockly.utils.object'); 17 | 18 | 19 | /** 20 | * An object containing information about the space a statement input takes up 21 | * during rendering 22 | * @param {!Blockly.blockRendering.ConstantProvider} constants The rendering 23 | * constants provider. 24 | * @param {!Blockly.Input} input The statement input to measure and store 25 | * information for. 26 | * @package 27 | * @constructor 28 | * @extends {Blockly.blockRendering.StatementInput} 29 | */ 30 | Blockly.zelos.StatementInput = function(constants, input) { 31 | Blockly.zelos.StatementInput.superClass_.constructor.call(this, 32 | constants, input); 33 | 34 | if (this.connectedBlock) { 35 | // Find the bottom-most connected block in the stack. 36 | var block = this.connectedBlock; 37 | while (block.getNextBlock()) { 38 | block = block.getNextBlock(); 39 | } 40 | if (!block.nextConnection) { 41 | this.height = this.connectedBlockHeight; 42 | this.connectedBottomNextConnection = true; 43 | } 44 | } 45 | }; 46 | Blockly.utils.object.inherits(Blockly.zelos.StatementInput, 47 | Blockly.blockRendering.StatementInput); 48 | -------------------------------------------------------------------------------- /js/generators/python/ndarrays.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | goog.provide('Blockly.Python.ndarrays'); 4 | 5 | goog.require('Blockly.Python'); 6 | 7 | Blockly.Python['ndarrays_create_with'] = function(block) { 8 | // Create an ndarray of any shape filled with a specific element. 9 | Blockly.Python.definitions_['import_np'] = 'import numpy as np'; 10 | var shape = new Array(block.dimCount_); 11 | for (var i = 0; i < block.dimCount_; i++) { 12 | shape[i] = Blockly.Python.valueToCode(block, 'DIM' + i, 13 | Blockly.Python.ORDER_NONE) || '0'; 14 | } 15 | var fill = Blockly.Python.valueToCode(block, 'FILL', 16 | Blockly.Python.ORDER_NONE) || '0'; 17 | var code = 'np.full((' + shape.join(', ') + '), ' + fill + ')'; 18 | return [code, Blockly.Python.ORDER_ATOMIC]; 19 | }; 20 | 21 | Blockly.Python['ndarrays_create_with_list'] = function(block) { 22 | // Create an ndarray of any shape filled with a specific element. 23 | Blockly.Python.definitions_['import_np'] = 'import numpy as np'; 24 | var list = Blockly.Python.valueToCode(block, 'LIST', 25 | Blockly.Python.ORDER_NONE) || '0'; 26 | var code = 'np.array(' + list + ')'; 27 | return [code, Blockly.Python.ORDER_ATOMIC]; 28 | }; 29 | 30 | Blockly.Python['ndarrays_to_list'] = function(block) { 31 | // Create an ndarray of any shape filled with a specific element. 32 | Blockly.Python.definitions_['import_np'] = 'import numpy as np'; 33 | var array = Blockly.Python.valueToCode(block, 'ARRAY', 34 | Blockly.Python.ORDER_NONE) || '0'; 35 | var code = array + '.tolist()'; 36 | return [code, Blockly.Python.ORDER_ATOMIC]; 37 | }; -------------------------------------------------------------------------------- /js/game_msg/arkanoid.js: -------------------------------------------------------------------------------- 1 | Blockly.Msg["MLPLAY_GAME_STATUS_OPTIONS"] = [ 2 | ["%{BKY_ARKANOID_GAME_STATUS_1}", "GAME_ALIVE"], 3 | ["%{BKY_ARKANOID_GAME_STATUS_2}", "GAME_PASS"], 4 | ["%{BKY_ARKANOID_GAME_STATUS_3}", "GAME_OVER"] 5 | ]; 6 | Blockly.Msg["MLPLAY_GET_INFO_OPTIONS"] = [ 7 | ["%{BKY_ARKANOID_SCENE_INFO_1}", "scene_info['frame']"], 8 | ["%{BKY_ARKANOID_SCENE_INFO_2}", "scene_info['status']"], 9 | ["%{BKY_ARKANOID_SCENE_INFO_3}", "scene_info['ball'][0]"], 10 | ["%{BKY_ARKANOID_SCENE_INFO_4}", "scene_info['ball'][1]"], 11 | ["%{BKY_ARKANOID_SCENE_INFO_5}", "scene_info['platform'][0]"], 12 | ["%{BKY_ARKANOID_SCENE_INFO_6}", "scene_info['platform'][1]"], 13 | ["%{BKY_ARKANOID_SCENE_INFO_7}", "scene_info['bricks']"], 14 | ["%{BKY_ARKANOID_SCENE_INFO_8}", "scene_info['hard_bricks']"], 15 | ["%{BKY_ARKANOID_SCENE_INFO_9}", "scene_info"] 16 | ]; 17 | Blockly.Msg["MLPLAY_GET_CONSTANT_OPTIONS"] = [ 18 | ["%{BKY_ARKANOID_CONSTANT_1}", "1/0"], 19 | ["%{BKY_ARKANOID_CONSTANT_2}", "2/200"], 20 | ["%{BKY_ARKANOID_CONSTANT_3}", "3/0"], 21 | ["%{BKY_ARKANOID_CONSTANT_4}", "4/500"], 22 | ["%{BKY_ARKANOID_CONSTANT_5}", "5/40"], 23 | ["%{BKY_ARKANOID_CONSTANT_6}", "6/5"], 24 | ["%{BKY_ARKANOID_CONSTANT_7}", "7/25"], 25 | ["%{BKY_ARKANOID_CONSTANT_8}", "8/10"] 26 | ]; 27 | Blockly.Msg["MLPLAY_RETURN_ACTION_OPTIONS"] = [ 28 | ["%{BKY_ARKANOID_ACTION_1}", "SERVE_TO_LEFT"], 29 | ["%{BKY_ARKANOID_ACTION_2}", "SERVE_TO_RIGHT"], 30 | ["%{BKY_ARKANOID_ACTION_3}", "MOVE_LEFT"], 31 | ["%{BKY_ARKANOID_ACTION_4}", "MOVE_RIGHT"], 32 | ["%{BKY_ARKANOID_ACTION_5}", "NONE"], 33 | ["%{BKY_ARKANOID_ACTION_6}", "RESET"] 34 | ]; 35 | -------------------------------------------------------------------------------- /js/blocks/plot.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | goog.require('Blockly'); 4 | goog.require('Blockly.Blocks'); 5 | goog.require('Blockly.FieldDropdown'); 6 | goog.require('Blockly.FieldLabel'); 7 | goog.require('Blockly.FieldColour'); 8 | 9 | Blockly.defineBlocksWithJsonArray([ 10 | // Train a model. 11 | { 12 | "type": "plot_plot", 13 | "message0": "%{BKY_PLOT_PLOT}", 14 | "args0": [ 15 | { 16 | "type": "input_value", 17 | "name": "X" 18 | }, 19 | { 20 | "type": "input_value", 21 | "name": "Y" 22 | }, 23 | { 24 | "type": "field_dropdown", 25 | "name": "MARKER", 26 | "options": [ 27 | ["None", ""], 28 | ["\u{25CF}", "."], 29 | ["\u{25B2}", "^"], 30 | ["\u{2605}", "*"] 31 | ] 32 | }, 33 | { 34 | "type": "field_dropdown", 35 | "name": "LINE", 36 | "options": [ 37 | ["None", ""], 38 | ["\u{23AF}\u{23AF}\u{23AF}", "-"], 39 | ["\u{207B}\u{207B}\u{207B}", "--"], 40 | ["\u{2027}\u{2027}\u{2027}\u{2027}\u{2027}", ":"], 41 | ["\u{2012}\u{2027}\u{2012}", "-."] 42 | ] 43 | }, 44 | { 45 | "type": "field_colour", 46 | "name": "COLOR", 47 | "colour": "#1f77b4", 48 | "colourOptions": 49 | ['#1f77b4', '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', 50 | '#8c564b', '#e377c2', '#7f7f7f', '#bcbd22', '#17becf'], 51 | "columns": 5 52 | } 53 | ], 54 | "inputsInline": true, 55 | "previousStatement": null, 56 | "nextStatement": null, 57 | "style": "plot_blocks", 58 | "tooltip": "%{BKY_PLOT_PLOT_TOOLTIP}" 59 | } 60 | ]); -------------------------------------------------------------------------------- /js/core/utils/math.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2019 Google LLC 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | /** 8 | * @fileoverview Utility methods for math. 9 | * These methods are not specific to Blockly, and could be factored out into 10 | * a JavaScript framework such as Closure. 11 | * @author fraser@google.com (Neil Fraser) 12 | */ 13 | 'use strict'; 14 | 15 | /** 16 | * @name Blockly.utils.math 17 | * @namespace 18 | */ 19 | goog.provide('Blockly.utils.math'); 20 | 21 | 22 | /** 23 | * Converts degrees to radians. 24 | * Copied from Closure's goog.math.toRadians. 25 | * @param {number} angleDegrees Angle in degrees. 26 | * @return {number} Angle in radians. 27 | */ 28 | Blockly.utils.math.toRadians = function(angleDegrees) { 29 | return angleDegrees * Math.PI / 180; 30 | }; 31 | 32 | /** 33 | * Converts radians to degrees. 34 | * Copied from Closure's goog.math.toDegrees. 35 | * @param {number} angleRadians Angle in radians. 36 | * @return {number} Angle in degrees. 37 | */ 38 | Blockly.utils.math.toDegrees = function(angleRadians) { 39 | return angleRadians * 180 / Math.PI; 40 | }; 41 | 42 | /** 43 | * Clamp the provided number between the lower bound and the upper bound. 44 | * @param {number} lowerBound The desired lower bound. 45 | * @param {number} number The number to clamp. 46 | * @param {number} upperBound The desired upper bound. 47 | * @return {number} The clamped number. 48 | */ 49 | Blockly.utils.math.clamp = function(lowerBound, number, upperBound) { 50 | if (upperBound < lowerBound) { 51 | var temp = upperBound; 52 | upperBound = lowerBound; 53 | lowerBound = temp; 54 | } 55 | return Math.max(lowerBound, Math.min(number, upperBound)); 56 | }; 57 | -------------------------------------------------------------------------------- /js/ui_msg/en.js: -------------------------------------------------------------------------------- 1 | var MSG = { 2 | title: "Blockly", 3 | blocks: "Blocks", 4 | examples: "Examples", 5 | lang: "Language", 6 | options: "Options", 7 | linkTooltip: "Save and link to blocks.", 8 | runTooltip: "Run the program defined by the blocks in the workspace.", 9 | badCode: "Program error:\n%1", 10 | timeout: "Maximum execution iterations exceeded.", 11 | discard: "Discard all blocks", 12 | download: "Save Python file", 13 | runMLGame: "Play game", 14 | runPython: "Run Python file", 15 | openXml: "Open XML file", 16 | openPython: "Open Python file", 17 | downloadXml: "Save XML file", 18 | en: "English", 19 | zh_hant: "Chinese", 20 | catLogic: "Logic", 21 | catLoops: "Loops", 22 | catMath: "Math", 23 | catText: "Text", 24 | catLists: "Lists", 25 | catDicts: "Dictionaries", 26 | catNdarrays: "Ndarrays", 27 | catColour: "Colour", 28 | catVariables: "Variables", 29 | catFunctions: "Functions", 30 | catFile: "File", 31 | catPlot: "Plot", 32 | catModel: "Model", 33 | listVariable: "list", 34 | ndarrayVariable: "ndarray", 35 | textVariable: "text", 36 | dictVariable: "dictionary", 37 | modelVariable: "model", 38 | objVariable: "object", 39 | filename: "filename", 40 | trainData: "train data", 41 | testData: "test data", 42 | trainTarget: "train target", 43 | testTarget: "test target", 44 | httpRequestError: "There was a problem with the request.", 45 | linkAlert: "Share your blocks with this link:\n\n%1", 46 | hashError: "Sorry, '%1' doesn't correspond with any saved program.", 47 | xmlError: "Could not load your saved file. Perhaps it was created with a different version of Blockly?", 48 | badXml: "Error parsing XML:\n%1\n\nSelect 'OK' to abandon your changes or 'Cancel' to further edit the XML." 49 | }; 50 | -------------------------------------------------------------------------------- /js/game_msg/maze_car.js: -------------------------------------------------------------------------------- 1 | Blockly.Msg["MLPLAY_INIT_INFO_OPTIONS"] = [ 2 | ["%{BKY_MAZE_CAR_INIT_INFO_1}", "player"] 3 | ]; 4 | Blockly.Msg["MLPLAY_PLAYER_STATUS_OPTIONS"] = [ 5 | ["%{BKY_MAZE_CAR_PLAYER_STATUS_1}", "player1"], 6 | ["%{BKY_MAZE_CAR_PLAYER_STATUS_2}", "player2"], 7 | ["%{BKY_MAZE_CAR_PLAYER_STATUS_3}", "player3"], 8 | ["%{BKY_MAZE_CAR_PLAYER_STATUS_4}", "player4"], 9 | ["%{BKY_MAZE_CAR_PLAYER_STATUS_5}", "player5"], 10 | ["%{BKY_MAZE_CAR_PLAYER_STATUS_6}", "player6"] 11 | ]; 12 | Blockly.Msg["MLPLAY_GAME_STATUS_OPTIONS"] = [ 13 | ["%{BKY_MAZE_CAR_GAME_STATUS_1}", "GAME_ALIVE"], 14 | ["%{BKY_MAZE_CAR_GAME_STATUS_2}", "GAME_PASS"], 15 | ["%{BKY_MAZE_CAR_GAME_STATUS_3}", "GAME_OVER"] 16 | ]; 17 | Blockly.Msg["MLPLAY_GET_INFO_OPTIONS"] = [ 18 | ["%{BKY_MAZE_CAR_SCENE_INFO_1}", "scene_info['frame']"], 19 | ["%{BKY_MAZE_CAR_SCENE_INFO_2}", "scene_info['status']"], 20 | ["%{BKY_MAZE_CAR_SCENE_INFO_3}", "scene_info['x']"], 21 | ["%{BKY_MAZE_CAR_SCENE_INFO_4}", "scene_info['y']"], 22 | ["%{BKY_MAZE_CAR_SCENE_INFO_5}", "scene_info['angle']"], 23 | ["%{BKY_MAZE_CAR_SCENE_INFO_6}", "scene_info['end']"], 24 | ["%{BKY_MAZE_CAR_SCENE_INFO_7}", "scene_info['R_sensor']"], 25 | ["%{BKY_MAZE_CAR_SCENE_INFO_8}", "scene_info['F_sensor']"], 26 | ["%{BKY_MAZE_CAR_SCENE_INFO_9}", "scene_info['L_sensor']"], 27 | ["%{BKY_MAZE_CAR_SCENE_INFO_10}", "scene_info['R_T_sensor']"], 28 | ["%{BKY_MAZE_CAR_SCENE_INFO_11}", "scene_info['L_T_sensor']"] 29 | ]; 30 | Blockly.Msg["MLPLAY_GET_CONSTANT_OPTIONS"] = [ 31 | ["%{BKY_MAZE_CAR_CONSTANT_1}", "1/0"], 32 | ["%{BKY_MAZE_CAR_CONSTANT_2}", "2/820"], 33 | ["%{BKY_MAZE_CAR_CONSTANT_3}", "3/0"], 34 | ["%{BKY_MAZE_CAR_CONSTANT_4}", "4/520"] 35 | ]; 36 | Blockly.Msg["MLPLAY_RETURN_ACTION_OPTIONS"] = [ 37 | ["%{BKY_MAZE_CAR_ACTION_1}", "RESET"] 38 | ]; 39 | -------------------------------------------------------------------------------- /js/mlgame/racingcar.json: -------------------------------------------------------------------------------- 1 | { 2 | "GAME_STATUS": [ 3 | ["GAME_ALIVE", "alive", "存活"], 4 | ["GAME_PASS", "pass", "通關"], 5 | ["GAME_OVER", "over", "失敗"] 6 | ], 7 | "SCENE_INFO": [ 8 | ["scene_info['frame']", "# frame", "# 幀數"], 9 | ["scene_info['status']", "game status", "遊戲狀態"], 10 | ["scene_info['id']", "player id", "玩家編號"], 11 | ["scene_info['x']", "x position of player", "玩家的 x 座標"], 12 | ["scene_info['y']", "y position of player", "玩家的 y 座標"], 13 | ["scene_info['distance']", "advanced distance of player", "玩家前進的距離"], 14 | ["scene_info['velocity']", "velocity", "玩家的速度"], 15 | ["scene_info['all_cars_pos']", "positions of all cars", "所有車子的位置"], 16 | ["scene_info['coin']", "positions of coins", "金幣的位置"], 17 | ["scene_info['coin_num']", "number of coins obtained", "獲得的金幣數量"] 18 | ], 19 | "CONSTANT": [ 20 | [0, "left boundary", "左邊界"], 21 | [1000, "right boundary", "右邊界"], 22 | [0, "top boundary", "上邊界"], 23 | [700, "bottom boundary", "下邊界"], 24 | [60, "car length", "車子長度"], 25 | [30, "car width", "車子寬度"], 26 | [30, "coin length", "金幣長度"], 27 | [31, "coin width", "金幣寬度"] 28 | ], 29 | "ACTION": [ 30 | ["['SPEED']", "speed up", "加速"], 31 | ["['BRAKE']", "brake", "減速"], 32 | ["['MOVE_LEFT']", "move left", "向左移動"], 33 | ["['MOVE_RIGHT']", "move left", "向右移動"], 34 | ["['SPEED', 'MOVE_LEFT']", "speed up and move left", "加速並向左移動"], 35 | ["['SPEED', 'MOVE_RIGHT']", "speed up and move right", "加速並向右移動"], 36 | ["['BRAKE', 'MOVE_LEFT']", "brake and move left", "減速並向左移動"], 37 | ["['BRAKE', 'MOVE_RIGHT']", "brake and move right", "減速並向右移動"], 38 | ["RESET", "reset", "重置遊戲"], 39 | ["[]", "do nothing", "不動作"] 40 | ] 41 | } -------------------------------------------------------------------------------- /js/i18n/tests.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | 4 | # Tests of i18n scripts. 5 | # 6 | # Copyright 2013 Google LLC 7 | # 8 | # Licensed under the Apache License, Version 2.0 (the "License"); 9 | # you may not use this file except in compliance with the License. 10 | # You may obtain a copy of the License at 11 | # 12 | # http://www.apache.org/licenses/LICENSE-2.0 13 | # 14 | # Unless required by applicable law or agreed to in writing, software 15 | # distributed under the License is distributed on an "AS IS" BASIS, 16 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | # See the License for the specific language governing permissions and 18 | # limitations under the License. 19 | 20 | import common 21 | import re 22 | import unittest 23 | 24 | class TestSequenceFunctions(unittest.TestCase): 25 | def test_insert_breaks(self): 26 | spaces = re.compile(r'\s+|\\n') 27 | def contains_all_chars(orig, result): 28 | return re.sub(spaces, '', orig) == re.sub(spaces, '', result) 29 | 30 | sentences = [u'Quay Pegman qua bên trái hoặc bên phải 90 độ.', 31 | u'Foo bar baz this is english that is okay bye.', 32 | u'If there is a path in the specified direction, \nthen ' + 33 | u'do some actions.', 34 | u'If there is a path in the specified direction, then do ' + 35 | u'the first block of actions. Otherwise, do the second ' + 36 | u'block of actions.'] 37 | for sentence in sentences: 38 | output = common.insert_breaks(sentence, 30, 50) 39 | self.assertTrue(contains_all_chars(sentence, output), 40 | u'Mismatch between:\n{0}\n{1}'.format( 41 | re.sub(spaces, '', sentence), 42 | re.sub(spaces, '', output))) 43 | 44 | 45 | if __name__ == '__main__': 46 | unittest.main() 47 | -------------------------------------------------------------------------------- /js/generators/python/dicts.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | goog.provide('Blockly.Python.dicts'); 4 | 5 | goog.require('Blockly.Python'); 6 | 7 | Blockly.Python['dicts_get_keys'] = function(block) { 8 | // Get dict keys. 9 | var list = Blockly.Python.valueToCode(block, 'DICT', 10 | Blockly.Python.ORDER_NONE) || '{}'; 11 | return [list + '.keys()', Blockly.Python.ORDER_ATOMIC]; 12 | }; 13 | 14 | 15 | Blockly.Python['dicts_create_with'] = function(block) { 16 | if (block.itemCount_ == 0) { 17 | return ['{}', Blockly.Python.ORDER_ATOMIC]; 18 | } 19 | 20 | var code = new Array(block.itemCount_); 21 | 22 | for (var n = 0; n < block.itemCount_; n++) { 23 | var key = Blockly.Python.valueToCode(block, 'KEY' + n, 24 | Blockly.Python.ORDER_NONE) || 'None'; 25 | var value = Blockly.Python.valueToCode(block, 'VALUE' + n, 26 | Blockly.Python.ORDER_NONE) || 'None'; 27 | code[n] = key +": "+ value; 28 | } 29 | code = '{\n' + Blockly.Python.INDENT + code.join(',\n' + Blockly.Python.INDENT) + '\n}'; 30 | return [code, Blockly.Python.ORDER_ATOMIC]; 31 | }; 32 | 33 | Blockly.Python['dicts_get_value'] = function(block) { 34 | var dict = Blockly.Python.valueToCode(block, 'DICT', 35 | Blockly.Python.ORDER_MEMBER) || '{}'; 36 | var key = Blockly.Python.valueToCode(block, 'KEY', 37 | Blockly.Python.ORDER_NONE) || 'None'; 38 | var code = dict + '[' + key + ']'; 39 | return [code, Blockly.Python.ORDER_ATOMIC]; 40 | }; 41 | 42 | Blockly.Python['dicts_set_value'] = function(block) { 43 | var dict = Blockly.Python.valueToCode(block, 'DICT', 44 | Blockly.Python.ORDER_MEMBER) || '{}'; 45 | var key = Blockly.Python.valueToCode(block, 'KEY', 46 | Blockly.Python.ORDER_NONE) || 'None'; 47 | var value = Blockly.Python.valueToCode(block, 'VALUE', 48 | Blockly.Python.ORDER_NONE) || 'None'; 49 | var code = dict + '[' + key + '] = ' + value + '\n'; 50 | return code; 51 | }; 52 | -------------------------------------------------------------------------------- /js/game_msg/racingcar.js: -------------------------------------------------------------------------------- 1 | Blockly.Msg["MLPLAY_GAME_STATUS_OPTIONS"] = [ 2 | ["%{BKY_RACINGCAR_GAME_STATUS_1}", "GAME_ALIVE"], 3 | ["%{BKY_RACINGCAR_GAME_STATUS_2}", "GAME_PASS"], 4 | ["%{BKY_RACINGCAR_GAME_STATUS_3}", "GAME_OVER"] 5 | ]; 6 | Blockly.Msg["MLPLAY_GET_INFO_OPTIONS"] = [ 7 | ["%{BKY_RACINGCAR_SCENE_INFO_1}", "scene_info['frame']"], 8 | ["%{BKY_RACINGCAR_SCENE_INFO_2}", "scene_info['status']"], 9 | ["%{BKY_RACINGCAR_SCENE_INFO_3}", "scene_info['id']"], 10 | ["%{BKY_RACINGCAR_SCENE_INFO_4}", "scene_info['x']"], 11 | ["%{BKY_RACINGCAR_SCENE_INFO_5}", "scene_info['y']"], 12 | ["%{BKY_RACINGCAR_SCENE_INFO_6}", "scene_info['distance']"], 13 | ["%{BKY_RACINGCAR_SCENE_INFO_7}", "scene_info['velocity']"], 14 | ["%{BKY_RACINGCAR_SCENE_INFO_8}", "scene_info['all_cars_pos']"], 15 | ["%{BKY_RACINGCAR_SCENE_INFO_9}", "scene_info['coin']"], 16 | ["%{BKY_RACINGCAR_SCENE_INFO_10}", "scene_info['coin_num']"] 17 | ]; 18 | Blockly.Msg["MLPLAY_GET_CONSTANT_OPTIONS"] = [ 19 | ["%{BKY_RACINGCAR_CONSTANT_1}", "1/0"], 20 | ["%{BKY_RACINGCAR_CONSTANT_2}", "2/1000"], 21 | ["%{BKY_RACINGCAR_CONSTANT_3}", "3/0"], 22 | ["%{BKY_RACINGCAR_CONSTANT_4}", "4/700"], 23 | ["%{BKY_RACINGCAR_CONSTANT_5}", "5/60"], 24 | ["%{BKY_RACINGCAR_CONSTANT_6}", "6/30"], 25 | ["%{BKY_RACINGCAR_CONSTANT_7}", "7/30"], 26 | ["%{BKY_RACINGCAR_CONSTANT_8}", "8/31"] 27 | ]; 28 | Blockly.Msg["MLPLAY_RETURN_ACTION_OPTIONS"] = [ 29 | ["%{BKY_RACINGCAR_ACTION_1}", "['SPEED']"], 30 | ["%{BKY_RACINGCAR_ACTION_2}", "['BRAKE']"], 31 | ["%{BKY_RACINGCAR_ACTION_3}", "['MOVE_LEFT']"], 32 | ["%{BKY_RACINGCAR_ACTION_4}", "['MOVE_RIGHT']"], 33 | ["%{BKY_RACINGCAR_ACTION_5}", "['SPEED', 'MOVE_LEFT']"], 34 | ["%{BKY_RACINGCAR_ACTION_6}", "['SPEED', 'MOVE_RIGHT']"], 35 | ["%{BKY_RACINGCAR_ACTION_7}", "['BRAKE', 'MOVE_LEFT']"], 36 | ["%{BKY_RACINGCAR_ACTION_8}", "['BRAKE', 'MOVE_RIGHT']"], 37 | ["%{BKY_RACINGCAR_ACTION_9}", "RESET"], 38 | ["%{BKY_RACINGCAR_ACTION_10}", "[]"] 39 | ]; 40 | -------------------------------------------------------------------------------- /js/core/renderers/geras/constants.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2019 Google LLC 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | /** 8 | * @fileoverview An object that provides constants for rendering blocks in Geras 9 | * mode. 10 | * @author kozbial@google.com (Monica Kozbial) 11 | */ 12 | 'use strict'; 13 | 14 | goog.provide('Blockly.geras.ConstantProvider'); 15 | 16 | goog.require('Blockly.blockRendering.ConstantProvider'); 17 | goog.require('Blockly.utils.object'); 18 | 19 | 20 | /** 21 | * An object that provides constants for rendering blocks in Geras mode. 22 | * @constructor 23 | * @package 24 | * @extends {Blockly.blockRendering.ConstantProvider} 25 | */ 26 | Blockly.geras.ConstantProvider = function() { 27 | Blockly.geras.ConstantProvider.superClass_.constructor.call(this); 28 | 29 | /** 30 | * @override 31 | */ 32 | this.FIELD_TEXT_BASELINE_CENTER = false; 33 | 34 | // The dark/shadow path in classic rendering is the same as the normal block 35 | // path, but translated down one and right one. 36 | this.DARK_PATH_OFFSET = 1; 37 | 38 | /** 39 | * The maximum width of a bottom row that follows a statement input and has 40 | * inputs inline. 41 | * @type {number} 42 | */ 43 | this.MAX_BOTTOM_WIDTH = 30; 44 | }; 45 | Blockly.utils.object.inherits(Blockly.geras.ConstantProvider, 46 | Blockly.blockRendering.ConstantProvider); 47 | 48 | 49 | /** 50 | * @override 51 | */ 52 | Blockly.geras.ConstantProvider.prototype.getCSS_ = function(selector) { 53 | return Blockly.geras.ConstantProvider.superClass_.getCSS_.call(this, selector) 54 | .concat([ 55 | /* eslint-disable indent */ 56 | // Insertion marker. 57 | selector + ' .blocklyInsertionMarker>.blocklyPathLight,', 58 | selector + ' .blocklyInsertionMarker>.blocklyPathDark {', 59 | 'fill-opacity: ' + this.INSERTION_MARKER_OPACITY + ';', 60 | 'stroke: none;', 61 | '}', 62 | /* eslint-enable indent */ 63 | ]); 64 | }; 65 | -------------------------------------------------------------------------------- /python/examples/maze_car/2. manual.py: -------------------------------------------------------------------------------- 1 | import pickle 2 | import os 3 | from pynput import keyboard 4 | from collections import defaultdict 5 | 6 | _KEYBOARD_ON_PRESSED = None 7 | 8 | def on_press(key): 9 | _KEYBOARD_ON_PRESSED[str(key)] = True 10 | 11 | def on_release(key): 12 | _KEYBOARD_ON_PRESSED[str(key)] = False 13 | 14 | _KEYBOARD_ON_PRESSED = defaultdict(bool) 15 | listener = keyboard.Listener( 16 | on_press=on_press, 17 | on_release=on_release) 18 | listener.start() 19 | 20 | 21 | class MLPlay: 22 | def __init__(self, player): 23 | self.f_sensor_value = 0 24 | self.r_sensor_value = 0 25 | self.l_sensor_value = 0 26 | self.left_PWM = 0 27 | self.right_PWM = 0 28 | self.feature = [] 29 | self.target = [] 30 | def update(self, scene_info): 31 | if scene_info['status'] != "GAME_PASS": 32 | with open(os.path.join(os.path.dirname(__file__), 'feature.pickle'), 'wb') as f: 33 | pickle.dump(self.feature, f) 34 | with open(os.path.join(os.path.dirname(__file__), 'target.pickle'), 'wb') as f: 35 | pickle.dump(self.target, f) 36 | elif _KEYBOARD_ON_PRESSED["Key.up"]: 37 | self.left_PWM = 150 38 | self.right_PWM = 150 39 | elif _KEYBOARD_ON_PRESSED["Key.right"]: 40 | self.left_PWM = 100 41 | self.right_PWM = -100 42 | elif _KEYBOARD_ON_PRESSED["Key.left"]: 43 | self.left_PWM = -100 44 | self.right_PWM = 100 45 | elif _KEYBOARD_ON_PRESSED["Key.down"]: 46 | self.left_PWM = -150 47 | self.right_PWM = -150 48 | else: 49 | self.left_PWM = 0 50 | self.right_PWM = 0 51 | self.feature.append([scene_info['F_sensor'], scene_info['L_sensor'], scene_info['R_sensor']]) 52 | self.target.append([self.left_PWM, self.right_PWM]) 53 | return [{'left_PWM': self.left_PWM, 'right_PWM': self.right_PWM}] 54 | def reset(self): 55 | pass -------------------------------------------------------------------------------- /python/examples/racingcar/2. manual.py: -------------------------------------------------------------------------------- 1 | from pynput import keyboard 2 | from collections import defaultdict 3 | import pickle 4 | import os 5 | 6 | _KEYBOARD_ON_PRESSED = None 7 | 8 | def on_press(key): 9 | _KEYBOARD_ON_PRESSED[str(key)] = True 10 | 11 | def on_release(key): 12 | _KEYBOARD_ON_PRESSED[str(key)] = False 13 | 14 | _KEYBOARD_ON_PRESSED = defaultdict(bool) 15 | listener = keyboard.Listener( 16 | on_press=on_press, 17 | on_release=on_release) 18 | listener.start() 19 | 20 | class MLPlay: 21 | def __init__(self, player): 22 | self.player = player 23 | self.other_cars_position = [] 24 | self.player_car_position = [] 25 | self.action = [] 26 | def update(self, scene_info): 27 | if scene_info['status'] == "RUNNING": 28 | if _KEYBOARD_ON_PRESSED["Key.right"]: 29 | self.player_car_position.append([scene_info['x'], scene_info['y']]) 30 | self.action.append(1) 31 | return ['SPEED'] 32 | elif _KEYBOARD_ON_PRESSED["Key.left"]: 33 | self.player_car_position.append([scene_info['x'], scene_info['y']]) 34 | self.action.append(2) 35 | return ['BRAKE'] 36 | elif _KEYBOARD_ON_PRESSED["Key.up"]: 37 | self.player_car_position.append([scene_info['x'], scene_info['y']]) 38 | self.action.append(3) 39 | return ['MOVE_LEFT'] 40 | elif _KEYBOARD_ON_PRESSED["Key.down"]: 41 | self.player_car_position.append([scene_info['x'], scene_info['y']]) 42 | self.action.append(4) 43 | return ['MOVE_RIGHT'] 44 | elif scene_info['status'] == "END": 45 | with open(os.path.join(os.path.dirname(__file__), 'feature.pickle'), 'wb') as f: 46 | pickle.dump(self.player_car_position, f) 47 | with open(os.path.join(os.path.dirname(__file__), 'target.pickle'), 'wb') as f: 48 | pickle.dump(self.action, f) 49 | def reset(self): 50 | pass -------------------------------------------------------------------------------- /python/examples/arkanoid/2. manual.py: -------------------------------------------------------------------------------- 1 | import pickle 2 | import os 3 | from pynput import keyboard 4 | from collections import defaultdict 5 | 6 | _KEYBOARD_ON_PRESSED = None 7 | 8 | def on_press(key): 9 | _KEYBOARD_ON_PRESSED[str(key)] = True 10 | 11 | def on_release(key): 12 | _KEYBOARD_ON_PRESSED[str(key)] = False 13 | 14 | _KEYBOARD_ON_PRESSED = defaultdict(bool) 15 | listener = keyboard.Listener( 16 | on_press=on_press, 17 | on_release=on_release) 18 | listener.start() 19 | 20 | 21 | class MLPlay: 22 | def __init__(self): 23 | self.ball_served = False 24 | self.actions = [] 25 | self.positions = [] 26 | def update(self, scene_info): 27 | if scene_info['status'] == "GAME_PASS" or scene_info['status'] == "GAME_OVER": 28 | with open(os.path.join(os.path.dirname(__file__), 'target.pickle'), 'wb') as f: 29 | pickle.dump(self.actions, f) 30 | with open(os.path.join(os.path.dirname(__file__), 'feature.pickle'), 'wb') as f: 31 | pickle.dump(self.positions, f) 32 | return "RESET" 33 | if not self.ball_served: 34 | if (_KEYBOARD_ON_PRESSED["'A'"] or _KEYBOARD_ON_PRESSED["'a'"]): 35 | self.ball_served = True 36 | return "SERVE_TO_LEFT" 37 | elif (_KEYBOARD_ON_PRESSED["'D'"] or _KEYBOARD_ON_PRESSED["'d'"]): 38 | self.ball_served = True 39 | return "SERVE_TO_RIGHT" 40 | else: 41 | if _KEYBOARD_ON_PRESSED["Key.left"]: 42 | self.ball_served = True 43 | self.positions.append([scene_info['ball'][0], scene_info['ball'][1]]) 44 | self.actions.append(1) 45 | return "MOVE_LEFT" 46 | elif _KEYBOARD_ON_PRESSED["Key.right"]: 47 | self.ball_served = True 48 | self.positions.append([scene_info['ball'][0], scene_info['ball'][1]]) 49 | self.actions.append(0) 50 | return "MOVE_RIGHT" 51 | def reset(self): 52 | self.ball_served = False -------------------------------------------------------------------------------- /media/sprites.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /js/core/interfaces/i_accessibility.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2020 Google LLC 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | /** 8 | * @fileoverview AST Node and keyboard navigation interfaces. 9 | * @author samelh@google.com (Sam El-Husseini) 10 | */ 11 | 12 | 'use strict'; 13 | 14 | goog.provide('Blockly.IASTNodeLocation'); 15 | goog.provide('Blockly.IASTNodeLocationSvg'); 16 | goog.provide('Blockly.IASTNodeLocationWithBlock'); 17 | goog.provide('Blockly.IBlocklyActionable'); 18 | 19 | /** 20 | * An AST node location interface. 21 | * @interface 22 | */ 23 | Blockly.IASTNodeLocation = function() {}; 24 | 25 | /** 26 | * An AST node location SVG interface. 27 | * @interface 28 | * @extends {Blockly.IASTNodeLocation} 29 | */ 30 | Blockly.IASTNodeLocationSvg = function() {}; 31 | 32 | /** 33 | * Add the marker svg to this node's svg group. 34 | * @param {SVGElement} markerSvg The svg root of the marker to be added to the 35 | * svg group. 36 | */ 37 | Blockly.IASTNodeLocationSvg.prototype.setMarkerSvg; 38 | 39 | /** 40 | * Add the cursor svg to this node's svg group. 41 | * @param {SVGElement} cursorSvg The svg root of the cursor to be added to the 42 | * svg group. 43 | */ 44 | Blockly.IASTNodeLocationSvg.prototype.setCursorSvg; 45 | 46 | /** 47 | * An AST node location that has an associated block. 48 | * @interface 49 | * @extends {Blockly.IASTNodeLocation} 50 | */ 51 | Blockly.IASTNodeLocationWithBlock = function() {}; 52 | 53 | /** 54 | * Get the source block associated with this node. 55 | * @return {Blockly.Block} The source block. 56 | */ 57 | Blockly.IASTNodeLocationWithBlock.prototype.getSourceBlock; 58 | 59 | 60 | /** 61 | * An interface for an object that handles Blockly actions when keyboard 62 | * navigation is enabled. 63 | * @interface 64 | */ 65 | Blockly.IBlocklyActionable = function() {}; 66 | 67 | /** 68 | * Handles the given action. 69 | * @param {!Blockly.Action} action The action to be handled. 70 | * @return {boolean} True if the action has been handled, false otherwise. 71 | */ 72 | Blockly.IBlocklyActionable.prototype.onBlocklyAction; 73 | -------------------------------------------------------------------------------- /js/mlgame/pingpong.json: -------------------------------------------------------------------------------- 1 | { 2 | "INIT_INFO": [ 3 | ["side", "player number", "玩家編號"] 4 | ], 5 | "PLAYER_STATUS": [ 6 | ["1P", "1P", "1P"], 7 | ["2P", "2P", "2P"] 8 | ], 9 | "GAME_STATUS": [ 10 | ["GAME_ALIVE", "alive", "存活"], 11 | ["GAME_1P_WIN", "1P wins", "1P 勝利"], 12 | ["GAME_2P_WIN", "2P wins", "2P 勝利"], 13 | ["GAME_DRAW", "draw", "平手"] 14 | ], 15 | "SCENE_INFO": [ 16 | ["scene_info['frame']", "# frame", "# 幀數"], 17 | ["scene_info['status']", "game status", "遊戲狀態"], 18 | ["scene_info['ball'][0]", "x coordinate of ball", "球的 x 座標"], 19 | ["scene_info['ball'][1]", "y coordinate of ball", "球的 y 座標"], 20 | ["scene_info['ball_speed'][0]", "ball velocity along x-axis", "球的 x 方向速度"], 21 | ["scene_info['ball_speed'][1]", "ball velocity along y-axis", "球的 y 方向速度"], 22 | ["scene_info['platform_1P'][0]", "x coordinate of 1P platform", "1P 平台的 x 座標"], 23 | ["scene_info['platform_1P'][1]", "y coordinate of 1P platform", "1P 平台的 y 座標"], 24 | ["scene_info['platform_2P'][0]", "x coordinate of 2P platform", "2P 平台的 x 座標"], 25 | ["scene_info['platform_2P'][1]", "y coordinate of 2P platform", "2P 平台的 y 座標"], 26 | ["scene_info['blocker'][0]", "x coordinate of blocker position", "障礙物的 x 座標"], 27 | ["scene_info['blocker'][1]", "y coordinate of blocker position", "障礙物的 y 座標"], 28 | ["scene_info", "dictionary of all information", "包含所有資訊的字典"] 29 | ], 30 | "CONSTANT": [ 31 | [0, "left boundary", "左邊界"], 32 | [200, "right boundary", "右邊界"], 33 | [0, "top boundary", "上邊界"], 34 | [500, "bottom boundary", "下邊界"], 35 | [40, "platform width", "平台寬度"], 36 | [30, "platform height", "平台高度"], 37 | [30, "blocker width", "障礙物寬度"], 38 | [20, "blocker height", "障礙物高度"] 39 | ], 40 | "ACTION": [ 41 | ["SERVE_TO_LEFT", "serving left", "向左發球"], 42 | ["SERVE_TO_RIGHT", "serving right", "向右發球"], 43 | ["MOVE_LEFT", "moving left", "向左移動"], 44 | ["MOVE_RIGHT", "moving right", "向右移動"], 45 | ["NONE", "doing nothing", "不動作"], 46 | ["RESET", "reset", "重置"] 47 | ] 48 | } -------------------------------------------------------------------------------- /js/game_msg/pingpong.js: -------------------------------------------------------------------------------- 1 | Blockly.Msg["MLPLAY_INIT_INFO_OPTIONS"] = [ 2 | ["%{BKY_PINGPONG_INIT_INFO_1}", "side"] 3 | ]; 4 | Blockly.Msg["MLPLAY_PLAYER_STATUS_OPTIONS"] = [ 5 | ["%{BKY_PINGPONG_PLAYER_STATUS_1}", "1P"], 6 | ["%{BKY_PINGPONG_PLAYER_STATUS_2}", "2P"] 7 | ]; 8 | Blockly.Msg["MLPLAY_GAME_STATUS_OPTIONS"] = [ 9 | ["%{BKY_PINGPONG_GAME_STATUS_1}", "GAME_ALIVE"], 10 | ["%{BKY_PINGPONG_GAME_STATUS_2}", "GAME_1P_WIN"], 11 | ["%{BKY_PINGPONG_GAME_STATUS_3}", "GAME_2P_WIN"], 12 | ["%{BKY_PINGPONG_GAME_STATUS_4}", "GAME_DRAW"] 13 | ]; 14 | Blockly.Msg["MLPLAY_GET_INFO_OPTIONS"] = [ 15 | ["%{BKY_PINGPONG_SCENE_INFO_1}", "scene_info['frame']"], 16 | ["%{BKY_PINGPONG_SCENE_INFO_2}", "scene_info['status']"], 17 | ["%{BKY_PINGPONG_SCENE_INFO_3}", "scene_info['ball'][0]"], 18 | ["%{BKY_PINGPONG_SCENE_INFO_4}", "scene_info['ball'][1]"], 19 | ["%{BKY_PINGPONG_SCENE_INFO_5}", "scene_info['ball_speed'][0]"], 20 | ["%{BKY_PINGPONG_SCENE_INFO_6}", "scene_info['ball_speed'][1]"], 21 | ["%{BKY_PINGPONG_SCENE_INFO_7}", "scene_info['platform_1P'][0]"], 22 | ["%{BKY_PINGPONG_SCENE_INFO_8}", "scene_info['platform_1P'][1]"], 23 | ["%{BKY_PINGPONG_SCENE_INFO_9}", "scene_info['platform_2P'][0]"], 24 | ["%{BKY_PINGPONG_SCENE_INFO_10}", "scene_info['platform_2P'][1]"], 25 | ["%{BKY_PINGPONG_SCENE_INFO_11}", "scene_info['blocker'][0]"], 26 | ["%{BKY_PINGPONG_SCENE_INFO_12}", "scene_info['blocker'][1]"], 27 | ["%{BKY_PINGPONG_SCENE_INFO_13}", "scene_info"] 28 | ]; 29 | Blockly.Msg["MLPLAY_GET_CONSTANT_OPTIONS"] = [ 30 | ["%{BKY_PINGPONG_CONSTANT_1}", "1/0"], 31 | ["%{BKY_PINGPONG_CONSTANT_2}", "2/200"], 32 | ["%{BKY_PINGPONG_CONSTANT_3}", "3/0"], 33 | ["%{BKY_PINGPONG_CONSTANT_4}", "4/500"], 34 | ["%{BKY_PINGPONG_CONSTANT_5}", "5/40"], 35 | ["%{BKY_PINGPONG_CONSTANT_6}", "6/30"], 36 | ["%{BKY_PINGPONG_CONSTANT_7}", "7/30"], 37 | ["%{BKY_PINGPONG_CONSTANT_8}", "8/20"] 38 | ]; 39 | Blockly.Msg["MLPLAY_RETURN_ACTION_OPTIONS"] = [ 40 | ["%{BKY_PINGPONG_ACTION_1}", "SERVE_TO_LEFT"], 41 | ["%{BKY_PINGPONG_ACTION_2}", "SERVE_TO_RIGHT"], 42 | ["%{BKY_PINGPONG_ACTION_3}", "MOVE_LEFT"], 43 | ["%{BKY_PINGPONG_ACTION_4}", "MOVE_RIGHT"], 44 | ["%{BKY_PINGPONG_ACTION_5}", "NONE"], 45 | ["%{BKY_PINGPONG_ACTION_6}", "RESET"] 46 | ]; 47 | -------------------------------------------------------------------------------- /js/core/utils/object.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2019 Google LLC 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | /** 8 | * @fileoverview Utility methods for objects. 9 | * @author samelh@google.com (Sam El-Husseini) 10 | */ 11 | 'use strict'; 12 | 13 | goog.provide('Blockly.utils.object'); 14 | 15 | 16 | /** 17 | * Inherit the prototype methods from one constructor into another. 18 | * 19 | * @param {!Function} childCtor Child class. 20 | * @param {!Function} parentCtor Parent class. 21 | * @suppress {strictMissingProperties} superClass_ is not defined on Function. 22 | */ 23 | Blockly.utils.object.inherits = function(childCtor, parentCtor) { 24 | childCtor.superClass_ = parentCtor.prototype; 25 | childCtor.prototype = Object.create(parentCtor.prototype); 26 | childCtor.prototype.constructor = childCtor; 27 | }; 28 | 29 | /** 30 | * Copies all the members of a source object to a target object. 31 | * @param {!Object} target Target. 32 | * @param {!Object} source Source. 33 | */ 34 | Blockly.utils.object.mixin = function(target, source) { 35 | for (var x in source) { 36 | target[x] = source[x]; 37 | } 38 | }; 39 | 40 | /** 41 | * Complete a deep merge of all members of a source object with a target object. 42 | * @param {!Object} target Target. 43 | * @param {!Object} source Source. 44 | * @return {!Object} The resulting object. 45 | */ 46 | Blockly.utils.object.deepMerge = function(target, source) { 47 | for (var x in source) { 48 | if (source[x] != null && typeof source[x] === 'object') { 49 | target[x] = Blockly.utils.object.deepMerge( 50 | target[x] || Object.create(null), source[x]); 51 | } else { 52 | target[x] = source[x]; 53 | } 54 | } 55 | return target; 56 | }; 57 | 58 | /** 59 | * Returns an array of a given object's own enumerable property values. 60 | * @param {!Object} obj Object containing values. 61 | * @return {!Array} Array of values. 62 | */ 63 | Blockly.utils.object.values = function(obj) { 64 | if (Object.values) { 65 | /* eslint-disable es5/no-es6-methods */ 66 | return Object.values(obj); 67 | /* eslint-enable es5/no-es6-methods */ 68 | } 69 | // Fallback for IE. 70 | return Object.keys(obj).map(function(e) { 71 | return obj[e]; 72 | }); 73 | }; 74 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | | :warning: WARNING | 2 | | :---------------- | 3 | | Blockly-App is deprecated after version 1.2.6. The latest version will continue to be released under the name [PAIA-Desktop](https://github.com/PAIA-Playful-AI-Arena/Paia-Desktop). | 4 | 5 | # Blockly-App 6 | 7 | Blockly-App is a visual programming editor based on Blockly, and built on Electron. We designed it to make everyone can easily build AI to play games. 8 | 9 | ## Downloads 10 | 11 | Pre-built installers of latest release can be downloaded from the links below. 12 | 13 | #### Windows 64-bit 14 | 15 | [![](https://img.shields.io/badge/EXE%20Installer-v1.2.6-red)](https://github.com/jason53415/blockly-app/releases/download/v1.2.6/blockly-app-1.2.6.Setup.exe) [![](https://img.shields.io/badge/ZIP%20Portable-v1.2.6-red)](https://github.com/jason53415/blockly-app/releases/download/v1.2.6/blockly-app-win32-x64-1.2.6.zip) 16 | #### macOS 64-bit 17 | 18 | [![](https://img.shields.io/badge/DMG%20Installer-v1.2.6-blue)](https://github.com/jason53415/blockly-app/releases/download/v1.2.6/blockly-app-1.2.6.dmg) [![](https://img.shields.io/badge/ZIP%20Portable-v1.2.6-blue)](https://github.com/jason53415/blockly-app/releases/download/v1.2.6/blockly-app-darwin-x64-1.2.6.zip) 19 | 20 | #### Linux 64-bit 21 | 22 | [![](https://img.shields.io/badge/DEB%20Installer-v1.2.6-green)](https://github.com/jason53415/blockly-app/releases/download/v1.2.6/blockly-app-1.2.6.deb) [![](https://img.shields.io/badge/RPM%20Installer-v1.2.6-green)](https://github.com/jason53415/blockly-app/releases/download/v1.2.6/blockly-app-1.2.6.rpm) 23 | 24 | ## Building 25 | 26 | To build Blockly-App from source you'll need [Git](https://git-scm.com), [Python 3.6+](https://www.python.org/) and [Node.js](https://nodejs.org/en/download/) (which comes with [npm](http://npmjs.com)) installed on your computer. From your command line: 27 | 28 | ```bash 29 | # Clone this repository 30 | git clone --recursive https://github.com/jason53415/blockly-app.git 31 | # Go into the repository 32 | cd blockly-app 33 | # Install Python dependencies 34 | pip install -r requirements.txt 35 | # Install Node.js dependencies 36 | npm install 37 | # Build Python executable 38 | npm run make-py 39 | # Build Blockly-App executable 40 | npm run make 41 | ``` 42 | The built executables can be found in the `out` directory. -------------------------------------------------------------------------------- /js/core/utils/xml.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2018 Google LLC 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | /** 8 | * @fileoverview XML element manipulation. 9 | * These methods are not specific to Blockly, and could be factored out into 10 | * a JavaScript framework such as Closure. 11 | * @author fraser@google.com (Neil Fraser) 12 | */ 13 | 'use strict'; 14 | 15 | /** 16 | * @name Blockly.utils.xml 17 | * @namespace 18 | */ 19 | goog.provide('Blockly.utils.xml'); 20 | 21 | /** 22 | * Namespace for Blockly's XML. 23 | */ 24 | Blockly.utils.xml.NAME_SPACE = 'https://developers.google.com/blockly/xml'; 25 | 26 | /** 27 | * Get the document object. This method is overridden in the Node.js build of 28 | * Blockly. See gulpfile.js, package-blockly-node task. 29 | * @return {!Document} The document object. 30 | * @public 31 | */ 32 | Blockly.utils.xml.document = function() { 33 | return document; 34 | }; 35 | 36 | /** 37 | * Create DOM element for XML. 38 | * @param {string} tagName Name of DOM element. 39 | * @return {!Element} New DOM element. 40 | * @public 41 | */ 42 | Blockly.utils.xml.createElement = function(tagName) { 43 | return Blockly.utils.xml.document().createElementNS( 44 | Blockly.utils.xml.NAME_SPACE, tagName); 45 | }; 46 | 47 | /** 48 | * Create text element for XML. 49 | * @param {string} text Text content. 50 | * @return {!Text} New DOM text node. 51 | * @public 52 | */ 53 | Blockly.utils.xml.createTextNode = function(text) { 54 | return Blockly.utils.xml.document().createTextNode(text); 55 | }; 56 | 57 | /** 58 | * Converts an XML string into a DOM tree. 59 | * @param {string} text XML string. 60 | * @return {Document} The DOM document. 61 | * @throws if XML doesn't parse. 62 | * @public 63 | */ 64 | Blockly.utils.xml.textToDomDocument = function(text) { 65 | var oParser = new DOMParser(); 66 | return oParser.parseFromString(text, 'text/xml'); 67 | }; 68 | 69 | /** 70 | * Converts a DOM structure into plain text. 71 | * Currently the text format is fairly ugly: all one line with no whitespace. 72 | * @param {!Node} dom A tree of XML nodes. 73 | * @return {string} Text representation. 74 | * @public 75 | */ 76 | Blockly.utils.xml.domToText = function(dom) { 77 | var oSerializer = new XMLSerializer(); 78 | return oSerializer.serializeToString(dom); 79 | }; 80 | -------------------------------------------------------------------------------- /js/core/workspace_events.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2019 Google LLC 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | /** 8 | * @fileoverview Class for a finished loading workspace event. 9 | * @author BeksOmega 10 | */ 11 | 'use strict'; 12 | 13 | goog.provide('Blockly.Events.FinishedLoading'); 14 | 15 | goog.require('Blockly.Events'); 16 | goog.require('Blockly.Events.Ui'); 17 | goog.require('Blockly.utils.object'); 18 | 19 | 20 | /** 21 | * Class for a finished loading event. 22 | * Used to notify the developer when the workspace has finished loading (i.e 23 | * domToWorkspace). 24 | * Finished loading events do not record undo or redo. 25 | * @param {!Blockly.Workspace} workspace The workspace that has finished 26 | * loading. 27 | * @extends {Blockly.Events.Abstract} 28 | * @constructor 29 | */ 30 | Blockly.Events.FinishedLoading = function(workspace) { 31 | /** 32 | * The workspace identifier for this event. 33 | * @type {string} 34 | */ 35 | this.workspaceId = workspace.id; 36 | 37 | /** 38 | * The event group ID for the group this event belongs to. Groups define 39 | * events that should be treated as an single action from the user's 40 | * perspective, and should be undone together. 41 | * @type {string} 42 | */ 43 | this.group = Blockly.Events.getGroup(); 44 | 45 | // Workspace events do not undo or redo. 46 | this.recordUndo = false; 47 | }; 48 | Blockly.utils.object.inherits(Blockly.Events.FinishedLoading, 49 | Blockly.Events.Ui); 50 | 51 | /** 52 | * Type of this event. 53 | * @type {string} 54 | */ 55 | Blockly.Events.FinishedLoading.prototype.type = Blockly.Events.FINISHED_LOADING; 56 | 57 | /** 58 | * Encode the event as JSON. 59 | * @return {!Object} JSON representation. 60 | */ 61 | Blockly.Events.FinishedLoading.prototype.toJson = function() { 62 | var json = { 63 | 'type': this.type, 64 | }; 65 | if (this.group) { 66 | json['group'] = this.group; 67 | } 68 | if (this.workspaceId) { 69 | json['workspaceId'] = this.workspaceId; 70 | } 71 | return json; 72 | }; 73 | 74 | /** 75 | * Decode the JSON event. 76 | * @param {!Object} json JSON representation. 77 | */ 78 | Blockly.Events.FinishedLoading.prototype.fromJson = function(json) { 79 | this.workspaceId = json['workspaceId']; 80 | this.group = json['group']; 81 | }; 82 | -------------------------------------------------------------------------------- /python/examples/pingpong/2. manual.py: -------------------------------------------------------------------------------- 1 | import pickle 2 | import os 3 | from pynput import keyboard 4 | from collections import defaultdict 5 | 6 | _KEYBOARD_ON_PRESSED = None 7 | 8 | def on_press(key): 9 | _KEYBOARD_ON_PRESSED[str(key)] = True 10 | 11 | def on_release(key): 12 | _KEYBOARD_ON_PRESSED[str(key)] = False 13 | 14 | _KEYBOARD_ON_PRESSED = defaultdict(bool) 15 | listener = keyboard.Listener( 16 | on_press=on_press, 17 | on_release=on_release) 18 | listener.start() 19 | 20 | class MLPlay: 21 | def __init__(self, side): 22 | self.ball_served = False 23 | self.side = side 24 | self.action = [] 25 | self.ball_position = [] 26 | def update(self, scene_info): 27 | if self.side == '1P': 28 | if scene_info['status'] != "GAME_ALIVE": 29 | with open(os.path.join(os.path.dirname(__file__), 'feature.pickle'), 'wb') as f: 30 | pickle.dump(self.ball_position, f) 31 | with open(os.path.join(os.path.dirname(__file__), 'target.pickle'), 'wb') as f: 32 | pickle.dump(self.action, f) 33 | return "RESET" 34 | if not self.ball_served: 35 | self.ball_served = True 36 | return "SERVE_TO_LEFT" 37 | else: 38 | if _KEYBOARD_ON_PRESSED["Key.left"]: 39 | self.ball_position.append([scene_info['ball_speed'][0], scene_info['ball_speed'][1]]) 40 | self.action.append(1) 41 | return "MOVE_LEFT" 42 | elif _KEYBOARD_ON_PRESSED["Key.right"]: 43 | self.ball_position.append([scene_info['ball_speed'][0], scene_info['ball_speed'][1]]) 44 | self.action.append(0) 45 | return "MOVE_RIGHT" 46 | else: 47 | if scene_info['status'] != "GAME_ALIVE": 48 | return "RESET" 49 | if not self.ball_served: 50 | self.ball_served = True 51 | return "SERVE_TO_LEFT" 52 | else: 53 | if (_KEYBOARD_ON_PRESSED["'A'"] or _KEYBOARD_ON_PRESSED["'a'"]): 54 | return "MOVE_LEFT" 55 | elif (_KEYBOARD_ON_PRESSED["'D'"] or _KEYBOARD_ON_PRESSED["'d'"]): 56 | return "MOVE_RIGHT" 57 | def reset(self): 58 | self.ball_served = False -------------------------------------------------------------------------------- /renderer.js: -------------------------------------------------------------------------------- 1 | // This file is required by the index.html file and will 2 | // be executed in the renderer process for that window. 3 | // No Node.js APIs are available in this process because 4 | // `nodeIntegration` is turned off. Use `preload.js` to 5 | // selectively enable features needed in the rendering 6 | // process. 7 | const { dialog, shell } = require('electron').remote; 8 | const { PythonShell } = require('python-shell'); 9 | const buffer = require('buffer'); 10 | const Store = require('electron-store'); 11 | const store = new Store(); 12 | const path = require('path'); 13 | const fs = require('fs'); 14 | 15 | window.pythonRun = function(options, script, tmp_file, cwd) { 16 | var old_cwd = process.cwd(); 17 | process.chdir(cwd); 18 | let python = new PythonShell(script, options); 19 | python.on('message', function (message) { 20 | var full_message = document.getElementById('content_console').textContent + message + '\n'; 21 | document.getElementById('content_console').textContent = full_message.slice(-5000); 22 | var e = document.getElementById('console-body'); 23 | e.scrollTo(0, e.scrollHeight); 24 | }); 25 | python.on('stderr', function (stderr) { 26 | document.getElementById('content_console').textContent += stderr + '\n'; 27 | var e = document.getElementById('console-body'); 28 | e.scrollTo(0, e.scrollHeight); 29 | }); 30 | python.on('close', function () { 31 | document.getElementById('content_console').textContent += '> Python program finished\n'; 32 | var e = document.getElementById('console-body'); 33 | e.scrollTo(0, e.scrollHeight); 34 | fs.unlinkSync(tmp_file); 35 | process.chdir(old_cwd); 36 | }); 37 | python.on('error', function () { 38 | window.alert('Error: process exited with code ' + python.exitCode); 39 | }); 40 | }; 41 | 42 | window.writeFile = function(file, data) { 43 | fs.writeFileSync(file, data, (err) => { 44 | if (err) window.alert(err); 45 | console.log('The file has been saved at ' + file); 46 | }); 47 | }; 48 | 49 | window.readFile = function(file) { 50 | return fs.readFileSync(file, 'utf8', (err, data) => { 51 | if (err) window.alert(err); 52 | return data; 53 | }); 54 | }; 55 | 56 | window.selectPath = function(options) { 57 | return dialog.showOpenDialogSync(options); 58 | }; 59 | 60 | window.openPath = function(pathname) { 61 | shell.openPath(pathname); 62 | }; 63 | -------------------------------------------------------------------------------- /js/core/renderers/minimalist/renderer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2019 Google LLC 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | /** 8 | * @fileoverview Minimalist renderer. 9 | */ 10 | 'use strict'; 11 | 12 | goog.provide('Blockly.minimalist.Renderer'); 13 | 14 | goog.require('Blockly.blockRendering'); 15 | goog.require('Blockly.blockRendering.Renderer'); 16 | goog.require('Blockly.utils.object'); 17 | goog.require('Blockly.minimalist.ConstantProvider'); 18 | goog.require('Blockly.minimalist.Drawer'); 19 | goog.require('Blockly.minimalist.RenderInfo'); 20 | 21 | 22 | /** 23 | * The minimalist renderer. 24 | * @param {string} name The renderer name. 25 | * @package 26 | * @constructor 27 | * @extends {Blockly.blockRendering.Renderer} 28 | */ 29 | Blockly.minimalist.Renderer = function(name) { 30 | Blockly.minimalist.Renderer.superClass_.constructor.call(this, name); 31 | }; 32 | Blockly.utils.object.inherits(Blockly.minimalist.Renderer, 33 | Blockly.blockRendering.Renderer); 34 | 35 | /** 36 | * Create a new instance of the renderer's constant provider. 37 | * @return {!Blockly.minimalist.ConstantProvider} The constant provider. 38 | * @protected 39 | * @override 40 | */ 41 | Blockly.minimalist.Renderer.prototype.makeConstants_ = function() { 42 | return new Blockly.minimalist.ConstantProvider(); 43 | }; 44 | 45 | /** 46 | * Create a new instance of the renderer's render info object. 47 | * @param {!Blockly.BlockSvg} block The block to measure. 48 | * @return {!Blockly.minimalist.RenderInfo} The render info object. 49 | * @protected 50 | * @override 51 | */ 52 | Blockly.minimalist.Renderer.prototype.makeRenderInfo_ = function(block) { 53 | return new Blockly.minimalist.RenderInfo(this, block); 54 | }; 55 | 56 | /** 57 | * Create a new instance of the renderer's drawer. 58 | * @param {!Blockly.BlockSvg} block The block to render. 59 | * @param {!Blockly.blockRendering.RenderInfo} info An object containing all 60 | * information needed to render this block. 61 | * @return {!Blockly.minimalist.Drawer} The drawer. 62 | * @protected 63 | * @override 64 | */ 65 | Blockly.minimalist.Renderer.prototype.makeDrawer_ = function(block, info) { 66 | return new Blockly.minimalist.Drawer(block, 67 | /** @type {!Blockly.minimalist.RenderInfo} */ (info)); 68 | }; 69 | 70 | Blockly.blockRendering.register('minimalist', Blockly.minimalist.Renderer); 71 | -------------------------------------------------------------------------------- /js/core/theme/classic.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2018 Google LLC 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | /** 8 | * @fileoverview Classic theme. 9 | * Contains multi-coloured border to create shadow effect. 10 | */ 11 | 'use strict'; 12 | 13 | goog.provide('Blockly.Themes.Classic'); 14 | 15 | goog.require('Blockly.Theme'); 16 | 17 | 18 | // Temporary holding object. 19 | Blockly.Themes.Classic = {}; 20 | 21 | Blockly.Themes.Classic.defaultBlockStyles = { 22 | "colour_blocks": { 23 | "colourPrimary": "20" 24 | }, 25 | "logic_blocks": { 26 | "colourPrimary": "100" 27 | }, 28 | "loop_blocks": { 29 | "colourPrimary": "140" 30 | }, 31 | "math_blocks": { 32 | "colourPrimary": "170" 33 | }, 34 | "text_blocks": { 35 | "colourPrimary": "190" 36 | }, 37 | "list_blocks": { 38 | "colourPrimary": "210" 39 | }, 40 | "dict_blocks": { 41 | "colourPrimary": "230" 42 | }, 43 | "ndarray_blocks": { 44 | "colourPrimary": "250" 45 | }, 46 | "model_blocks": { 47 | "colourPrimary": "270" 48 | }, 49 | "variable_blocks": { 50 | "colourPrimary": "290" 51 | }, 52 | "variable_dynamic_blocks": { 53 | "colourPrimary": "300" 54 | }, 55 | "procedure_blocks": { 56 | "colourPrimary": "310" 57 | }, 58 | "plot_blocks": { 59 | "colourPrimary": "335" 60 | }, 61 | "file_blocks": { 62 | "colourPrimary": "360" 63 | }, 64 | "mlgame_blocks": { 65 | "colourPrimary": "20" 66 | }, 67 | "hat_blocks": { 68 | "colourPrimary": "360", 69 | "hat": "cap" 70 | } 71 | }; 72 | 73 | Blockly.Themes.Classic.categoryStyles = { 74 | "colour_category": { 75 | "colour": "20" 76 | }, 77 | "list_category": { 78 | "colour": "260" 79 | }, 80 | "logic_category": { 81 | "colour": "210" 82 | }, 83 | "loop_category": { 84 | "colour": "120" 85 | }, 86 | "math_category": { 87 | "colour": "230" 88 | }, 89 | "procedure_category": { 90 | "colour": "290" 91 | }, 92 | "text_category": { 93 | "colour": "160" 94 | }, 95 | "variable_category": { 96 | "colour": "330" 97 | }, 98 | "variable_dynamic_category": { 99 | "colour": "310" 100 | } 101 | }; 102 | 103 | Blockly.Themes.Classic = 104 | new Blockly.Theme('classic', Blockly.Themes.Classic.defaultBlockStyles, 105 | Blockly.Themes.Classic.categoryStyles); 106 | -------------------------------------------------------------------------------- /js/core/ui_events.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2018 Google LLC 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | /** 8 | * @fileoverview Events fired as a result of UI actions in Blockly's editor. 9 | * @author fraser@google.com (Neil Fraser) 10 | */ 11 | 'use strict'; 12 | 13 | goog.provide('Blockly.Events.Ui'); 14 | 15 | goog.require('Blockly.Events'); 16 | goog.require('Blockly.Events.Abstract'); 17 | goog.require('Blockly.utils.object'); 18 | 19 | 20 | /** 21 | * Class for a UI event. 22 | * UI events are events that don't need to be sent over the wire for multi-user 23 | * editing to work (e.g. scrolling the workspace, zooming, opening toolbox 24 | * categories). 25 | * UI events do not undo or redo. 26 | * @param {Blockly.Block} block The affected block. 27 | * @param {string} element One of 'selected', 'comment', 'mutatorOpen', etc. 28 | * @param {*} oldValue Previous value of element. 29 | * @param {*} newValue New value of element. 30 | * @extends {Blockly.Events.Abstract} 31 | * @constructor 32 | */ 33 | Blockly.Events.Ui = function(block, element, oldValue, newValue) { 34 | Blockly.Events.Ui.superClass_.constructor.call(this); 35 | this.blockId = block ? block.id : null; 36 | this.workspaceId = block ? block.workspace.id : undefined; 37 | this.element = element; 38 | this.oldValue = oldValue; 39 | this.newValue = newValue; 40 | // UI events do not undo or redo. 41 | this.recordUndo = false; 42 | }; 43 | Blockly.utils.object.inherits(Blockly.Events.Ui, Blockly.Events.Abstract); 44 | 45 | /** 46 | * Type of this event. 47 | * @type {string} 48 | */ 49 | Blockly.Events.Ui.prototype.type = Blockly.Events.UI; 50 | 51 | /** 52 | * Encode the event as JSON. 53 | * @return {!Object} JSON representation. 54 | */ 55 | Blockly.Events.Ui.prototype.toJson = function() { 56 | var json = Blockly.Events.Ui.superClass_.toJson.call(this); 57 | json['element'] = this.element; 58 | if (this.newValue !== undefined) { 59 | json['newValue'] = this.newValue; 60 | } 61 | if (this.blockId) { 62 | json['blockId'] = this.blockId; 63 | } 64 | return json; 65 | }; 66 | 67 | /** 68 | * Decode the JSON event. 69 | * @param {!Object} json JSON representation. 70 | */ 71 | Blockly.Events.Ui.prototype.fromJson = function(json) { 72 | Blockly.Events.Ui.superClass_.fromJson.call(this, json); 73 | this.element = json['element']; 74 | this.newValue = json['newValue']; 75 | this.blockId = json['blockId']; 76 | }; 77 | -------------------------------------------------------------------------------- /js/core/renderers/geras/measurables/inputs.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2019 Google LLC 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | /** 8 | * @fileoverview Objects representing inputs with connections on a rendered 9 | * block. 10 | * @author kozbial@google.com (Monica Kozbial) 11 | */ 12 | 'use strict'; 13 | 14 | goog.provide('Blockly.geras.InlineInput'); 15 | goog.provide('Blockly.geras.StatementInput'); 16 | 17 | goog.require('Blockly.utils.object'); 18 | 19 | 20 | /** 21 | * An object containing information about the space an inline input takes up 22 | * during rendering 23 | * @param {!Blockly.blockRendering.ConstantProvider} constants The rendering 24 | * constants provider. 25 | * @param {!Blockly.Input} input The inline input to measure and store 26 | * information for. 27 | * @package 28 | * @constructor 29 | * @extends {Blockly.blockRendering.InlineInput} 30 | */ 31 | Blockly.geras.InlineInput = function(constants, input) { 32 | Blockly.geras.InlineInput.superClass_.constructor.call( 33 | this, constants, input); 34 | 35 | if (this.connectedBlock) { 36 | // We allow the dark path to show on the parent block so that the child 37 | // block looks embossed. This takes up an extra pixel in both x and y. 38 | this.width += this.constants_.DARK_PATH_OFFSET; 39 | this.height += this.constants_.DARK_PATH_OFFSET; 40 | } 41 | }; 42 | Blockly.utils.object.inherits(Blockly.geras.InlineInput, 43 | Blockly.blockRendering.InlineInput); 44 | 45 | /** 46 | * An object containing information about the space a statement input takes up 47 | * during rendering 48 | * @param {!Blockly.blockRendering.ConstantProvider} constants The rendering 49 | * constants provider. 50 | * @param {!Blockly.Input} input The statement input to measure and store 51 | * information for. 52 | * @package 53 | * @constructor 54 | * @extends {Blockly.blockRendering.StatementInput} 55 | */ 56 | Blockly.geras.StatementInput = function(constants, input) { 57 | Blockly.geras.StatementInput.superClass_.constructor.call( 58 | this, constants, input); 59 | 60 | if (this.connectedBlock) { 61 | // We allow the dark path to show on the parent block so that the child 62 | // block looks embossed. This takes up an extra pixel in both x and y. 63 | this.height += this.constants_.DARK_PATH_OFFSET; 64 | } 65 | }; 66 | Blockly.utils.object.inherits(Blockly.geras.StatementInput, 67 | Blockly.blockRendering.StatementInput); 68 | -------------------------------------------------------------------------------- /js/core/renderers/common/block_rendering.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2019 Google LLC 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | /** 8 | * @fileoverview Namespace for block rendering functionality. 9 | * @author fenichel@google.com (Rachel Fenichel) 10 | */ 11 | 'use strict'; 12 | 13 | /** 14 | * The top level namespace for block rendering. 15 | * @namespace Blockly.blockRendering 16 | */ 17 | goog.provide('Blockly.blockRendering'); 18 | 19 | goog.require('Blockly.registry'); 20 | goog.require('Blockly.utils.object'); 21 | 22 | 23 | /** 24 | * Whether or not the debugger is turned on. 25 | * @type {boolean} 26 | * @package 27 | */ 28 | Blockly.blockRendering.useDebugger = false; 29 | 30 | /** 31 | * Registers a new renderer. 32 | * @param {string} name The name of the renderer. 33 | * @param {!Function} rendererClass The new renderer class 34 | * to register. 35 | * @throws {Error} if a renderer with the same name has already been registered. 36 | */ 37 | Blockly.blockRendering.register = function(name, rendererClass) { 38 | Blockly.registry.register(Blockly.registry.Type.RENDERER, name, 39 | rendererClass); 40 | }; 41 | 42 | /** 43 | * Unregisters the renderer registered with the given name. 44 | * @param {string} name The name of the renderer. 45 | */ 46 | Blockly.blockRendering.unregister = function(name) { 47 | Blockly.registry.unregister(Blockly.registry.Type.RENDERER, name); 48 | }; 49 | /** 50 | * Turn on the blocks debugger. 51 | * @package 52 | */ 53 | Blockly.blockRendering.startDebugger = function() { 54 | Blockly.blockRendering.useDebugger = true; 55 | }; 56 | 57 | /** 58 | * Turn off the blocks debugger. 59 | * @package 60 | */ 61 | Blockly.blockRendering.stopDebugger = function() { 62 | Blockly.blockRendering.useDebugger = false; 63 | }; 64 | 65 | /** 66 | * Initialize anything needed for rendering (constants, etc). 67 | * @param {!string} name Name of the renderer to initialize. 68 | * @param {!Blockly.Theme} theme The workspace theme object. 69 | * @param {Object=} opt_rendererOverrides Rendering constant overrides. 70 | * @return {!Blockly.blockRendering.Renderer} The new instance of a renderer. 71 | * Already initialized. 72 | * @package 73 | */ 74 | 75 | Blockly.blockRendering.init = function(name, theme, opt_rendererOverrides) { 76 | var rendererClass = Blockly.registry.getClass( 77 | Blockly.registry.Type.RENDERER, name); 78 | var renderer = new rendererClass(name); 79 | renderer.init(theme, opt_rendererOverrides); 80 | return renderer; 81 | }; 82 | -------------------------------------------------------------------------------- /js/core/field_registry.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2019 Google LLC 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | /** 8 | * @fileoverview Fields can be created based on a JSON definition. This file 9 | * contains methods for registering those JSON definitions, and building the 10 | * fields based on JSON. 11 | * @author bekawestberg@gmail.com (Beka Westberg) 12 | */ 13 | 'use strict'; 14 | 15 | goog.provide('Blockly.fieldRegistry'); 16 | 17 | goog.require('Blockly.registry'); 18 | 19 | 20 | /** 21 | * Registers a field type. 22 | * Blockly.fieldRegistry.fromJson uses this registry to 23 | * find the appropriate field type. 24 | * @param {string} type The field type name as used in the JSON definition. 25 | * @param {?function(new:Blockly.Field, ...?)} fieldClass The field class 26 | * containing a fromJson function that can construct an instance of the 27 | * field. 28 | * @throws {Error} if the type name is empty, the field is already 29 | * registered, or the fieldClass is not an object containing a fromJson 30 | * function. 31 | */ 32 | Blockly.fieldRegistry.register = function(type, fieldClass) { 33 | Blockly.registry.register(Blockly.registry.Type.FIELD, type, fieldClass); 34 | }; 35 | 36 | /** 37 | * Unregisters the field registered with the given type. 38 | * @param {string} type The field type name as used in the JSON definition. 39 | */ 40 | Blockly.fieldRegistry.unregister = function(type) { 41 | Blockly.registry.unregister(Blockly.registry.Type.FIELD, type); 42 | }; 43 | 44 | /** 45 | * Construct a Field from a JSON arg object. 46 | * Finds the appropriate registered field by the type name as registered using 47 | * Blockly.fieldRegistry.register. 48 | * @param {!Object} options A JSON object with a type and options specific 49 | * to the field type. 50 | * @return {Blockly.Field} The new field instance or null if a field wasn't 51 | * found with the given type name 52 | * @package 53 | */ 54 | Blockly.fieldRegistry.fromJson = function(options) { 55 | var fieldClass = /** @type {{fromJson:function(!Object):!Blockly.Field}} */ ( 56 | Blockly.registry.getClass(Blockly.registry.Type.FIELD, options['type'])); 57 | if (!fieldClass) { 58 | console.warn('Blockly could not create a field of type ' + options['type'] + 59 | '. The field is probably not being registered. This could be because' + 60 | ' the file is not loaded, the field does not register itself (Issue' + 61 | ' #1584), or the registration is not being reached.'); 62 | return null; 63 | } 64 | return fieldClass.fromJson(options); 65 | }; 66 | -------------------------------------------------------------------------------- /js/core/interfaces/i_toolbox.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2020 Google LLC 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | /** 8 | * @fileoverview The interface for a toolbox. 9 | * @author aschmiedt@google.com (Abby Schmiedt) 10 | */ 11 | 12 | 'use strict'; 13 | 14 | goog.provide('Blockly.IToolbox'); 15 | 16 | goog.requireType('Blockly.IRegistrable'); 17 | 18 | 19 | /** 20 | * Interface for a toolbox. 21 | * @extends {Blockly.IRegistrable} 22 | * @interface 23 | */ 24 | Blockly.IToolbox = function() {}; 25 | 26 | /** 27 | * Initializes the toolbox. 28 | * @return {void} 29 | */ 30 | Blockly.IToolbox.prototype.init; 31 | 32 | /** 33 | * Fill the toolbox with categories and blocks. 34 | * @param {Array.} toolboxDef Array holding objects 35 | * containing information on the contents of the toolbox. 36 | */ 37 | Blockly.IToolbox.prototype.render; 38 | 39 | /** 40 | * Dispose of this toolbox. 41 | * @return {void} 42 | */ 43 | Blockly.IToolbox.prototype.dispose; 44 | 45 | /** 46 | * Get the width of the toolbox. 47 | * @return {number} The width of the toolbox. 48 | */ 49 | Blockly.IToolbox.prototype.getWidth; 50 | 51 | /** 52 | * Get the height of the toolbox. 53 | * @return {number} The width of the toolbox. 54 | */ 55 | Blockly.IToolbox.prototype.getHeight; 56 | 57 | /** 58 | * Get the toolbox flyout. 59 | * @return {Blockly.Flyout} The toolbox flyout. 60 | */ 61 | Blockly.IToolbox.prototype.getFlyout; 62 | 63 | /** 64 | * Move the toolbox to the edge. 65 | * @return {void} 66 | */ 67 | Blockly.IToolbox.prototype.position; 68 | 69 | /** 70 | * Unhighlight any previously specified option. 71 | * @return {void} 72 | */ 73 | Blockly.IToolbox.prototype.clearSelection; 74 | 75 | /** 76 | * Updates the category colours and background colour of selected categories. 77 | * @return {void} 78 | */ 79 | Blockly.IToolbox.prototype.refreshTheme; 80 | 81 | /** 82 | * Update the flyout's contents without closing it. Should be used in response 83 | * to a change in one of the dynamic categories, such as variables or 84 | * procedures. 85 | * @return {void} 86 | */ 87 | Blockly.IToolbox.prototype.refreshSelection; 88 | 89 | /** 90 | * Toggles the visibility of the toolbox. 91 | * @param {boolean} isVisible True if the toolbox should be visible. 92 | */ 93 | Blockly.IToolbox.prototype.setVisible; 94 | 95 | /** 96 | * Select the first toolbox category if no category is selected. 97 | * @return {void} 98 | */ 99 | Blockly.IToolbox.prototype.selectFirstCategory; 100 | -------------------------------------------------------------------------------- /js/core/flyout_dragger.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2017 Google LLC 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | /** 8 | * @fileoverview Methods for dragging a flyout visually. 9 | * @author fenichel@google.com (Rachel Fenichel) 10 | */ 11 | 'use strict'; 12 | 13 | goog.provide('Blockly.FlyoutDragger'); 14 | 15 | goog.require('Blockly.utils.object'); 16 | goog.require('Blockly.WorkspaceDragger'); 17 | 18 | 19 | /** 20 | * Class for a flyout dragger. It moves a flyout workspace around when it is 21 | * being dragged by a mouse or touch. 22 | * Note that the workspace itself manages whether or not it has a drag surface 23 | * and how to do translations based on that. This simply passes the right 24 | * commands based on events. 25 | * @param {!Blockly.Flyout} flyout The flyout to drag. 26 | * @extends {Blockly.WorkspaceDragger} 27 | * @constructor 28 | */ 29 | Blockly.FlyoutDragger = function(flyout) { 30 | Blockly.FlyoutDragger.superClass_.constructor.call(this, 31 | flyout.getWorkspace()); 32 | 33 | /** 34 | * The scrollbar to update to move the flyout. 35 | * Unlike the main workspace, the flyout has only one scrollbar, in either the 36 | * horizontal or the vertical direction. 37 | * @type {!Blockly.Scrollbar} 38 | * @private 39 | */ 40 | this.scrollbar_ = flyout.scrollbar; 41 | 42 | /** 43 | * Whether the flyout scrolls horizontally. If false, the flyout scrolls 44 | * vertically. 45 | * @type {boolean} 46 | * @private 47 | */ 48 | this.horizontalLayout_ = flyout.horizontalLayout; 49 | }; 50 | Blockly.utils.object.inherits(Blockly.FlyoutDragger, Blockly.WorkspaceDragger); 51 | 52 | /** 53 | * Move the flyout based on the most recent mouse movements. 54 | * @param {!Blockly.utils.Coordinate} currentDragDeltaXY How far the pointer has 55 | * moved from the position at the start of the drag, in pixel coordinates. 56 | * @package 57 | */ 58 | Blockly.FlyoutDragger.prototype.drag = function(currentDragDeltaXY) { 59 | // startScrollXY_ is assigned by the superclass. 60 | var newXY = Blockly.utils.Coordinate.sum(this.startScrollXY_, 61 | currentDragDeltaXY); 62 | 63 | // We can't call workspace.scroll because the flyout's workspace doesn't own 64 | // it's own scrollbars. This is because (as of 2.20190722.1) the 65 | // workspace's scrollbar property must be a scrollbar pair, rather than a 66 | // single scrollbar. 67 | // Instead we'll just expect setting the scrollbar to update the scroll of 68 | // the workspace as well. 69 | if (this.horizontalLayout_) { 70 | this.scrollbar_.set(-newXY.x); 71 | } else { 72 | this.scrollbar_.set(-newXY.y); 73 | } 74 | }; 75 | -------------------------------------------------------------------------------- /js/i18n/dedup_json.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | # Consolidates duplicate key-value pairs in a JSON file. 4 | # If the same key is used with different values, no warning is given, 5 | # and there is no guarantee about which key-value pair will be output. 6 | # There is also no guarantee as to the order of the key-value pairs 7 | # output. 8 | # 9 | # Copyright 2013 Google LLC 10 | # 11 | # Licensed under the Apache License, Version 2.0 (the "License"); 12 | # you may not use this file except in compliance with the License. 13 | # You may obtain a copy of the License at 14 | # 15 | # http://www.apache.org/licenses/LICENSE-2.0 16 | # 17 | # Unless required by applicable law or agreed to in writing, software 18 | # distributed under the License is distributed on an "AS IS" BASIS, 19 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 20 | # See the License for the specific language governing permissions and 21 | # limitations under the License. 22 | 23 | import argparse 24 | import codecs 25 | import json 26 | from common import InputError 27 | 28 | 29 | def main(): 30 | """Parses arguments and iterates over files. 31 | 32 | Raises: 33 | IOError: An I/O error occurred with an input or output file. 34 | InputError: Input JSON could not be parsed. 35 | """ 36 | 37 | # Set up argument parser. 38 | parser = argparse.ArgumentParser( 39 | description='Removes duplicate key-value pairs from JSON files.') 40 | parser.add_argument('--suffix', default='', 41 | help='optional suffix for output files; ' 42 | 'if empty, files will be changed in place') 43 | parser.add_argument('files', nargs='+', help='input files') 44 | args = parser.parse_args() 45 | 46 | # Iterate over files. 47 | for filename in args.files: 48 | # Read in json using Python libraries. This eliminates duplicates. 49 | print('Processing ' + filename + '...') 50 | try: 51 | with codecs.open(filename, 'r', 'utf-8') as infile: 52 | j = json.load(infile) 53 | except ValueError as e: 54 | print('Error reading ' + filename) 55 | raise InputError(filename, str(e)) 56 | 57 | # Built up output strings as an array to make output of delimiters easier. 58 | output = [] 59 | for key in j: 60 | if key != '@metadata': 61 | output.append('\t"' + key + '": "' + 62 | j[key].replace('\n', '\\n') + '"') 63 | 64 | # Output results. 65 | with codecs.open(filename + args.suffix, 'w', 'utf-8') as outfile: 66 | outfile.write('{\n') 67 | outfile.write(',\n'.join(output)) 68 | outfile.write('\n}\n') 69 | 70 | 71 | if __name__ == '__main__': 72 | main() 73 | -------------------------------------------------------------------------------- /js/core/field_label_serializable.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2019 Google LLC 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | /** 8 | * @fileoverview Non-editable, serializable text field. Behaves like a 9 | * normal label but is serialized to XML. It may only be 10 | * edited programmatically. 11 | */ 12 | 'use strict'; 13 | 14 | goog.provide('Blockly.FieldLabelSerializable'); 15 | 16 | goog.require('Blockly.FieldLabel'); 17 | goog.require('Blockly.fieldRegistry'); 18 | goog.require('Blockly.utils'); 19 | goog.require('Blockly.utils.object'); 20 | 21 | 22 | /** 23 | * Class for a non-editable, serializable text field. 24 | * @param {*} opt_value The initial value of the field. Should cast to a 25 | * string. Defaults to an empty string if null or undefined. 26 | * @param {string=} opt_class Optional CSS class for the field's text. 27 | * @param {Object=} opt_config A map of options used to configure the field. 28 | * See the [field creation documentation]{@link https://developers.google.com/blockly/guides/create-custom-blocks/fields/built-in-fields/label-serializable#creation} 29 | * for a list of properties this parameter supports. 30 | * @extends {Blockly.FieldLabel} 31 | * @constructor 32 | * 33 | */ 34 | Blockly.FieldLabelSerializable = function(opt_value, opt_class, opt_config) { 35 | Blockly.FieldLabelSerializable.superClass_.constructor.call( 36 | this, opt_value, opt_class, opt_config); 37 | }; 38 | Blockly.utils.object.inherits(Blockly.FieldLabelSerializable, 39 | Blockly.FieldLabel); 40 | 41 | /** 42 | * Construct a FieldLabelSerializable from a JSON arg object, 43 | * dereferencing any string table references. 44 | * @param {!Object} options A JSON object with options (text, and class). 45 | * @return {!Blockly.FieldLabelSerializable} The new field instance. 46 | * @package 47 | * @nocollapse 48 | */ 49 | Blockly.FieldLabelSerializable.fromJson = function(options) { 50 | var text = Blockly.utils.replaceMessageReferences(options['text']); 51 | return new Blockly.FieldLabelSerializable(text, undefined, options); 52 | }; 53 | 54 | /** 55 | * Editable fields usually show some sort of UI indicating they are 56 | * editable. This field should not. 57 | * @type {boolean} 58 | */ 59 | Blockly.FieldLabelSerializable.prototype.EDITABLE = false; 60 | 61 | /** 62 | * Serializable fields are saved by the XML renderer, non-serializable fields 63 | * are not. This field should be serialized, but only edited programmatically. 64 | * @type {boolean} 65 | */ 66 | Blockly.FieldLabelSerializable.prototype.SERIALIZABLE = true; 67 | 68 | Blockly.fieldRegistry.register( 69 | 'field_label_serializable', Blockly.FieldLabelSerializable); 70 | -------------------------------------------------------------------------------- /js/core/events_abstract.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2018 Google LLC 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | /** 8 | * @fileoverview Abstract class for events fired as a result of actions in 9 | * Blockly's editor. 10 | * @author fraser@google.com (Neil Fraser) 11 | */ 12 | 'use strict'; 13 | 14 | goog.provide('Blockly.Events.Abstract'); 15 | 16 | goog.require('Blockly.Events'); 17 | 18 | 19 | /** 20 | * Abstract class for an event. 21 | * @constructor 22 | */ 23 | Blockly.Events.Abstract = function() { 24 | /** 25 | * The workspace identifier for this event. 26 | * @type {string|undefined} 27 | */ 28 | this.workspaceId = undefined; 29 | 30 | /** 31 | * The event group id for the group this event belongs to. Groups define 32 | * events that should be treated as an single action from the user's 33 | * perspective, and should be undone together. 34 | * @type {string} 35 | */ 36 | this.group = Blockly.Events.getGroup(); 37 | 38 | /** 39 | * Sets whether the event should be added to the undo stack. 40 | * @type {boolean} 41 | */ 42 | this.recordUndo = Blockly.Events.recordUndo; 43 | }; 44 | 45 | /** 46 | * Encode the event as JSON. 47 | * @return {!Object} JSON representation. 48 | */ 49 | Blockly.Events.Abstract.prototype.toJson = function() { 50 | var json = { 51 | 'type': this.type 52 | }; 53 | if (this.group) { 54 | json['group'] = this.group; 55 | } 56 | return json; 57 | }; 58 | 59 | /** 60 | * Decode the JSON event. 61 | * @param {!Object} json JSON representation. 62 | */ 63 | Blockly.Events.Abstract.prototype.fromJson = function(json) { 64 | this.group = json['group']; 65 | }; 66 | 67 | /** 68 | * Does this event record any change of state? 69 | * @return {boolean} True if null, false if something changed. 70 | */ 71 | Blockly.Events.Abstract.prototype.isNull = function() { 72 | return false; 73 | }; 74 | 75 | /** 76 | * Run an event. 77 | * @param {boolean} _forward True if run forward, false if run backward (undo). 78 | */ 79 | Blockly.Events.Abstract.prototype.run = function(_forward) { 80 | // Defined by subclasses. 81 | }; 82 | 83 | /** 84 | * Get workspace the event belongs to. 85 | * @return {!Blockly.Workspace} The workspace the event belongs to. 86 | * @throws {Error} if workspace is null. 87 | * @protected 88 | */ 89 | Blockly.Events.Abstract.prototype.getEventWorkspace_ = function() { 90 | if (this.workspaceId) { 91 | var workspace = Blockly.Workspace.getById(this.workspaceId); 92 | } 93 | if (!workspace) { 94 | throw Error('Workspace is null. Event must have been generated from real' + 95 | ' Blockly events.'); 96 | } 97 | return workspace; 98 | }; 99 | -------------------------------------------------------------------------------- /js/core/workspace_dragger.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2017 Google LLC 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | /** 8 | * @fileoverview Methods for dragging a workspace visually. 9 | * @author fenichel@google.com (Rachel Fenichel) 10 | */ 11 | 'use strict'; 12 | 13 | goog.provide('Blockly.WorkspaceDragger'); 14 | 15 | goog.require('Blockly.utils.Coordinate'); 16 | 17 | 18 | /** 19 | * Class for a workspace dragger. It moves the workspace around when it is 20 | * being dragged by a mouse or touch. 21 | * Note that the workspace itself manages whether or not it has a drag surface 22 | * and how to do translations based on that. This simply passes the right 23 | * commands based on events. 24 | * @param {!Blockly.WorkspaceSvg} workspace The workspace to drag. 25 | * @constructor 26 | */ 27 | Blockly.WorkspaceDragger = function(workspace) { 28 | /** 29 | * @type {!Blockly.WorkspaceSvg} 30 | * @private 31 | */ 32 | this.workspace_ = workspace; 33 | 34 | /** 35 | * The scroll position of the workspace at the beginning of the drag. 36 | * Coordinate system: pixel coordinates. 37 | * @type {!Blockly.utils.Coordinate} 38 | * @protected 39 | */ 40 | this.startScrollXY_ = new Blockly.utils.Coordinate( 41 | workspace.scrollX, workspace.scrollY); 42 | }; 43 | 44 | /** 45 | * Sever all links from this object. 46 | * @package 47 | * @suppress {checkTypes} 48 | */ 49 | Blockly.WorkspaceDragger.prototype.dispose = function() { 50 | this.workspace_ = null; 51 | }; 52 | 53 | /** 54 | * Start dragging the workspace. 55 | * @package 56 | */ 57 | Blockly.WorkspaceDragger.prototype.startDrag = function() { 58 | if (Blockly.selected) { 59 | Blockly.selected.unselect(); 60 | } 61 | this.workspace_.setupDragSurface(); 62 | }; 63 | 64 | /** 65 | * Finish dragging the workspace and put everything back where it belongs. 66 | * @param {!Blockly.utils.Coordinate} currentDragDeltaXY How far the pointer has 67 | * moved from the position at the start of the drag, in pixel coordinates. 68 | * @package 69 | */ 70 | Blockly.WorkspaceDragger.prototype.endDrag = function(currentDragDeltaXY) { 71 | // Make sure everything is up to date. 72 | this.drag(currentDragDeltaXY); 73 | this.workspace_.resetDragSurface(); 74 | }; 75 | 76 | /** 77 | * Move the workspace based on the most recent mouse movements. 78 | * @param {!Blockly.utils.Coordinate} currentDragDeltaXY How far the pointer has 79 | * moved from the position at the start of the drag, in pixel coordinates. 80 | * @package 81 | */ 82 | Blockly.WorkspaceDragger.prototype.drag = function(currentDragDeltaXY) { 83 | var newXY = Blockly.utils.Coordinate.sum(this.startScrollXY_, currentDragDeltaXY); 84 | this.workspace_.scroll(newXY.x, newXY.y); 85 | }; 86 | -------------------------------------------------------------------------------- /js/core/theme/tritanopia.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2019 Google LLC 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | /** 8 | * @fileoverview Tritanopia theme. 9 | * A color palette for people that have tritanopia (the inability to perceive 10 | * blue light). 11 | */ 12 | 'use strict'; 13 | 14 | goog.provide('Blockly.Themes.Tritanopia'); 15 | 16 | goog.require('Blockly.Theme'); 17 | 18 | 19 | // Temporary holding object. 20 | Blockly.Themes.Tritanopia = {}; 21 | 22 | Blockly.Themes.Tritanopia.defaultBlockStyles = { 23 | "colour_blocks": { 24 | "colourPrimary": "#05427f", 25 | "colourSecondary": "#2974c0", 26 | "colourTertiary": "#2d74bb" 27 | }, 28 | "list_blocks": { 29 | "colourPrimary": "#b69ce8", 30 | "colourSecondary": "#ccbaef", 31 | "colourTertiary": "#9176c5" 32 | }, 33 | "logic_blocks": { 34 | "colourPrimary": "#9fd2f1", 35 | "colourSecondary": "#c0e0f4", 36 | "colourTertiary": "#74bae5" 37 | }, 38 | "loop_blocks": { 39 | "colourPrimary": "#aa1846", 40 | "colourSecondary": "#d36185", 41 | "colourTertiary": "#7c1636" 42 | }, 43 | "math_blocks": { 44 | "colourPrimary": "#e6da39", 45 | "colourSecondary": "#f3ec8e", 46 | "colourTertiary": "#f2eeb7" 47 | }, 48 | "procedure_blocks": { 49 | "colourPrimary": "#590721", 50 | "colourSecondary": "#8c475d", 51 | "colourTertiary": "#885464" 52 | }, 53 | "text_blocks": { 54 | "colourPrimary": "#058863", 55 | "colourSecondary": "#5ecfaf", 56 | "colourTertiary": "#04684c" 57 | }, 58 | "variable_blocks": { 59 | "colourPrimary": "#4b2d84", 60 | "colourSecondary": "#816ea7", 61 | "colourTertiary": "#83759e" 62 | }, 63 | "variable_dynamic_blocks": { 64 | "colourPrimary": "#4b2d84", 65 | "colourSecondary": "#816ea7", 66 | "colourTertiary": "#83759e" 67 | } 68 | }; 69 | 70 | Blockly.Themes.Tritanopia.categoryStyles = { 71 | "colour_category": { 72 | "colour": "#05427f" 73 | }, 74 | "list_category": { 75 | "colour": "#b69ce8" 76 | }, 77 | "logic_category": { 78 | "colour": "#9fd2f1" 79 | }, 80 | "loop_category": { 81 | "colour": "#aa1846" 82 | }, 83 | "math_category": { 84 | "colour": "#e6da39" 85 | }, 86 | "procedure_category": { 87 | "colour": "#590721" 88 | }, 89 | "text_category": { 90 | "colour": "#058863" 91 | }, 92 | "variable_category": { 93 | "colour": "#4b2d84" 94 | }, 95 | "variable_dynamic_category": { 96 | "colour": "#4b2d84" 97 | } 98 | }; 99 | 100 | Blockly.Themes.Tritanopia = 101 | new Blockly.Theme('tritanopia', 102 | Blockly.Themes.Tritanopia.defaultBlockStyles, 103 | Blockly.Themes.Tritanopia.categoryStyles); 104 | -------------------------------------------------------------------------------- /js/core/theme/zelos.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2018 Google LLC 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | /** 8 | * @fileoverview Zelos theme. 9 | */ 10 | 'use strict'; 11 | 12 | goog.provide('Blockly.Themes.Zelos'); 13 | 14 | goog.require('Blockly.Theme'); 15 | 16 | 17 | // Temporary holding object. 18 | Blockly.Themes.Zelos = {}; 19 | 20 | Blockly.Themes.Zelos.defaultBlockStyles = { 21 | "colour_blocks": { 22 | "colourPrimary": "#CF63CF", 23 | "colourSecondary": "#C94FC9", 24 | "colourTertiary": "#BD42BD" 25 | }, 26 | "list_blocks": { 27 | "colourPrimary": "#9966FF", 28 | "colourSecondary": "#855CD6", 29 | "colourTertiary": "#774DCB" 30 | }, 31 | "logic_blocks": { 32 | "colourPrimary": "#4C97FF", 33 | "colourSecondary": "#4280D7", 34 | "colourTertiary": "#3373CC" 35 | }, 36 | "loop_blocks": { 37 | "colourPrimary": "#0fBD8C", 38 | "colourSecondary": "#0DA57A", 39 | "colourTertiary": "#0B8E69" 40 | }, 41 | "math_blocks": { 42 | "colourPrimary": "#59C059", 43 | "colourSecondary": "#46B946", 44 | "colourTertiary": "#389438" 45 | }, 46 | "procedure_blocks": { 47 | "colourPrimary": "#FF6680", 48 | "colourSecondary": "#FF4D6A", 49 | "colourTertiary": "#FF3355" 50 | }, 51 | "text_blocks": { 52 | "colourPrimary": "#FFBF00", 53 | "colourSecondary": "#E6AC00", 54 | "colourTertiary": "#CC9900" 55 | }, 56 | "variable_blocks": { 57 | "colourPrimary": "#FF8C1A", 58 | "colourSecondary": "#FF8000", 59 | "colourTertiary": "#DB6E00" 60 | }, 61 | "variable_dynamic_blocks": { 62 | "colourPrimary": "#FF8C1A", 63 | "colourSecondary": "#FF8000", 64 | "colourTertiary": "#DB6E00" 65 | }, 66 | "hat_blocks": { 67 | "colourPrimary": "#4C97FF", 68 | "colourSecondary": "#4280D7", 69 | "colourTertiary": "#3373CC", 70 | "hat": "cap" 71 | } 72 | }; 73 | 74 | Blockly.Themes.Zelos.categoryStyles = { 75 | "colour_category": { 76 | "colour": "#CF63CF" 77 | }, 78 | "list_category": { 79 | "colour": "#9966FF" 80 | }, 81 | "logic_category": { 82 | "colour": "#4C97FF" 83 | }, 84 | "loop_category": { 85 | "colour": "#0fBD8C" 86 | }, 87 | "math_category": { 88 | "colour": "#59C059" 89 | }, 90 | "procedure_category": { 91 | "colour": "#FF6680" 92 | }, 93 | "text_category": { 94 | "colour": "#FFBF00" 95 | }, 96 | "variable_category": { 97 | "colour": "#FF8C1A" 98 | }, 99 | "variable_dynamic_category": { 100 | "colour": "#FF8C1A" 101 | } 102 | }; 103 | 104 | Blockly.Themes.Zelos = 105 | new Blockly.Theme('zelos', Blockly.Themes.Zelos.defaultBlockStyles, 106 | Blockly.Themes.Zelos.categoryStyles); 107 | -------------------------------------------------------------------------------- /js/core/theme/deuteranopia.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2019 Google LLC 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | /** 8 | * @fileoverview Deuteranopia theme. 9 | * A colour palette for people that have deuteranopia (the inability to perceive 10 | * green light). This can also be used for people that have protanopia (the 11 | * inability to perceive red light). 12 | */ 13 | 'use strict'; 14 | 15 | goog.provide('Blockly.Themes.Deuteranopia'); 16 | 17 | goog.require('Blockly.Theme'); 18 | 19 | 20 | // Temporary holding object. 21 | Blockly.Themes.Deuteranopia = {}; 22 | 23 | Blockly.Themes.Deuteranopia.defaultBlockStyles = { 24 | "colour_blocks": { 25 | "colourPrimary": "#f2a72c", 26 | "colourSecondary": "#f1c172", 27 | "colourTertiary": "#da921c" 28 | }, 29 | "list_blocks": { 30 | "colourPrimary": "#7d65ab", 31 | "colourSecondary": "#a88be0", 32 | "colourTertiary": "#66518e" 33 | }, 34 | "logic_blocks": { 35 | "colourPrimary": "#9fd2f1", 36 | "colourSecondary": "#c0e0f4", 37 | "colourTertiary": "#74bae5" 38 | }, 39 | "loop_blocks": { 40 | "colourPrimary": "#795a07", 41 | "colourSecondary": "#ac8726", 42 | "colourTertiary": "#c4a03f" 43 | }, 44 | "math_blocks": { 45 | "colourPrimary": "#e6da39", 46 | "colourSecondary": "#f3ec8e", 47 | "colourTertiary": "#f2eeb7" 48 | }, 49 | "procedure_blocks": { 50 | "colourPrimary": "#590721", 51 | "colourSecondary": "#8c475d", 52 | "colourTertiary": "#885464" 53 | }, 54 | "text_blocks": { 55 | "colourPrimary": "#058863", 56 | "colourSecondary": "#5ecfaf", 57 | "colourTertiary": "#04684c" 58 | }, 59 | "variable_blocks": { 60 | "colourPrimary": "#47025a", 61 | "colourSecondary": "#820fa1", 62 | "colourTertiary": "#8e579d" 63 | }, 64 | "variable_dynamic_blocks": { 65 | "colourPrimary": "#47025a", 66 | "colourSecondary": "#820fa1", 67 | "colourTertiary": "#8e579d" 68 | } 69 | }; 70 | 71 | Blockly.Themes.Deuteranopia.categoryStyles = { 72 | "colour_category": { 73 | "colour": "#f2a72c" 74 | }, 75 | "list_category": { 76 | "colour": "#7d65ab" 77 | }, 78 | "logic_category": { 79 | "colour": "#9fd2f1" 80 | }, 81 | "loop_category": { 82 | "colour": "#795a07" 83 | }, 84 | "math_category": { 85 | "colour": "#e6da39" 86 | }, 87 | "procedure_category": { 88 | "colour": "#590721" 89 | }, 90 | "text_category": { 91 | "colour": "#058863" 92 | }, 93 | "variable_category": { 94 | "colour": "#47025a" 95 | }, 96 | "variable_dynamic_category": { 97 | "colour": "#47025a" 98 | } 99 | }; 100 | 101 | Blockly.Themes.Deuteranopia = 102 | new Blockly.Theme('deuteranopia', 103 | Blockly.Themes.Deuteranopia.defaultBlockStyles, 104 | Blockly.Themes.Deuteranopia.categoryStyles); 105 | -------------------------------------------------------------------------------- /js/core/theme/modern.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2018 Google LLC 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | /** 8 | * @fileoverview Modern theme. 9 | * Same colours as classic, but single coloured border. 10 | */ 11 | 'use strict'; 12 | 13 | goog.provide('Blockly.Themes.Modern'); 14 | 15 | goog.require('Blockly.Theme'); 16 | 17 | 18 | // Temporary holding object. 19 | Blockly.Themes.Modern = {}; 20 | 21 | Blockly.Themes.Modern.defaultBlockStyles = { 22 | "colour_blocks": { 23 | "colourPrimary": "#a5745b", 24 | "colourSecondary": "#dbc7bd", 25 | "colourTertiary": "#845d49" 26 | }, 27 | "list_blocks": { 28 | "colourPrimary": "#745ba5", 29 | "colourSecondary": "#c7bddb", 30 | "colourTertiary": "#5d4984" 31 | }, 32 | "logic_blocks": { 33 | "colourPrimary": "#5b80a5", 34 | "colourSecondary": "#bdccdb", 35 | "colourTertiary": "#496684" 36 | }, 37 | "loop_blocks": { 38 | "colourPrimary": "#5ba55b", 39 | "colourSecondary": "#bddbbd", 40 | "colourTertiary": "#498449" 41 | }, 42 | "math_blocks": { 43 | "colourPrimary": "#5b67a5", 44 | "colourSecondary": "#bdc2db", 45 | "colourTertiary": "#495284" 46 | }, 47 | "procedure_blocks": { 48 | "colourPrimary": "#995ba5", 49 | "colourSecondary": "#d6bddb", 50 | "colourTertiary": "#7a4984" 51 | }, 52 | "text_blocks": { 53 | "colourPrimary": "#5ba58c", 54 | "colourSecondary": "#bddbd1", 55 | "colourTertiary": "#498470" 56 | }, 57 | "variable_blocks": { 58 | "colourPrimary": "#a55b99", 59 | "colourSecondary": "#dbbdd6", 60 | "colourTertiary": "#84497a" 61 | }, 62 | "variable_dynamic_blocks": { 63 | "colourPrimary": "#a55b99", 64 | "colourSecondary": "#dbbdd6", 65 | "colourTertiary": "#84497a" 66 | }, 67 | "hat_blocks": { 68 | "colourPrimary": "#a55b99", 69 | "colourSecondary": "#dbbdd6", 70 | "colourTertiary": "#84497a", 71 | "hat": "cap" 72 | } 73 | }; 74 | 75 | Blockly.Themes.Modern.categoryStyles = { 76 | "colour_category": { 77 | "colour": "#a5745b" 78 | }, 79 | "list_category": { 80 | "colour": "#745ba5" 81 | }, 82 | "logic_category": { 83 | "colour": "#5b80a5" 84 | }, 85 | "loop_category": { 86 | "colour": "#5ba55b" 87 | }, 88 | "math_category": { 89 | "colour": "#5b67a5" 90 | }, 91 | "procedure_category": { 92 | "colour": "#995ba5" 93 | }, 94 | "text_category": { 95 | "colour": "#5ba58c" 96 | }, 97 | "variable_category": { 98 | "colour": "#a55b99" 99 | }, 100 | "variable_dynamic_category": { 101 | "colour": "#a55b99" 102 | } 103 | }; 104 | 105 | // This style is still being fleshed out and may change. 106 | Blockly.Themes.Modern = 107 | new Blockly.Theme('modern', Blockly.Themes.Modern.defaultBlockStyles, 108 | Blockly.Themes.Modern.categoryStyles); 109 | -------------------------------------------------------------------------------- /js/core/keyboard_nav/flyout_cursor.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2019 Google LLC 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | /** 8 | * @fileoverview The class representing a cursor used to navigate the flyout. 9 | * Used primarily for keyboard navigation. 10 | * @author aschmiedt@google.com (Abby Schmiedt) 11 | */ 12 | 'use strict'; 13 | 14 | goog.provide('Blockly.FlyoutCursor'); 15 | 16 | goog.require('Blockly.Cursor'); 17 | goog.require('Blockly.navigation'); 18 | goog.require('Blockly.utils.object'); 19 | 20 | 21 | /** 22 | * Class for a flyout cursor. 23 | * This controls how a user navigates blocks in the flyout. 24 | * @constructor 25 | * @extends {Blockly.Cursor} 26 | */ 27 | Blockly.FlyoutCursor = function() { 28 | Blockly.FlyoutCursor.superClass_.constructor.call(this); 29 | }; 30 | Blockly.utils.object.inherits(Blockly.FlyoutCursor, Blockly.Cursor); 31 | 32 | /** 33 | * Handles the given action. 34 | * This is only triggered when keyboard navigation is enabled. 35 | * @param {!Blockly.Action} action The action to be handled. 36 | * @return {boolean} True if the action has been handled, false otherwise. 37 | * @override 38 | */ 39 | Blockly.FlyoutCursor.prototype.onBlocklyAction = function(action) { 40 | switch (action.name) { 41 | case Blockly.navigation.actionNames.PREVIOUS: 42 | this.prev(); 43 | return true; 44 | case Blockly.navigation.actionNames.NEXT: 45 | this.next(); 46 | return true; 47 | default: 48 | return false; 49 | } 50 | }; 51 | 52 | /** 53 | * Find the next connection, field, or block. 54 | * @return {Blockly.ASTNode} The next element, or null if the current node is 55 | * not set or there is no next value. 56 | * @override 57 | */ 58 | Blockly.FlyoutCursor.prototype.next = function() { 59 | var curNode = this.getCurNode(); 60 | if (!curNode) { 61 | return null; 62 | } 63 | var newNode = curNode.next(); 64 | 65 | if (newNode) { 66 | this.setCurNode(newNode); 67 | } 68 | return newNode; 69 | }; 70 | 71 | /** 72 | * This is a no-op since a flyout cursor can not go in. 73 | * @return {null} Always null. 74 | * @override 75 | */ 76 | Blockly.FlyoutCursor.prototype.in = function() { 77 | return null; 78 | }; 79 | 80 | /** 81 | * Find the previous connection, field, or block. 82 | * @return {Blockly.ASTNode} The previous element, or null if the current node 83 | * is not set or there is no previous value. 84 | * @override 85 | */ 86 | Blockly.FlyoutCursor.prototype.prev = function() { 87 | var curNode = this.getCurNode(); 88 | if (!curNode) { 89 | return null; 90 | } 91 | var newNode = curNode.prev(); 92 | 93 | if (newNode) { 94 | this.setCurNode(newNode); 95 | } 96 | return newNode; 97 | }; 98 | 99 | /** 100 | * This is a no-op since a flyout cursor can not go out. 101 | * @return {null} Always null. 102 | * @override 103 | */ 104 | Blockly.FlyoutCursor.prototype.out = function() { 105 | return null; 106 | }; 107 | -------------------------------------------------------------------------------- /js/generators/python/file.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | goog.provide('Blockly.Python.file'); 4 | 5 | goog.require('Blockly.Python'); 6 | 7 | Blockly.Python['file_save'] = function(block) { 8 | // Save an object as a pickle file. 9 | Blockly.Python.definitions_['import_pickle'] = 'import pickle'; 10 | Blockly.Python.definitions_['import_os'] = 'import os'; 11 | var obj = Blockly.Python.valueToCode(block, 'OBJECT', 12 | Blockly.Python.ORDER_NONE) || 'None'; 13 | var name = Blockly.Python.valueToCode(block, 'FILENAME', 14 | Blockly.Python.ORDER_NONE) || ("'save_" + new Date().getTime() + "'"); 15 | var code = "with open(os.path.join(os.path.dirname(__file__), " + name + " + '.pickle'), 'wb') as f:\n" + 16 | Blockly.Python.prefixLines("pickle.dump(" + obj + ", f)\n", Blockly.Python.INDENT); 17 | return code; 18 | }; 19 | 20 | Blockly.Python['file_load'] = function(block) { 21 | // Load an object from a pickle file. 22 | Blockly.Python.definitions_['import_pickle'] = 'import pickle'; 23 | Blockly.Python.definitions_['import_os'] = 'import os'; 24 | var obj = Blockly.Python.valueToCode(block, 'OBJECT', 25 | Blockly.Python.ORDER_NONE) || '_'; 26 | var name = Blockly.Python.valueToCode(block, 'FILENAME', 27 | Blockly.Python.ORDER_NONE) || "''"; 28 | var code = "with open(os.path.join(os.path.dirname(__file__), " + name + " + '.pickle'), 'rb') as f:\n" + 29 | Blockly.Python.prefixLines(obj + " = pickle.load(f)\n", Blockly.Python.INDENT); 30 | return code; 31 | }; 32 | 33 | Blockly.Python['file_csv_save'] = function(block) { 34 | // Save an object as a csv file. 35 | Blockly.Python.definitions_['import_csv'] = 'import csv'; 36 | Blockly.Python.definitions_['import_os'] = 'import os'; 37 | var obj = Blockly.Python.valueToCode(block, 'OBJECT', 38 | Blockly.Python.ORDER_NONE) || 'None'; 39 | var name = Blockly.Python.valueToCode(block, 'FILENAME', 40 | Blockly.Python.ORDER_NONE) || ("'save_" + new Date().getTime() + "'"); 41 | var delimiter = block.getFieldValue('DELIMITER'); 42 | var code = "with open(os.path.join(os.path.dirname(__file__), " + name + " + '.csv'), 'w', newline='') as f:\n" + 43 | Blockly.Python.prefixLines("csv.writer(f, delimiter='" + delimiter + "').writerows(" + obj + ")\n", Blockly.Python.INDENT); 44 | return code; 45 | }; 46 | 47 | Blockly.Python['file_csv_load'] = function(block) { 48 | // Load an object from a csv file. 49 | Blockly.Python.definitions_['import_csv'] = 'import csv'; 50 | Blockly.Python.definitions_['import_os'] = 'import os'; 51 | var obj = Blockly.Python.valueToCode(block, 'OBJECT', 52 | Blockly.Python.ORDER_NONE) || '_'; 53 | var name = Blockly.Python.valueToCode(block, 'FILENAME', 54 | Blockly.Python.ORDER_NONE) || "''"; 55 | var delimiter = block.getFieldValue('DELIMITER'); 56 | var code = "with open(os.path.join(os.path.dirname(__file__), " + name + " + '.csv'), 'r', newline='') as f:\n" + 57 | Blockly.Python.prefixLines(obj + " = [row for row in csv.reader(f, delimiter='" + delimiter + "')]\n", Blockly.Python.INDENT); 58 | return code; 59 | }; 60 | -------------------------------------------------------------------------------- /js/core/variable_model.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2017 Google LLC 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | /** 8 | * @fileoverview Components for the variable model. 9 | * @author marisaleung@google.com (Marisa Leung) 10 | */ 11 | 'use strict'; 12 | 13 | goog.provide('Blockly.VariableModel'); 14 | 15 | goog.require('Blockly.Events'); 16 | goog.require('Blockly.Events.VarCreate'); 17 | goog.require('Blockly.utils'); 18 | 19 | 20 | /** 21 | * Class for a variable model. 22 | * Holds information for the variable including name, ID, and type. 23 | * @param {!Blockly.Workspace} workspace The variable's workspace. 24 | * @param {string} name The name of the variable. This must be unique across 25 | * variables and procedures. 26 | * @param {string=} opt_type The type of the variable like 'int' or 'string'. 27 | * Does not need to be unique. Field_variable can filter variables based on 28 | * their type. This will default to '' which is a specific type. 29 | * @param {string=} opt_id The unique ID of the variable. This will default to 30 | * a UUID. 31 | * @see {Blockly.FieldVariable} 32 | * @constructor 33 | */ 34 | Blockly.VariableModel = function(workspace, name, opt_type, opt_id) { 35 | /** 36 | * The workspace the variable is in. 37 | * @type {!Blockly.Workspace} 38 | */ 39 | this.workspace = workspace; 40 | 41 | /** 42 | * The name of the variable, typically defined by the user. It must be 43 | * unique across all names used for procedures and variables. It may be 44 | * changed by the user. 45 | * @type {string} 46 | */ 47 | this.name = name; 48 | 49 | /** 50 | * The type of the variable, such as 'int' or 'sound_effect'. This may be 51 | * used to build a list of variables of a specific type. By default this is 52 | * the empty string '', which is a specific type. 53 | * @see {Blockly.FieldVariable} 54 | * @type {string} 55 | */ 56 | this.type = opt_type || ''; 57 | 58 | /** 59 | * A unique id for the variable. This should be defined at creation and 60 | * not change, even if the name changes. In most cases this should be a 61 | * UUID. 62 | * @type {string} 63 | * @private 64 | */ 65 | this.id_ = opt_id || Blockly.utils.genUid(); 66 | 67 | Blockly.Events.fire(new Blockly.Events.VarCreate(this)); 68 | }; 69 | 70 | /** 71 | * @return {string} The ID for the variable. 72 | */ 73 | Blockly.VariableModel.prototype.getId = function() { 74 | return this.id_; 75 | }; 76 | 77 | /** 78 | * A custom compare function for the VariableModel objects. 79 | * @param {Blockly.VariableModel} var1 First variable to compare. 80 | * @param {Blockly.VariableModel} var2 Second variable to compare. 81 | * @return {number} -1 if name of var1 is less than name of var2, 0 if equal, 82 | * and 1 if greater. 83 | * @package 84 | */ 85 | Blockly.VariableModel.compareByName = function(var1, var2) { 86 | var name1 = var1.name.toLowerCase(); 87 | var name2 = var2.name.toLowerCase(); 88 | if (name1 < name2) { 89 | return -1; 90 | } else if (name1 == name2) { 91 | return 0; 92 | } else { 93 | return 1; 94 | } 95 | }; 96 | -------------------------------------------------------------------------------- /js/generators/python/colour.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2012 Google LLC 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | /** 8 | * @fileoverview Generating Python for colour blocks. 9 | * @author fraser@google.com (Neil Fraser) 10 | */ 11 | 'use strict'; 12 | 13 | goog.provide('Blockly.Python.colour'); 14 | 15 | goog.require('Blockly.Python'); 16 | 17 | 18 | Blockly.Python['colour_picker'] = function(block) { 19 | // Colour picker. 20 | var code = Blockly.Python.quote_(block.getFieldValue('COLOUR')); 21 | return [code, Blockly.Python.ORDER_ATOMIC]; 22 | }; 23 | 24 | Blockly.Python['colour_random'] = function(block) { 25 | // Generate a random colour. 26 | Blockly.Python.definitions_['import_random'] = 'import random'; 27 | var code = '\'#%06x\' % random.randint(0, 2**24 - 1)'; 28 | return [code, Blockly.Python.ORDER_FUNCTION_CALL]; 29 | }; 30 | 31 | Blockly.Python['colour_rgb'] = function(block) { 32 | // Compose a colour from RGB components expressed as percentages. 33 | var functionName = Blockly.Python.provideFunction_( 34 | 'colour_rgb', 35 | ['def ' + Blockly.Python.FUNCTION_NAME_PLACEHOLDER_ + '(r, g, b):', 36 | ' r = round(min(100, max(0, r)) * 2.55)', 37 | ' g = round(min(100, max(0, g)) * 2.55)', 38 | ' b = round(min(100, max(0, b)) * 2.55)', 39 | ' return \'#%02x%02x%02x\' % (r, g, b)']); 40 | var r = Blockly.Python.valueToCode(block, 'RED', 41 | Blockly.Python.ORDER_NONE) || 0; 42 | var g = Blockly.Python.valueToCode(block, 'GREEN', 43 | Blockly.Python.ORDER_NONE) || 0; 44 | var b = Blockly.Python.valueToCode(block, 'BLUE', 45 | Blockly.Python.ORDER_NONE) || 0; 46 | var code = functionName + '(' + r + ', ' + g + ', ' + b + ')'; 47 | return [code, Blockly.Python.ORDER_FUNCTION_CALL]; 48 | }; 49 | 50 | Blockly.Python['colour_blend'] = function(block) { 51 | // Blend two colours together. 52 | var functionName = Blockly.Python.provideFunction_( 53 | 'colour_blend', 54 | ['def ' + Blockly.Python.FUNCTION_NAME_PLACEHOLDER_ + 55 | '(colour1, colour2, ratio):', 56 | ' r1, r2 = int(colour1[1:3], 16), int(colour2[1:3], 16)', 57 | ' g1, g2 = int(colour1[3:5], 16), int(colour2[3:5], 16)', 58 | ' b1, b2 = int(colour1[5:7], 16), int(colour2[5:7], 16)', 59 | ' ratio = min(1, max(0, ratio))', 60 | ' r = round(r1 * (1 - ratio) + r2 * ratio)', 61 | ' g = round(g1 * (1 - ratio) + g2 * ratio)', 62 | ' b = round(b1 * (1 - ratio) + b2 * ratio)', 63 | ' return \'#%02x%02x%02x\' % (r, g, b)']); 64 | var colour1 = Blockly.Python.valueToCode(block, 'COLOUR1', 65 | Blockly.Python.ORDER_NONE) || '\'#000000\''; 66 | var colour2 = Blockly.Python.valueToCode(block, 'COLOUR2', 67 | Blockly.Python.ORDER_NONE) || '\'#000000\''; 68 | var ratio = Blockly.Python.valueToCode(block, 'RATIO', 69 | Blockly.Python.ORDER_NONE) || 0; 70 | var code = functionName + '(' + colour1 + ', ' + colour2 + ', ' + ratio + ')'; 71 | return [code, Blockly.Python.ORDER_FUNCTION_CALL]; 72 | }; 73 | -------------------------------------------------------------------------------- /js/blocks/file.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | goog.require('Blockly'); 4 | goog.require('Blockly.Blocks'); 5 | goog.require('Blockly.FieldTextInput'); 6 | goog.require('Blockly.FieldDropdown'); 7 | goog.require('Blockly.FieldLabel'); 8 | 9 | Blockly.defineBlocksWithJsonArray([ 10 | // Block for saving an object as a pickle file. 11 | { 12 | "type": "file_save", 13 | "message0": "%{BKY_FILE_SAVE}", 14 | "args0": [ 15 | { 16 | "type": "input_value", 17 | "name": "OBJECT" 18 | }, 19 | { 20 | "type": "input_value", 21 | "name": "FILENAME", 22 | "check": "String" 23 | } 24 | ], 25 | "inputsInline": true, 26 | "previousStatement": null, 27 | "nextStatement": null, 28 | "style": "file_blocks", 29 | "tooltip": "%{BKY_FILE_SAVE_TOOLTIP}" 30 | }, 31 | // Block for loading an object from a pickle file. 32 | { 33 | "type": "file_load", 34 | "message0": "%{BKY_FILE_LOAD}", 35 | "args0": [ 36 | { 37 | "type": "input_value", 38 | "name": "OBJECT" 39 | }, 40 | { 41 | "type": "input_value", 42 | "name": "FILENAME", 43 | "check": "String" 44 | } 45 | ], 46 | "inputsInline": true, 47 | "previousStatement": null, 48 | "nextStatement": null, 49 | "style": "file_blocks", 50 | "tooltip": "%{BKY_FILE_LOAD_TOOLTIP}" 51 | }, 52 | // Block for saving an object as a csv file. 53 | { 54 | "type": "file_csv_save", 55 | "message0": "%{BKY_FILE_CSV_SAVE}", 56 | "args0": [ 57 | { 58 | "type": "input_value", 59 | "name": "OBJECT" 60 | }, 61 | { 62 | "type": "input_value", 63 | "name": "FILENAME", 64 | "check": "String" 65 | }, 66 | { 67 | "type": "field_dropdown", 68 | "name": "DELIMITER", 69 | "options": [ 70 | [",", ","], 71 | [":", ":"], 72 | [";", ";"], 73 | ["|", "|"], 74 | ["SPACE", " "], 75 | ["TAB", "\\t"] 76 | ] 77 | } 78 | ], 79 | "inputsInline": true, 80 | "previousStatement": null, 81 | "nextStatement": null, 82 | "style": "file_blocks", 83 | "tooltip": "%{BKY_FILE_SAVE_TOOLTIP}" 84 | }, 85 | // Block for loading an object from a csv file. 86 | { 87 | "type": "file_csv_load", 88 | "message0": "%{BKY_FILE_CSV_LOAD}", 89 | "args0": [ 90 | { 91 | "type": "input_value", 92 | "name": "OBJECT" 93 | }, 94 | { 95 | "type": "input_value", 96 | "name": "FILENAME", 97 | "check": "String" 98 | }, 99 | { 100 | "type": "field_dropdown", 101 | "name": "DELIMITER", 102 | "options": [ 103 | [",", ","], 104 | [":", ":"], 105 | [";", ";"], 106 | ["|", "|"], 107 | ["SPACE", " "], 108 | ["TAB", "\\t"] 109 | ] 110 | } 111 | ], 112 | "inputsInline": true, 113 | "previousStatement": null, 114 | "nextStatement": null, 115 | "style": "file_blocks", 116 | "tooltip": "%{BKY_FILE_LOAD_TOOLTIP}" 117 | } 118 | ]); 119 | -------------------------------------------------------------------------------- /js/generators/lua/colour.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2016 Google LLC 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | /** 8 | * @fileoverview Generating Lua for colour blocks. 9 | * @author rodrigoq@google.com (Rodrigo Queiro) 10 | */ 11 | 'use strict'; 12 | 13 | goog.provide('Blockly.Lua.colour'); 14 | 15 | goog.require('Blockly.Lua'); 16 | 17 | 18 | Blockly.Lua['colour_picker'] = function(block) { 19 | // Colour picker. 20 | var code = Blockly.Lua.quote_(block.getFieldValue('COLOUR')); 21 | return [code, Blockly.Lua.ORDER_ATOMIC]; 22 | }; 23 | 24 | Blockly.Lua['colour_random'] = function(block) { 25 | // Generate a random colour. 26 | var code = 'string.format("#%06x", math.random(0, 2^24 - 1))'; 27 | return [code, Blockly.Lua.ORDER_HIGH]; 28 | }; 29 | 30 | Blockly.Lua['colour_rgb'] = function(block) { 31 | // Compose a colour from RGB components expressed as percentages. 32 | var functionName = Blockly.Lua.provideFunction_( 33 | 'colour_rgb', 34 | ['function ' + Blockly.Lua.FUNCTION_NAME_PLACEHOLDER_ + '(r, g, b)', 35 | ' r = math.floor(math.min(100, math.max(0, r)) * 2.55 + .5)', 36 | ' g = math.floor(math.min(100, math.max(0, g)) * 2.55 + .5)', 37 | ' b = math.floor(math.min(100, math.max(0, b)) * 2.55 + .5)', 38 | ' return string.format("#%02x%02x%02x", r, g, b)', 39 | 'end']); 40 | var r = Blockly.Lua.valueToCode(block, 'RED', 41 | Blockly.Lua.ORDER_NONE) || 0; 42 | var g = Blockly.Lua.valueToCode(block, 'GREEN', 43 | Blockly.Lua.ORDER_NONE) || 0; 44 | var b = Blockly.Lua.valueToCode(block, 'BLUE', 45 | Blockly.Lua.ORDER_NONE) || 0; 46 | var code = functionName + '(' + r + ', ' + g + ', ' + b + ')'; 47 | return [code, Blockly.Lua.ORDER_HIGH]; 48 | }; 49 | 50 | Blockly.Lua['colour_blend'] = function(block) { 51 | // Blend two colours together. 52 | var functionName = Blockly.Lua.provideFunction_( 53 | 'colour_blend', 54 | ['function ' + Blockly.Lua.FUNCTION_NAME_PLACEHOLDER_ + 55 | '(colour1, colour2, ratio)', 56 | ' local r1 = tonumber(string.sub(colour1, 2, 3), 16)', 57 | ' local r2 = tonumber(string.sub(colour2, 2, 3), 16)', 58 | ' local g1 = tonumber(string.sub(colour1, 4, 5), 16)', 59 | ' local g2 = tonumber(string.sub(colour2, 4, 5), 16)', 60 | ' local b1 = tonumber(string.sub(colour1, 6, 7), 16)', 61 | ' local b2 = tonumber(string.sub(colour2, 6, 7), 16)', 62 | ' local ratio = math.min(1, math.max(0, ratio))', 63 | ' local r = math.floor(r1 * (1 - ratio) + r2 * ratio + .5)', 64 | ' local g = math.floor(g1 * (1 - ratio) + g2 * ratio + .5)', 65 | ' local b = math.floor(b1 * (1 - ratio) + b2 * ratio + .5)', 66 | ' return string.format("#%02x%02x%02x", r, g, b)', 67 | 'end']); 68 | var colour1 = Blockly.Lua.valueToCode(block, 'COLOUR1', 69 | Blockly.Lua.ORDER_NONE) || '\'#000000\''; 70 | var colour2 = Blockly.Lua.valueToCode(block, 'COLOUR2', 71 | Blockly.Lua.ORDER_NONE) || '\'#000000\''; 72 | var ratio = Blockly.Lua.valueToCode(block, 'RATIO', 73 | Blockly.Lua.ORDER_NONE) || 0; 74 | var code = functionName + '(' + colour1 + ', ' + colour2 + ', ' + ratio + ')'; 75 | return [code, Blockly.Lua.ORDER_HIGH]; 76 | }; 77 | -------------------------------------------------------------------------------- /js/core/keyboard_nav/marker.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2019 Google LLC 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | /** 8 | * @fileoverview The class representing a marker. 9 | * Used primarily for keyboard navigation to show a marked location. 10 | * @author aschmiedt@google.com (Abby Schmiedt) 11 | */ 12 | 'use strict'; 13 | 14 | goog.provide('Blockly.Marker'); 15 | 16 | goog.require('Blockly.ASTNode'); 17 | goog.require('Blockly.navigation'); 18 | 19 | 20 | /** 21 | * Class for a marker. 22 | * This is used in keyboard navigation to save a location in the Blockly AST. 23 | * @constructor 24 | */ 25 | Blockly.Marker = function() { 26 | /** 27 | * The colour of the marker. 28 | * @type {?string} 29 | */ 30 | this.colour = null; 31 | 32 | /** 33 | * The current location of the marker. 34 | * @type {Blockly.ASTNode} 35 | * @private 36 | */ 37 | this.curNode_ = null; 38 | 39 | /** 40 | * The object in charge of drawing the visual representation of the current node. 41 | * @type {Blockly.blockRendering.MarkerSvg} 42 | * @private 43 | */ 44 | this.drawer_ = null; 45 | 46 | /** 47 | * The type of the marker. 48 | * @type {string} 49 | */ 50 | this.type = 'marker'; 51 | }; 52 | 53 | /** 54 | * Sets the object in charge of drawing the marker. 55 | * @param {Blockly.blockRendering.MarkerSvg} drawer The object in charge of 56 | * drawing the marker. 57 | */ 58 | Blockly.Marker.prototype.setDrawer = function(drawer) { 59 | this.drawer_ = drawer; 60 | }; 61 | 62 | /** 63 | * Get the current drawer for the marker. 64 | * @return {Blockly.blockRendering.MarkerSvg} The object in charge of drawing 65 | * the marker. 66 | */ 67 | Blockly.Marker.prototype.getDrawer = function() { 68 | return this.drawer_; 69 | }; 70 | 71 | /** 72 | * Gets the current location of the marker. 73 | * @return {Blockly.ASTNode} The current field, connection, or block the marker 74 | * is on. 75 | */ 76 | Blockly.Marker.prototype.getCurNode = function() { 77 | return this.curNode_; 78 | }; 79 | 80 | /** 81 | * Set the location of the marker and call the update method. 82 | * Setting isStack to true will only work if the newLocation is the top most 83 | * output or previous connection on a stack. 84 | * @param {Blockly.ASTNode} newNode The new location of the marker. 85 | */ 86 | Blockly.Marker.prototype.setCurNode = function(newNode) { 87 | var oldNode = this.curNode_; 88 | this.curNode_ = newNode; 89 | if (this.drawer_) { 90 | this.drawer_.draw(oldNode, this.curNode_); 91 | } 92 | }; 93 | 94 | /** 95 | * Redraw the current marker. 96 | * @package 97 | */ 98 | Blockly.Marker.prototype.draw = function() { 99 | if (this.drawer_) { 100 | this.drawer_.draw(this.curNode_, this.curNode_); 101 | } 102 | }; 103 | 104 | /** 105 | * Hide the marker SVG. 106 | */ 107 | Blockly.Marker.prototype.hide = function() { 108 | if (this.drawer_) { 109 | this.drawer_.hide(); 110 | } 111 | }; 112 | 113 | /** 114 | * Dispose of this marker. 115 | */ 116 | Blockly.Marker.prototype.dispose = function() { 117 | if (this.getDrawer()) { 118 | this.getDrawer().dispose(); 119 | } 120 | }; 121 | -------------------------------------------------------------------------------- /js/core/utils/metrics.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2020 Google LLC 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | /** 8 | * @fileoverview Workspace metrics definitions. 9 | * @author samelh@google.com (Sam El-Husseini) 10 | */ 11 | 'use strict'; 12 | 13 | goog.provide('Blockly.utils.Metrics'); 14 | 15 | 16 | /** 17 | * @record 18 | */ 19 | Blockly.utils.Metrics = function() {}; 20 | 21 | /** 22 | * Height of the visible portion of the workspace. 23 | * @type {number} 24 | */ 25 | Blockly.utils.Metrics.prototype.viewHeight; 26 | 27 | /** 28 | * Width of the visible portion of the workspace. 29 | * @type {number} 30 | */ 31 | Blockly.utils.Metrics.prototype.viewWidth; 32 | 33 | /** 34 | * Height of the content. 35 | * @type {number} 36 | */ 37 | Blockly.utils.Metrics.prototype.contentHeight; 38 | 39 | /** 40 | * Width of the content. 41 | * @type {number} 42 | */ 43 | Blockly.utils.Metrics.prototype.contentWidth; 44 | 45 | /** 46 | * Top-edge of the visible portion of the workspace, relative to the workspace 47 | * origin. 48 | * @type {number} 49 | */ 50 | Blockly.utils.Metrics.prototype.viewTop; 51 | 52 | /** 53 | * Left-edge of the visible portion of the workspace, relative to the workspace 54 | * origin. 55 | * @type {number} 56 | */ 57 | Blockly.utils.Metrics.prototype.viewLeft; 58 | 59 | /** 60 | * Top-edge of the content, relative to the workspace origin. 61 | * @type {number} 62 | */ 63 | Blockly.utils.Metrics.prototype.contentTop; 64 | 65 | /** 66 | * Left-edge of the content relative to the workspace origin. 67 | * @type {number} 68 | */ 69 | Blockly.utils.Metrics.prototype.contentLeft; 70 | 71 | /** 72 | * Top-edge of the visible portion of the workspace, relative to the blocklyDiv. 73 | * @type {number} 74 | */ 75 | Blockly.utils.Metrics.prototype.absoluteTop; 76 | 77 | /** 78 | * Left-edge of the visible portion of the workspace, relative to the 79 | * blocklyDiv. 80 | * @type {number} 81 | */ 82 | Blockly.utils.Metrics.prototype.absoluteLeft; 83 | 84 | /** 85 | * Height of the Blockly div (the view + the toolbox, simple of otherwise). 86 | * @type {number|undefined} 87 | */ 88 | Blockly.utils.Metrics.prototype.svgHeight; 89 | 90 | /** 91 | * Width of the Blockly div (the view + the toolbox, simple or otherwise). 92 | * @type {number|undefined} 93 | */ 94 | Blockly.utils.Metrics.prototype.svgWidth; 95 | 96 | /** 97 | * Width of the toolbox, if it exists. Otherwise zero. 98 | * @type {number|undefined} 99 | */ 100 | Blockly.utils.Metrics.prototype.toolboxWidth; 101 | 102 | /** 103 | * Height of the toolbox, if it exists. Otherwise zero. 104 | * @type {number|undefined} 105 | */ 106 | Blockly.utils.Metrics.prototype.toolboxHeight; 107 | 108 | /** 109 | * Top, bottom, left or right. Use TOOLBOX_AT constants to compare. 110 | * @type {number|undefined} 111 | */ 112 | Blockly.utils.Metrics.prototype.toolboxPosition; 113 | 114 | /** 115 | * Width of the flyout if it is always open. Otherwise zero. 116 | * @type {number|undefined} 117 | */ 118 | Blockly.utils.Metrics.prototype.flyoutWidth; 119 | 120 | /** 121 | * Height of the flyout if it is always open. Otherwise zero. 122 | * @type {number|undefined} 123 | */ 124 | Blockly.utils.Metrics.prototype.flyoutHeight; 125 | -------------------------------------------------------------------------------- /js/core/theme/highcontrast.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2018 Google LLC 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | /** 8 | * @fileoverview High contrast theme. 9 | * Darker colours to contrast the white font. 10 | */ 11 | 'use strict'; 12 | 13 | goog.provide('Blockly.Themes.HighContrast'); 14 | 15 | goog.require('Blockly.Theme'); 16 | 17 | 18 | // Temporary holding object. 19 | Blockly.Themes.HighContrast = {}; 20 | 21 | Blockly.Themes.HighContrast.defaultBlockStyles = { 22 | "colour_blocks": { 23 | "colourPrimary": "#a52714", 24 | "colourSecondary": "#FB9B8C", 25 | "colourTertiary": "#FBE1DD" 26 | }, 27 | "list_blocks": { 28 | "colourPrimary": "#4a148c", 29 | "colourSecondary": "#AD7BE9", 30 | "colourTertiary": "#CDB6E9" 31 | }, 32 | "logic_blocks": { 33 | "colourPrimary": "#01579b", 34 | "colourSecondary": "#64C7FF", 35 | "colourTertiary": "#C5EAFF" 36 | }, 37 | "loop_blocks": { 38 | "colourPrimary": "#33691e", 39 | "colourSecondary": "#9AFF78", 40 | "colourTertiary": "#E1FFD7" 41 | }, 42 | "math_blocks": { 43 | "colourPrimary": "#1a237e", 44 | "colourSecondary": "#8A9EFF", 45 | "colourTertiary": "#DCE2FF" 46 | }, 47 | "procedure_blocks": { 48 | "colourPrimary": "#006064", 49 | "colourSecondary": "#77E6EE", 50 | "colourTertiary": "#CFECEE" 51 | }, 52 | "text_blocks": { 53 | "colourPrimary": "#004d40", 54 | "colourSecondary": "#5ae27c", 55 | "colourTertiary": "#D2FFDD" 56 | }, 57 | "variable_blocks": { 58 | "colourPrimary": "#880e4f", 59 | "colourSecondary": "#FF73BE", 60 | "colourTertiary": "#FFD4EB" 61 | }, 62 | "variable_dynamic_blocks": { 63 | "colourPrimary": "#880e4f", 64 | "colourSecondary": "#FF73BE", 65 | "colourTertiary": "#FFD4EB" 66 | }, 67 | "hat_blocks": { 68 | "colourPrimary": "#880e4f", 69 | "colourSecondary": "#FF73BE", 70 | "colourTertiary": "#FFD4EB", 71 | "hat": "cap" 72 | } 73 | }; 74 | 75 | Blockly.Themes.HighContrast.categoryStyles = { 76 | "colour_category": { 77 | "colour": "#a52714" 78 | }, 79 | "list_category": { 80 | "colour": "#4a148c" 81 | }, 82 | "logic_category": { 83 | "colour": "#01579b" 84 | }, 85 | "loop_category": { 86 | "colour": "#33691e" 87 | }, 88 | "math_category": { 89 | "colour": "#1a237e" 90 | }, 91 | "procedure_category": { 92 | "colour": "#006064" 93 | }, 94 | "text_category": { 95 | "colour": "#004d40" 96 | }, 97 | "variable_category": { 98 | "colour": "#880e4f" 99 | }, 100 | "variable_dynamic_category": { 101 | "colour": "#880e4f" 102 | } 103 | }; 104 | 105 | // This style is still being fleshed out and may change. 106 | Blockly.Themes.HighContrast = 107 | new Blockly.Theme('highcontrast', 108 | Blockly.Themes.HighContrast.defaultBlockStyles, 109 | Blockly.Themes.HighContrast.categoryStyles); 110 | 111 | Blockly.Themes.HighContrast.setComponentStyle('selectedGlowColour', '#000000'); 112 | Blockly.Themes.HighContrast.setComponentStyle('selectedGlowSize', 1); 113 | Blockly.Themes.HighContrast.setComponentStyle('replacementGlowColour', '#000000'); 114 | 115 | Blockly.Themes.HighContrast.setFontStyle({ 116 | 'family': null, // Use default font-family 117 | 'weight': null, // Use default font-weight 118 | 'size': 16 119 | }); 120 | -------------------------------------------------------------------------------- /js/core/requires.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2019 Google LLC 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | /** 8 | * @fileoverview Default Blockly entry point. Use this to pick and choose which 9 | * fields and renderers to include in your Blockly bundle. 10 | * @author samelh@google.com (Sam El-Husseini) 11 | */ 12 | 'use strict'; 13 | 14 | goog.provide('Blockly.requires'); 15 | 16 | // Blockly Core (absolutely mandatory). 17 | goog.require('Blockly'); 18 | 19 | 20 | // If block comments aren't required, then Blockly.inject's "comments" 21 | // configuration must be false, and no blocks may be loaded from XML which 22 | // define comments. 23 | goog.require('Blockly.Comment'); 24 | // One of these two will almost certainly be needed (usually VerticalFlyout). 25 | goog.require('Blockly.HorizontalFlyout'); 26 | goog.require('Blockly.VerticalFlyout'); 27 | // Flyout buttons are needed by the variable category, 28 | // and by any custom toolbox that has a button or a label. 29 | goog.require('Blockly.FlyoutButton'); 30 | // If there is code generation into any language, then the generator is needed. 31 | // Should not be required when using advanced compilation since 32 | // individual generator files should already have this require. 33 | goog.require('Blockly.Generator'); 34 | // If the toolbox does not have categories and only has a simple flyout, then 35 | // 'Blockly.Toolbox' is not needed. 36 | goog.require('Blockly.Toolbox'); 37 | // If a trashcan on the workspace isn't required, then Blockly.inject's 38 | // "trashcan" configuration must be false. 39 | goog.require('Blockly.Trashcan'); 40 | // Only needed if one is using the 'VARIABLE_DYNAMIC' typed variables category. 41 | goog.require('Blockly.VariablesDynamic'); 42 | // Only need to require these two if you're using workspace comments. 43 | // goog.require('Blockly.WorkspaceCommentSvg'); 44 | // goog.require('Blockly.WorkspaceCommentSvg.render'); 45 | // If zoom controls aren't required, then Blockly.inject's 46 | // "zoom"/"controls" configuration must be false. 47 | goog.require('Blockly.ZoomControls'); 48 | 49 | 50 | // Block dependencies. 51 | // None of these should be required when using advanced compilation since 52 | // individual block files should include the requirements they depend on. 53 | goog.require('Blockly.Mutator'); 54 | goog.require('Blockly.Warning'); 55 | goog.require('Blockly.FieldAngle'); 56 | goog.require('Blockly.FieldCheckbox'); 57 | goog.require('Blockly.FieldColour'); 58 | goog.require('Blockly.FieldDropdown'); 59 | goog.require('Blockly.FieldLabelSerializable'); 60 | goog.require('Blockly.FieldImage'); 61 | goog.require('Blockly.FieldTextInput'); 62 | goog.require('Blockly.FieldMultilineInput'); 63 | goog.require('Blockly.FieldNumber'); 64 | goog.require('Blockly.FieldVariable'); 65 | 66 | 67 | // Blockly Renderers. 68 | // At least one renderer is mandatory. Geras is the default one. 69 | // Others may be chosen using Blockly.inject's "renderer" configuration. 70 | goog.require('Blockly.geras.Renderer'); 71 | goog.require('Blockly.thrasos.Renderer'); 72 | goog.require('Blockly.zelos.Renderer'); 73 | // The debug renderer, which shows simplified versions of the blocks for 74 | // developer use. 75 | // goog.require('Blockly.blockRendering.Debug'); 76 | 77 | // Blockly Themes. 78 | // Classic is the default theme. 79 | goog.require('Blockly.Themes.Classic'); 80 | goog.require('Blockly.Themes.Dark'); 81 | goog.require('Blockly.Themes.Deuteranopia'); 82 | goog.require('Blockly.Themes.HighContrast'); 83 | goog.require('Blockly.Themes.Tritanopia'); 84 | // goog.require('Blockly.Themes.Modern'); 85 | -------------------------------------------------------------------------------- /main.js: -------------------------------------------------------------------------------- 1 | // Modules to control application life and create native browser window 2 | const {app, BrowserWindow, shell, Menu, ipcMain} = require('electron') 3 | const path = require('path') 4 | const openAboutWindow = require('about-window').default 5 | 6 | function createWindow () { 7 | // Create the browser window. 8 | const mainWindow = new BrowserWindow({ 9 | width: 800, 10 | height: 600, 11 | webPreferences: { 12 | preload: path.join(__dirname, 'preload.js'), 13 | nodeIntegration: true, 14 | enableRemoteModule: true, 15 | } 16 | }) 17 | 18 | // The menubar template. 19 | const template = [ 20 | { 21 | label: 'File', 22 | submenu: [ 23 | { 24 | label: 'Exit', 25 | click() { 26 | mainWindow.close(); 27 | } 28 | } 29 | ] 30 | }, 31 | { 32 | label: 'View', 33 | submenu: [ 34 | { 35 | label: 'Reload', 36 | accelerator: 'CmdOrCtrl+R', 37 | click() { 38 | mainWindow.webContents.reload(); 39 | } 40 | }, 41 | { 42 | label: 'Toggle Developer Tools', 43 | accelerator: 'F12', 44 | click() { 45 | mainWindow.webContents.openDevTools(); 46 | } 47 | } 48 | ] 49 | }, 50 | { 51 | label: 'Help', 52 | submenu: [ 53 | { 54 | label: 'About', 55 | click() { 56 | openAboutWindow({ 57 | icon_path: path.join(__dirname, 'media', 'paia-logo.png'), 58 | package_json_dir: __dirname, 59 | win_options: { 60 | parent: mainWindow, 61 | modal: true 62 | }, 63 | bug_report_url: 'https://github.com/jason53415/blockly-app/issues' 64 | }); 65 | } 66 | } 67 | ] 68 | } 69 | ]; 70 | 71 | Menu.setApplicationMenu(Menu.buildFromTemplate(template)); 72 | 73 | // and load the index.html of the app. 74 | mainWindow.loadFile('index.html') 75 | // mainWindow.setMenuBarVisibility(false) 76 | 77 | // Open the DevTools. 78 | // mainWindow.webContents.openDevTools() 79 | var handleRedirect = (e, url) => { 80 | if(url.startsWith('http')) { 81 | e.preventDefault() 82 | shell.openExternal(url) 83 | } 84 | } 85 | 86 | mainWindow.webContents.on('will-navigate', handleRedirect) 87 | } 88 | 89 | // Make sure not launching multiple times during install on Windows. 90 | if (require('electron-squirrel-startup')) return app.quit(); 91 | 92 | // This method will be called when Electron has finished 93 | // initialization and is ready to create browser windows. 94 | // Some APIs can only be used after this event occurs. 95 | app.whenReady().then(() => { 96 | createWindow() 97 | 98 | app.on('activate', function () { 99 | // On macOS it's common to re-create a window in the app when the 100 | // dock icon is clicked and there are no other windows open. 101 | if (BrowserWindow.getAllWindows().length === 0) createWindow() 102 | }) 103 | }) 104 | 105 | // Quit when all windows are closed, except on macOS. There, it's common 106 | // for applications and their menu bar to stay active until the user quits 107 | // explicitly with Cmd + Q. 108 | app.on('window-all-closed', function () { 109 | if (process.platform !== 'darwin') app.quit() 110 | }) 111 | 112 | // In this file you can include the rest of your app's specific main process 113 | // code. You can also put them in separate files and require them here. 114 | -------------------------------------------------------------------------------- /js/core/renderers/zelos/measurables/rows.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2019 Google LLC 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | /** 8 | * @fileoverview An object representing a single row on a rendered block and all 9 | * of its subcomponents. 10 | * @author samelh@google.com (Sam El-Husseini) 11 | */ 12 | 'use strict'; 13 | 14 | goog.provide('Blockly.zelos.BottomRow'); 15 | goog.provide('Blockly.zelos.TopRow'); 16 | 17 | goog.require('Blockly.blockRendering.BottomRow'); 18 | goog.require('Blockly.blockRendering.TopRow'); 19 | goog.require('Blockly.blockRendering.SpacerRow'); 20 | goog.require('Blockly.utils.object'); 21 | 22 | 23 | /** 24 | * An object containing information about what elements are in the top row of a 25 | * block as well as sizing information for the top row. 26 | * Elements in a top row can consist of corners, hats, spacers, and previous 27 | * connections. 28 | * After this constructor is called, the row will contain all non-spacer 29 | * elements it needs. 30 | * @param {!Blockly.blockRendering.ConstantProvider} constants The rendering 31 | * constants provider. 32 | * @package 33 | * @constructor 34 | * @extends {Blockly.blockRendering.TopRow} 35 | */ 36 | Blockly.zelos.TopRow = function(constants) { 37 | Blockly.zelos.TopRow.superClass_.constructor.call(this, constants); 38 | }; 39 | Blockly.utils.object.inherits(Blockly.zelos.TopRow, 40 | Blockly.blockRendering.TopRow); 41 | 42 | /** 43 | * @override 44 | */ 45 | Blockly.zelos.TopRow.prototype.endsWithElemSpacer = function() { 46 | return false; 47 | }; 48 | 49 | /** 50 | * Render a round corner unless the block has an output connection. 51 | * @override 52 | */ 53 | Blockly.zelos.TopRow.prototype.hasLeftSquareCorner = function(block) { 54 | var hasHat = (block.hat ? 55 | block.hat === 'cap' : this.constants_.ADD_START_HATS) && 56 | !block.outputConnection && !block.previousConnection; 57 | return !!block.outputConnection || hasHat; 58 | }; 59 | 60 | /** 61 | * Render a round corner unless the block has an output connection. 62 | * @override 63 | */ 64 | Blockly.zelos.TopRow.prototype.hasRightSquareCorner = function(block) { 65 | return !!block.outputConnection && !block.statementInputCount && 66 | !block.nextConnection; 67 | }; 68 | 69 | /** 70 | * An object containing information about what elements are in the bottom row of 71 | * a block as well as spacing information for the top row. 72 | * Elements in a bottom row can consist of corners, spacers and next 73 | * connections. 74 | * @param {!Blockly.blockRendering.ConstantProvider} constants The rendering 75 | * constants provider. 76 | * @package 77 | * @constructor 78 | * @extends {Blockly.blockRendering.BottomRow} 79 | */ 80 | Blockly.zelos.BottomRow = function(constants) { 81 | Blockly.zelos.BottomRow.superClass_.constructor.call(this, constants); 82 | }; 83 | Blockly.utils.object.inherits(Blockly.zelos.BottomRow, 84 | Blockly.blockRendering.BottomRow); 85 | 86 | /** 87 | * @override 88 | */ 89 | Blockly.zelos.BottomRow.prototype.endsWithElemSpacer = function() { 90 | return false; 91 | }; 92 | 93 | /** 94 | * Render a round corner unless the block has an output connection. 95 | * @override 96 | */ 97 | Blockly.zelos.BottomRow.prototype.hasLeftSquareCorner = function(block) { 98 | return !!block.outputConnection; 99 | }; 100 | 101 | /** 102 | * Render a round corner unless the block has an output connection. 103 | * @override 104 | */ 105 | Blockly.zelos.BottomRow.prototype.hasRightSquareCorner = function(block) { 106 | return !!block.outputConnection && !block.statementInputCount && 107 | !block.nextConnection; 108 | }; 109 | -------------------------------------------------------------------------------- /js/generators/php/colour.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2015 Google LLC 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | /** 8 | * @fileoverview Generating PHP for colour blocks. 9 | * @author daarond@gmail.com (Daaron Dwyer) 10 | */ 11 | 'use strict'; 12 | 13 | goog.provide('Blockly.PHP.colour'); 14 | 15 | goog.require('Blockly.PHP'); 16 | 17 | 18 | Blockly.PHP['colour_picker'] = function(block) { 19 | // Colour picker. 20 | var code = Blockly.PHP.quote_(block.getFieldValue('COLOUR')); 21 | return [code, Blockly.PHP.ORDER_ATOMIC]; 22 | }; 23 | 24 | Blockly.PHP['colour_random'] = function(block) { 25 | // Generate a random colour. 26 | var functionName = Blockly.PHP.provideFunction_( 27 | 'colour_random', 28 | ['function ' + Blockly.PHP.FUNCTION_NAME_PLACEHOLDER_ + '() {', 29 | ' return \'#\' . str_pad(dechex(mt_rand(0, 0xFFFFFF)), ' + 30 | '6, \'0\', STR_PAD_LEFT);', 31 | '}']); 32 | var code = functionName + '()'; 33 | return [code, Blockly.PHP.ORDER_FUNCTION_CALL]; 34 | }; 35 | 36 | Blockly.PHP['colour_rgb'] = function(block) { 37 | // Compose a colour from RGB components expressed as percentages. 38 | var red = Blockly.PHP.valueToCode(block, 'RED', 39 | Blockly.PHP.ORDER_COMMA) || 0; 40 | var green = Blockly.PHP.valueToCode(block, 'GREEN', 41 | Blockly.PHP.ORDER_COMMA) || 0; 42 | var blue = Blockly.PHP.valueToCode(block, 'BLUE', 43 | Blockly.PHP.ORDER_COMMA) || 0; 44 | var functionName = Blockly.PHP.provideFunction_( 45 | 'colour_rgb', 46 | ['function ' + Blockly.PHP.FUNCTION_NAME_PLACEHOLDER_ + 47 | '($r, $g, $b) {', 48 | ' $r = round(max(min($r, 100), 0) * 2.55);', 49 | ' $g = round(max(min($g, 100), 0) * 2.55);', 50 | ' $b = round(max(min($b, 100), 0) * 2.55);', 51 | ' $hex = \'#\';', 52 | ' $hex .= str_pad(dechex($r), 2, \'0\', STR_PAD_LEFT);', 53 | ' $hex .= str_pad(dechex($g), 2, \'0\', STR_PAD_LEFT);', 54 | ' $hex .= str_pad(dechex($b), 2, \'0\', STR_PAD_LEFT);', 55 | ' return $hex;', 56 | '}']); 57 | var code = functionName + '(' + red + ', ' + green + ', ' + blue + ')'; 58 | return [code, Blockly.PHP.ORDER_FUNCTION_CALL]; 59 | }; 60 | 61 | Blockly.PHP['colour_blend'] = function(block) { 62 | // Blend two colours together. 63 | var c1 = Blockly.PHP.valueToCode(block, 'COLOUR1', 64 | Blockly.PHP.ORDER_COMMA) || '\'#000000\''; 65 | var c2 = Blockly.PHP.valueToCode(block, 'COLOUR2', 66 | Blockly.PHP.ORDER_COMMA) || '\'#000000\''; 67 | var ratio = Blockly.PHP.valueToCode(block, 'RATIO', 68 | Blockly.PHP.ORDER_COMMA) || 0.5; 69 | var functionName = Blockly.PHP.provideFunction_( 70 | 'colour_blend', 71 | ['function ' + Blockly.PHP.FUNCTION_NAME_PLACEHOLDER_ + 72 | '($c1, $c2, $ratio) {', 73 | ' $ratio = max(min($ratio, 1), 0);', 74 | ' $r1 = hexdec(substr($c1, 1, 2));', 75 | ' $g1 = hexdec(substr($c1, 3, 2));', 76 | ' $b1 = hexdec(substr($c1, 5, 2));', 77 | ' $r2 = hexdec(substr($c2, 1, 2));', 78 | ' $g2 = hexdec(substr($c2, 3, 2));', 79 | ' $b2 = hexdec(substr($c2, 5, 2));', 80 | ' $r = round($r1 * (1 - $ratio) + $r2 * $ratio);', 81 | ' $g = round($g1 * (1 - $ratio) + $g2 * $ratio);', 82 | ' $b = round($b1 * (1 - $ratio) + $b2 * $ratio);', 83 | ' $hex = \'#\';', 84 | ' $hex .= str_pad(dechex($r), 2, \'0\', STR_PAD_LEFT);', 85 | ' $hex .= str_pad(dechex($g), 2, \'0\', STR_PAD_LEFT);', 86 | ' $hex .= str_pad(dechex($b), 2, \'0\', STR_PAD_LEFT);', 87 | ' return $hex;', 88 | '}']); 89 | var code = functionName + '(' + c1 + ', ' + c2 + ', ' + ratio + ')'; 90 | return [code, Blockly.PHP.ORDER_FUNCTION_CALL]; 91 | }; 92 | -------------------------------------------------------------------------------- /js/blocks/colour.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2012 Google LLC 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | /** 8 | * @fileoverview Colour blocks for Blockly. 9 | * 10 | * This file is scraped to extract a .json file of block definitions. The array 11 | * passed to defineBlocksWithJsonArray(..) must be strict JSON: double quotes 12 | * only, no outside references, no functions, no trailing commas, etc. The one 13 | * exception is end-of-line comments, which the scraper will remove. 14 | * @author fraser@google.com (Neil Fraser) 15 | */ 16 | 'use strict'; 17 | 18 | goog.provide('Blockly.Blocks.colour'); // Deprecated 19 | goog.provide('Blockly.Constants.Colour'); 20 | 21 | goog.require('Blockly'); 22 | goog.require('Blockly.Blocks'); 23 | goog.require('Blockly.FieldColour'); 24 | goog.require('Blockly.FieldLabel'); 25 | 26 | 27 | /** 28 | * Unused constant for the common HSV hue for all blocks in this category. 29 | * @deprecated Use Blockly.Msg['COLOUR_HUE']. (2018 April 5) 30 | */ 31 | Blockly.Constants.Colour.HUE = 20; 32 | 33 | Blockly.defineBlocksWithJsonArray([ // BEGIN JSON EXTRACT 34 | // Block for colour picker. 35 | { 36 | "type": "colour_picker", 37 | "message0": "%1", 38 | "args0": [ 39 | { 40 | "type": "field_colour", 41 | "name": "COLOUR", 42 | "colour": "#ff0000" 43 | } 44 | ], 45 | "output": "Colour", 46 | "helpUrl": "%{BKY_COLOUR_PICKER_HELPURL}", 47 | "style": "colour_blocks", 48 | "tooltip": "%{BKY_COLOUR_PICKER_TOOLTIP}", 49 | "extensions": ["parent_tooltip_when_inline"] 50 | }, 51 | 52 | // Block for random colour. 53 | { 54 | "type": "colour_random", 55 | "message0": "%{BKY_COLOUR_RANDOM_TITLE}", 56 | "output": "Colour", 57 | "helpUrl": "%{BKY_COLOUR_RANDOM_HELPURL}", 58 | "style": "colour_blocks", 59 | "tooltip": "%{BKY_COLOUR_RANDOM_TOOLTIP}" 60 | }, 61 | 62 | // Block for composing a colour from RGB components. 63 | { 64 | "type": "colour_rgb", 65 | "message0": "%{BKY_COLOUR_RGB_TITLE} %{BKY_COLOUR_RGB_RED} %1 %{BKY_COLOUR_RGB_GREEN} %2 %{BKY_COLOUR_RGB_BLUE} %3", 66 | "args0": [ 67 | { 68 | "type": "input_value", 69 | "name": "RED", 70 | "check": "Number", 71 | "align": "RIGHT" 72 | }, 73 | { 74 | "type": "input_value", 75 | "name": "GREEN", 76 | "check": "Number", 77 | "align": "RIGHT" 78 | }, 79 | { 80 | "type": "input_value", 81 | "name": "BLUE", 82 | "check": "Number", 83 | "align": "RIGHT" 84 | } 85 | ], 86 | "output": "Colour", 87 | "helpUrl": "%{BKY_COLOUR_RGB_HELPURL}", 88 | "style": "colour_blocks", 89 | "tooltip": "%{BKY_COLOUR_RGB_TOOLTIP}" 90 | }, 91 | 92 | // Block for blending two colours together. 93 | { 94 | "type": "colour_blend", 95 | "message0": "%{BKY_COLOUR_BLEND_TITLE} %{BKY_COLOUR_BLEND_COLOUR1} " + 96 | "%1 %{BKY_COLOUR_BLEND_COLOUR2} %2 %{BKY_COLOUR_BLEND_RATIO} %3", 97 | "args0": [ 98 | { 99 | "type": "input_value", 100 | "name": "COLOUR1", 101 | "check": "Colour", 102 | "align": "RIGHT" 103 | }, 104 | { 105 | "type": "input_value", 106 | "name": "COLOUR2", 107 | "check": "Colour", 108 | "align": "RIGHT" 109 | }, 110 | { 111 | "type": "input_value", 112 | "name": "RATIO", 113 | "check": "Number", 114 | "align": "RIGHT" 115 | } 116 | ], 117 | "output": "Colour", 118 | "helpUrl": "%{BKY_COLOUR_BLEND_HELPURL}", 119 | "style": "colour_blocks", 120 | "tooltip": "%{BKY_COLOUR_BLEND_TOOLTIP}" 121 | } 122 | ]); // END JSON EXTRACT (Do not delete this comment.) 123 | -------------------------------------------------------------------------------- /media/pingpong.svg: -------------------------------------------------------------------------------- 1 | Pingpong_512 -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "blockly-app", 3 | "version": "1.2.6", 4 | "description": "A blockly application that can build AI to play games.", 5 | "main": "main.js", 6 | "scripts": { 7 | "start": "electron-forge start", 8 | "package": "electron-forge package", 9 | "make": "electron-forge make", 10 | "make-py": "cd ./python && pyinstaller -y --hidden-import=csv --hidden-import=pathlib --hidden-import=matplotlib.pyplot --hidden-import=pynput.keyboard._win32 --hidden-import=pynput.mouse._win32 --hidden-import=pynput.keyboard._darwin --hidden-import=pynput.mouse._darwin --hidden-import=pynput.keyboard._xorg --hidden-import=pynput.mouse._xorg --hidden-import=queue --hidden-import=pygame --hidden-import=multiprocessing --hidden-import=pickle --hidden-import=Box2D --hidden-import=sklearn.neighbors --hidden-import=sklearn.tree --hidden-import=sklearn.svm --hidden-import=sklearn.ensemble --hidden-import=sklearn.neural_network --hidden-import=sklearn.linear_model --hidden-import=sklearn.metrics --hidden-import=sklearn.model_selection --hidden-import=sklearn.utils._weight_vector --hidden-import=scipy.special.cython_special interpreter.py" 11 | }, 12 | "repository": "https://github.com/jason53415/blockly-app", 13 | "keywords": [ 14 | "Blockly", 15 | "Python", 16 | "MLGame", 17 | "AI" 18 | ], 19 | "author": "PAIA", 20 | "license": "CC0-1.0", 21 | "devDependencies": { 22 | "@electron-forge/cli": "^6.0.0-beta.54", 23 | "@electron-forge/maker-deb": "^6.0.0-beta.54", 24 | "@electron-forge/maker-dmg": "^6.0.0-beta.54", 25 | "@electron-forge/maker-rpm": "^6.0.0-beta.54", 26 | "@electron-forge/maker-squirrel": "^6.0.0-beta.54", 27 | "@electron-forge/maker-zip": "^6.0.0-beta.54", 28 | "electron": "^11.1.1" 29 | }, 30 | "dependencies": { 31 | "@paia-arena/blockly": "^0.0.3", 32 | "about-window": "^1.15.1", 33 | "bootstrap": "^4.1.3", 34 | "bootstrap-icons": "^1.5.0", 35 | "codemirror": "^5.61.1", 36 | "download-git-repo": "^3.0.2", 37 | "electron-installer-dmg": "^3.0.0", 38 | "electron-squirrel-startup": "^1.0.0", 39 | "electron-store": "^6.0.1", 40 | "github-markdown-css": "^4.0.0", 41 | "jquery": "^3.3.1", 42 | "popper.js": "^1.14.4", 43 | "python-shell": "^2.0.3", 44 | "showdown": "^1.9.1", 45 | "vex-js": "^4.1.0" 46 | }, 47 | "config": { 48 | "forge": { 49 | "packagerConfig": { 50 | "icon": "media/paia-logo", 51 | "ignore": [ 52 | "/.gitignore", 53 | "/.gitmodules", 54 | "/.vscode", 55 | "/requirements.txt", 56 | "/js/blocks", 57 | "/js/generators", 58 | "/js/i18n", 59 | "/js/mlgame", 60 | "/js/msg", 61 | "/js/build.py", 62 | "(.*)__pycache__", 63 | "/python/build", 64 | "/python/interpreter.spec", 65 | "/python/interpreter.py" 66 | ] 67 | }, 68 | "makers": [ 69 | { 70 | "name": "@electron-forge/maker-squirrel", 71 | "config": {} 72 | }, 73 | { 74 | "name": "@electron-forge/maker-zip", 75 | "platforms": [ 76 | "darwin", 77 | "win32" 78 | ] 79 | }, 80 | { 81 | "name": "@electron-forge/maker-dmg", 82 | "platforms": [ 83 | "darwin" 84 | ] 85 | }, 86 | { 87 | "name": "@electron-forge/maker-deb", 88 | "config": { 89 | "options": { 90 | "icon": "media/paia-logo.png" 91 | } 92 | } 93 | }, 94 | { 95 | "name": "@electron-forge/maker-rpm", 96 | "config": { 97 | "options": { 98 | "icon": "media/paia-logo.png" 99 | } 100 | } 101 | } 102 | ] 103 | } 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /js/core/utils/coordinate.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2019 Google LLC 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | /** 8 | * @fileoverview Utility methods for coordinate manipulation. 9 | * These methods are not specific to Blockly, and could be factored out into 10 | * a JavaScript framework such as Closure. 11 | * @author fraser@google.com (Neil Fraser) 12 | */ 13 | 'use strict'; 14 | 15 | /** 16 | * @name Blockly.utils.Coordinate 17 | * @namespace 18 | */ 19 | goog.provide('Blockly.utils.Coordinate'); 20 | 21 | 22 | /** 23 | * Class for representing coordinates and positions. 24 | * @param {number} x Left. 25 | * @param {number} y Top. 26 | * @struct 27 | * @constructor 28 | */ 29 | Blockly.utils.Coordinate = function(x, y) { 30 | /** 31 | * X-value 32 | * @type {number} 33 | */ 34 | this.x = x; 35 | 36 | /** 37 | * Y-value 38 | * @type {number} 39 | */ 40 | this.y = y; 41 | }; 42 | 43 | /** 44 | * Compares coordinates for equality. 45 | * @param {Blockly.utils.Coordinate} a A Coordinate. 46 | * @param {Blockly.utils.Coordinate} b A Coordinate. 47 | * @return {boolean} True iff the coordinates are equal, or if both are null. 48 | */ 49 | Blockly.utils.Coordinate.equals = function(a, b) { 50 | if (a == b) { 51 | return true; 52 | } 53 | if (!a || !b) { 54 | return false; 55 | } 56 | return a.x == b.x && a.y == b.y; 57 | }; 58 | 59 | /** 60 | * Returns the distance between two coordinates. 61 | * @param {!Blockly.utils.Coordinate} a A Coordinate. 62 | * @param {!Blockly.utils.Coordinate} b A Coordinate. 63 | * @return {number} The distance between `a` and `b`. 64 | */ 65 | Blockly.utils.Coordinate.distance = function(a, b) { 66 | var dx = a.x - b.x; 67 | var dy = a.y - b.y; 68 | return Math.sqrt(dx * dx + dy * dy); 69 | }; 70 | 71 | /** 72 | * Returns the magnitude of a coordinate. 73 | * @param {!Blockly.utils.Coordinate} a A Coordinate. 74 | * @return {number} The distance between the origin and `a`. 75 | */ 76 | Blockly.utils.Coordinate.magnitude = function(a) { 77 | return Math.sqrt(a.x * a.x + a.y * a.y); 78 | }; 79 | 80 | /** 81 | * Returns the difference between two coordinates as a new 82 | * Blockly.utils.Coordinate. 83 | * @param {!Blockly.utils.Coordinate|!SVGPoint} a An x/y coordinate. 84 | * @param {!Blockly.utils.Coordinate|!SVGPoint} b An x/y coordinate. 85 | * @return {!Blockly.utils.Coordinate} A Coordinate representing the difference 86 | * between `a` and `b`. 87 | */ 88 | Blockly.utils.Coordinate.difference = function(a, b) { 89 | return new Blockly.utils.Coordinate(a.x - b.x, a.y - b.y); 90 | }; 91 | 92 | /** 93 | * Returns the sum of two coordinates as a new Blockly.utils.Coordinate. 94 | * @param {!Blockly.utils.Coordinate|!SVGPoint} a An x/y coordinate. 95 | * @param {!Blockly.utils.Coordinate|!SVGPoint} b An x/y coordinate. 96 | * @return {!Blockly.utils.Coordinate} A Coordinate representing the sum of 97 | * the two coordinates. 98 | */ 99 | Blockly.utils.Coordinate.sum = function(a, b) { 100 | return new Blockly.utils.Coordinate(a.x + b.x, a.y + b.y); 101 | }; 102 | 103 | /** 104 | * Scales this coordinate by the given scale factor. 105 | * @param {number} s The scale factor to use for both x and y dimensions. 106 | * @return {!Blockly.utils.Coordinate} This coordinate after scaling. 107 | */ 108 | Blockly.utils.Coordinate.prototype.scale = function(s) { 109 | this.x *= s; 110 | this.y *= s; 111 | return this; 112 | }; 113 | 114 | /** 115 | * Translates this coordinate by the given offsets. 116 | * respectively. 117 | * @param {number} tx The value to translate x by. 118 | * @param {number} ty The value to translate y by. 119 | * @return {!Blockly.utils.Coordinate} This coordinate after translating. 120 | */ 121 | Blockly.utils.Coordinate.prototype.translate = function(tx, ty) { 122 | this.x += tx; 123 | this.y += ty; 124 | return this; 125 | }; 126 | --------------------------------------------------------------------------------