├── .DS_Store ├── LICENSE ├── README.md ├── Reblocks.png ├── Reblocks.png.import ├── Reblocksv2.svg ├── Reblocksv2.svg.import ├── block_code_node ├── block_code.gd ├── block_code.gd.uid ├── block_code_node.svg └── block_code_node.svg.import ├── block_code_plugin.gd ├── block_code_plugin.gd.uid ├── blocks ├── .DS_Store ├── communication │ ├── add_node_to_group.tres │ ├── add_to_group.tres │ ├── area2d_on_entered.tres │ ├── area2d_on_exited.tres │ ├── call_method_group.tres │ ├── call_method_node.tres │ ├── define_method.tres │ ├── get_node.gd │ ├── get_node.gd.uid │ ├── get_node.tres │ ├── groups.gd │ ├── groups.gd.uid │ ├── is_in_group.tres │ ├── is_node_in_group.tres │ ├── remove_from_group.tres │ ├── remove_node_from_group.tres │ ├── rigidbody2d_on_entered.tres │ ├── rigidbody2d_on_exited.tres │ └── switch_scene.tres ├── graphics │ ├── animationplayer_is_playing.tres │ ├── animationplayer_pause.tres │ ├── animationplayer_play.gd │ ├── animationplayer_play.gd.uid │ ├── animationplayer_play.tres │ ├── animationplayer_stop.tres │ ├── viewport_center.tres │ ├── viewport_height.tres │ └── viewport_width.tres ├── input │ ├── characterbody2d_is_on_floor.tres │ ├── characterbody2d_move.tres │ ├── is_input_actioned.gd │ ├── is_input_actioned.gd.uid │ └── is_input_actioned.tres ├── lifecycle │ ├── physics_process.tres │ ├── process.tres │ ├── queue_free.tres │ ├── queue_free_node.tres │ └── ready.tres ├── log │ ├── breakpoint.tres │ ├── comment.tres │ ├── concat.tres │ └── print.tres ├── logic │ ├── and.tres │ ├── compare.tres │ ├── else.tres │ ├── else_if.tres │ ├── flip.tres │ ├── if.tres │ ├── not.tres │ └── or.tres ├── loops │ ├── await_scene_ready.tres │ ├── break.tres │ ├── continue.tres │ ├── for.tres │ └── while.tres ├── math │ ├── add.tres │ ├── cos.tres │ ├── divide.tres │ ├── multiply.tres │ ├── pow.tres │ ├── randf_range.tres │ ├── randi_range.tres │ ├── sin.tres │ ├── subtract.tres │ ├── tan.tres │ ├── vector2_xy.tres │ ├── vector3_multiply.tres │ ├── vector3_xyz.tres │ ├── vector_from_angle.tres │ └── vector_multiply.tres ├── physics │ ├── characterbody2d_move_and_slide.tres │ └── characterbody3d_move_and_slide.tres ├── sounds │ ├── audiostreamplayer_play.tres │ ├── audiostreamplayer_stop.tres │ ├── load_sound.tres │ ├── pause_continue_sound.tres │ ├── play_sound.tres │ └── stop_sound.tres ├── spawn │ └── cpuparticles2d_finished.tres ├── transform │ └── rigidbody2d_physics_position.tres ├── ui │ └── label_set_text.tres └── variables │ ├── vector2.tres │ └── vector3.tres ├── code_generation ├── ast_list.gd ├── ast_list.gd.uid ├── block_ast.gd ├── block_ast.gd.uid ├── block_definition.gd ├── block_definition.gd.uid ├── block_extension.gd ├── block_extension.gd.uid ├── blocks_catalog.gd ├── blocks_catalog.gd.uid ├── option_data.gd ├── option_data.gd.uid ├── script_generator.gd ├── script_generator.gd.uid ├── util.gd ├── util.gd.uid ├── variable_definition.gd └── variable_definition.gd.uid ├── drag_manager ├── drag.gd ├── drag.gd.uid ├── drag_manager.gd ├── drag_manager.gd.uid └── drag_manager.tscn ├── image.png ├── image.png.import ├── inspector_plugin ├── block_script_inspector.gd └── block_script_inspector.gd.uid ├── locale ├── ar.po ├── az.po ├── bg.po ├── bn.po ├── ca.po ├── cs.po ├── de.po ├── el.po ├── eo.po ├── es.po ├── et.po ├── fa.po ├── fi.po ├── fr.po ├── ga.po ├── gl.po ├── godot_block_coding.pot ├── he.po ├── hi.po ├── hu.po ├── id.po ├── it.po ├── ja.po ├── ka.po ├── ko.po ├── lt.po ├── lv.po ├── mr.po ├── ms.po ├── nb.po ├── nl.po ├── pl.po ├── pt.po ├── ro.po ├── ru.po ├── si.po ├── sk.po ├── sl.po ├── sq.po ├── sv.po ├── sw.po ├── ta.po ├── th.po ├── tr.po ├── uk.po ├── vi.po ├── zh_CN.po └── zh_TW.po ├── plugin.cfg ├── serialization ├── block_script_serialization.gd ├── block_script_serialization.gd.uid ├── block_serialization.gd ├── block_serialization.gd.uid ├── block_serialization_tree.gd ├── block_serialization_tree.gd.uid ├── default_block_script.tres ├── value_block_serialization.gd └── value_block_serialization.gd.uid ├── translation ├── parser.gd ├── parser.gd.uid ├── utils.gd └── utils.gd.uid ├── types ├── types.gd └── types.gd.uid └── ui ├── block_canvas ├── block_canvas.gd ├── block_canvas.gd.uid └── block_canvas.tscn ├── block_editor_context.gd ├── block_editor_context.gd.uid ├── block_tree_util.gd ├── block_tree_util.gd.uid ├── blocks ├── block │ ├── block.gd │ └── block.gd.uid ├── control_block │ ├── control_block.gd │ ├── control_block.gd.uid │ └── control_block.tscn ├── entry_block │ ├── entry_block.gd │ ├── entry_block.gd.uid │ └── entry_block.tscn ├── parameter_block │ ├── parameter_block.gd │ ├── parameter_block.gd.uid │ └── parameter_block.tscn ├── statement_block │ ├── statement_block.gd │ ├── statement_block.gd.uid │ └── statement_block.tscn └── utilities │ ├── background │ ├── background.gd │ ├── background.gd.uid │ ├── gutter.gd │ └── gutter.gd.uid │ ├── drag_drop_area │ ├── drag_drop_area.gd │ ├── drag_drop_area.gd.uid │ └── drag_drop_area.tscn │ ├── parameter_input │ ├── parameter_input.gd │ ├── parameter_input.gd.uid │ └── parameter_input.tscn │ ├── parameter_output │ ├── parameter_output.gd │ ├── parameter_output.gd.uid │ └── parameter_output.tscn │ ├── snap_point │ ├── snap_point.gd │ ├── snap_point.gd.uid │ └── snap_point.tscn │ └── template_editor │ ├── collapsable_settings.gd │ ├── collapsable_settings.gd.uid │ ├── collapsable_settings.tscn │ ├── minus.svg │ ├── minus.svg.import │ ├── plus.svg │ ├── plus.svg.import │ ├── template_editor.gd │ ├── template_editor.gd.uid │ └── template_editor.tscn ├── constants.gd ├── constants.gd.uid ├── main_panel.gd ├── main_panel.gd.uid ├── main_panel.tscn ├── picker ├── categories │ ├── block_category.gd │ ├── block_category.gd.uid │ ├── block_category_button.gd │ ├── block_category_button.gd.uid │ ├── block_category_button.tscn │ ├── block_category_display.gd │ ├── block_category_display.gd.uid │ ├── block_category_display.tscn │ ├── category_factory.gd │ ├── category_factory.gd.uid │ ├── icons │ │ ├── communication.svg │ │ ├── communication.svg.import │ │ ├── file_broken.svg │ │ ├── file_broken.svg.import │ │ ├── graphics.svg │ │ ├── graphics.svg.import │ │ ├── info.svg │ │ ├── info.svg.import │ │ ├── input.svg │ │ ├── input.svg.import │ │ ├── lifecycle.svg │ │ ├── lifecycle.svg.import │ │ ├── log.svg │ │ ├── log.svg.import │ │ ├── logic.svg │ │ ├── logic.svg.import │ │ ├── loops.svg │ │ ├── loops.svg.import │ │ ├── math.svg │ │ ├── math.svg.import │ │ ├── physics.svg │ │ ├── physics.svg.import │ │ ├── sounds.svg │ │ ├── sounds.svg.import │ │ ├── transform.svg │ │ ├── transform.svg.import │ │ ├── ui.svg │ │ ├── ui.svg.import │ │ ├── variables.svg │ │ └── variables.svg.import │ └── variable_category │ │ ├── create_variable_button.gd │ │ ├── create_variable_button.gd.uid │ │ ├── create_variable_button.tscn │ │ ├── create_variable_dialog.gd │ │ ├── create_variable_dialog.gd.uid │ │ ├── create_variable_dialog.tscn │ │ ├── variable_category_display.gd │ │ ├── variable_category_display.gd.uid │ │ └── variable_category_display.tscn ├── picker.gd ├── picker.gd.uid └── picker.tscn ├── script_window ├── script_window.gd ├── script_window.gd.uid ├── script_window.tscn ├── split_script_window.gd ├── split_script_window.gd.uid └── split_script_window.tscn ├── title_bar ├── title_bar.gd ├── title_bar.gd.uid └── title_bar.tscn ├── tooltip ├── tooltip.gd ├── tooltip.gd.uid └── tooltip.tscn ├── util.gd └── util.gd.uid /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Redot-Experimental/reblocks/c80e8b09503556f4fba4c436dc7bb5dcb0c51804/.DS_Store -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Endless OS Foundation 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ReBlocks 2 | 3 | ![Reblocks](image.png) 4 | 5 | 6 | 7 | 8 | reblocks logo 9 | 10 | 11 | ReBlocks is a fork of the very good Block Coding plugin by [Endless OS Foundation](https://endlessos.org). While their mission is to provide a way to learn to program and eventually move to code, we want to provide a general use visual tool for making games, that will both enable users to make any kind of game they want without necessarily moving to code. 12 | 13 | ## Background 14 | 15 | From the very beginning of creating Redot, we've wanted both a community developed and supported, "official" visual scripting plugin that we could provide learning content, documentation, and examples for. Not to mention games. While this project is far from that goal, We fully intend to continue to develop and expand its capabilities, in order to eventually reach the goal of it being a solid, general use, game development alternative to coding. 16 | 17 | While there are other ways of visually programming a game, we feel that the block style is both an easy to learn, and closer to code-style where it does make it easier to pick up code if you wanted to. In that way, this tool will help people who want to learn to code but feel overwhelmed by code, to learn how to think logically and write in a more human way. 18 | 19 | On the other hand, there are plenty of people who just like the idea of visual scripting, have used other tools that are similar and would just like to continue with that paradigm. 20 | 21 | ## Current Status 22 | 23 | This plugin is under heavy development, and as such should not be used for general game development. we welcome anyone to download and give us feedback to help further development, as well as any help in the programming department. Currently the plugin is being developed by @Andevrs and @Takun. 24 | 25 | ## Feedback & Discussion 26 | 27 | Please join our [Discord](https://discord.gg/Z6WvTeN3kM) to provide feedback, share ideas, and ask questions. You can also join the general Redot [discord](https://discord.gg/redot) 28 | 29 | -------------------------------------------------------------------------------- /Reblocks.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Redot-Experimental/reblocks/c80e8b09503556f4fba4c436dc7bb5dcb0c51804/Reblocks.png -------------------------------------------------------------------------------- /Reblocks.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://b74a25ua3bnur" 6 | path="res://.godot/imported/Reblocks.png-d1c246f0c6f1f875f87739ecd7c3dff5.ctex" 7 | metadata={ 8 | "vram_texture": false 9 | } 10 | 11 | [deps] 12 | 13 | source_file="res://addons/reblocks/Reblocks.png" 14 | dest_files=["res://.godot/imported/Reblocks.png-d1c246f0c6f1f875f87739ecd7c3dff5.ctex"] 15 | 16 | [params] 17 | 18 | compress/mode=0 19 | compress/high_quality=false 20 | compress/lossy_quality=0.7 21 | compress/hdr_compression=1 22 | compress/normal_map=0 23 | compress/channel_pack=0 24 | mipmaps/generate=false 25 | mipmaps/limit=-1 26 | roughness/mode=0 27 | roughness/src_normal="" 28 | process/fix_alpha_border=true 29 | process/premult_alpha=false 30 | process/normal_map_invert_y=false 31 | process/hdr_as_srgb=false 32 | process/hdr_clamp_exposure=false 33 | process/size_limit=0 34 | detect_3d/compress_to=1 35 | -------------------------------------------------------------------------------- /Reblocksv2.svg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://gpnxcfitxm68" 6 | path="res://.godot/imported/Reblocksv2.svg-34a916730e874b867a7afb18294be04a.ctex" 7 | metadata={ 8 | "vram_texture": false 9 | } 10 | 11 | [deps] 12 | 13 | source_file="res://addons/reblocks/Reblocksv2.svg" 14 | dest_files=["res://.godot/imported/Reblocksv2.svg-34a916730e874b867a7afb18294be04a.ctex"] 15 | 16 | [params] 17 | 18 | compress/mode=0 19 | compress/high_quality=false 20 | compress/lossy_quality=0.7 21 | compress/hdr_compression=1 22 | compress/normal_map=0 23 | compress/channel_pack=0 24 | mipmaps/generate=false 25 | mipmaps/limit=-1 26 | roughness/mode=0 27 | roughness/src_normal="" 28 | process/fix_alpha_border=true 29 | process/premult_alpha=false 30 | process/normal_map_invert_y=false 31 | process/hdr_as_srgb=false 32 | process/hdr_clamp_exposure=false 33 | process/size_limit=0 34 | detect_3d/compress_to=1 35 | svg/scale=0.01 36 | editor/scale_with_editor_scale=false 37 | editor/convert_colors_with_editor_theme=false 38 | -------------------------------------------------------------------------------- /block_code_node/block_code.gd: -------------------------------------------------------------------------------- 1 | @tool 2 | @icon("res://addons/reblocks/block_code_node/block_code_node.svg") 3 | class_name BlockCode 4 | extends Node 5 | 6 | const TxUtils := preload("res://addons/reblocks/translation/utils.gd") 7 | 8 | @export var block_script: BlockScriptSerialization = null: 9 | set = _set_block_script 10 | 11 | 12 | func _init(): 13 | TxUtils.set_block_translation_domain(self) 14 | 15 | 16 | func _ready(): 17 | if Engine.is_editor_hint(): 18 | return 19 | 20 | _update_parent_script() 21 | 22 | 23 | func _get_custom_or_native_class(node: Node): 24 | if node.has_method("get_custom_class"): 25 | return node.get_custom_class() 26 | return node.get_class() 27 | 28 | 29 | func _enter_tree(): 30 | if not Engine.is_editor_hint(): 31 | return 32 | 33 | # Create script 34 | if block_script == null: 35 | var new_block_script: BlockScriptSerialization = load("res://addons/reblocks/serialization/default_block_script.tres").duplicate(true) 36 | new_block_script.script_inherits = _get_custom_or_native_class(get_parent()) 37 | new_block_script.generated_script = new_block_script.generated_script.replace("INHERIT_DEFAULT", new_block_script.script_inherits) 38 | block_script = new_block_script 39 | 40 | 41 | func _set_block_script(value): 42 | if value == null: 43 | # Wipe out the bidirectional link between this block code node and the 44 | # block script 45 | if block_script: 46 | block_script.block_code_node = null 47 | else: 48 | value.block_code_node = self 49 | block_script = value 50 | 51 | 52 | func _update_parent_script(): 53 | if Engine.is_editor_hint(): 54 | push_error("Updating the parent script must happen in game.") 55 | return 56 | 57 | var parent: Node = get_parent() 58 | var script := GDScript.new() 59 | script.set_source_code(block_script.generated_script) 60 | script.reload() 61 | 62 | # Persist export script variables (like SimpleCharacter exported texture) 63 | var persist_properties = {} 64 | var old_property_list = parent.get_property_list() 65 | for property in old_property_list: 66 | if property.usage & PROPERTY_USAGE_SCRIPT_VARIABLE: 67 | persist_properties[property.name] = parent.get(property.name) 68 | 69 | parent.set_script(script) 70 | parent.set_process(true) 71 | 72 | # Set persisted script variables in new script 73 | for property_name in persist_properties: 74 | parent.set(property_name, persist_properties.get(property_name)) 75 | 76 | # Run simple setup after node is ready 77 | if parent.has_method("simple_setup"): 78 | parent.call_deferred("simple_setup") 79 | 80 | 81 | func _get_configuration_warnings(): 82 | var warnings = [] 83 | if self.owner == null: 84 | warnings.append("A BlockCode must not be a root node.") 85 | if get_parent() is BlockCode: 86 | warnings.append("The parent must not be a BlockCode.") 87 | if get_parent().script: 88 | var parent_script_name: StringName = get_parent().script.get_global_name() 89 | if not (parent_script_name and block_script and parent_script_name == block_script.script_inherits): 90 | warnings.append("This BlockCode will override the existing script in the parent node.") 91 | if get_parent().find_children("*", "BlockCode", false).size() > 1: 92 | warnings.append("The parent should only contain one BlockCode.") 93 | if block_script and _get_custom_or_native_class(get_parent()) != block_script.script_inherits: 94 | var warning = "The parent is not a %s. Create a new BlockCode node and reattach." % block_script.script_inherits 95 | warnings.append(warning) 96 | return warnings 97 | -------------------------------------------------------------------------------- /block_code_node/block_code.gd.uid: -------------------------------------------------------------------------------- 1 | uid://bh3nmc4c3kefq 2 | -------------------------------------------------------------------------------- /block_code_node/block_code_node.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /block_code_node/block_code_node.svg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://cmusxj1ppspnp" 6 | path="res://.godot/imported/block_code_node.svg-c652aef58e872e066bb0462e7d6dc430.ctex" 7 | metadata={ 8 | "has_editor_variant": true, 9 | "vram_texture": false 10 | } 11 | 12 | [deps] 13 | 14 | source_file="res://addons/reblocks/block_code_node/block_code_node.svg" 15 | dest_files=["res://.godot/imported/block_code_node.svg-c652aef58e872e066bb0462e7d6dc430.ctex"] 16 | 17 | [params] 18 | 19 | compress/mode=0 20 | compress/high_quality=false 21 | compress/lossy_quality=0.7 22 | compress/hdr_compression=1 23 | compress/normal_map=0 24 | compress/channel_pack=0 25 | mipmaps/generate=false 26 | mipmaps/limit=-1 27 | roughness/mode=0 28 | roughness/src_normal="" 29 | process/fix_alpha_border=true 30 | process/premult_alpha=false 31 | process/normal_map_invert_y=false 32 | process/hdr_as_srgb=false 33 | process/hdr_clamp_exposure=false 34 | process/size_limit=0 35 | detect_3d/compress_to=1 36 | svg/scale=1.0 37 | editor/scale_with_editor_scale=true 38 | editor/convert_colors_with_editor_theme=true 39 | -------------------------------------------------------------------------------- /block_code_plugin.gd.uid: -------------------------------------------------------------------------------- 1 | uid://cvhc6iqgs7rj2 2 | -------------------------------------------------------------------------------- /blocks/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Redot-Experimental/reblocks/c80e8b09503556f4fba4c436dc7bb5dcb0c51804/blocks/.DS_Store -------------------------------------------------------------------------------- /blocks/communication/add_node_to_group.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Resource" load_steps=5 format=3 uid="uid://bpvefei72nh3a"] 2 | 3 | [ext_resource type="Script" path="res://addons/reblocks/code_generation/block_definition.gd" id="1_5qal7"] 4 | [ext_resource type="Script" path="res://addons/reblocks/code_generation/option_data.gd" id="1_auf06"] 5 | [ext_resource type="Script" path="res://addons/reblocks/blocks/communication/groups.gd" id="1_p83c7"] 6 | 7 | [sub_resource type="Resource" id="Resource_sus0f"] 8 | script = ExtResource("1_auf06") 9 | selected = 0 10 | items = [] 11 | 12 | [resource] 13 | script = ExtResource("1_5qal7") 14 | name = &"add_node_to_group" 15 | target_node_class = "" 16 | description = "Add the node into the group" 17 | category = "Communication | Groups" 18 | type = 2 19 | variant_type = 0 20 | display_template = "add {node: OBJECT} to group {group: STRING}" 21 | code_template = "{node}.add_to_group({group})" 22 | defaults = { 23 | "group": SubResource("Resource_sus0f") 24 | } 25 | signal_name = "" 26 | is_advanced = false 27 | extension_script = ExtResource("1_p83c7") 28 | -------------------------------------------------------------------------------- /blocks/communication/add_to_group.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Resource" load_steps=5 format=3 uid="uid://bvrmau8atjx1x"] 2 | 3 | [ext_resource type="Script" path="res://addons/reblocks/code_generation/option_data.gd" id="1_aom4j"] 4 | [ext_resource type="Script" path="res://addons/reblocks/code_generation/block_definition.gd" id="1_bcm71"] 5 | [ext_resource type="Script" path="res://addons/reblocks/blocks/communication/groups.gd" id="2_42ixf"] 6 | 7 | [sub_resource type="Resource" id="Resource_fk0wa"] 8 | script = ExtResource("1_aom4j") 9 | selected = 0 10 | items = [] 11 | 12 | [resource] 13 | script = ExtResource("1_bcm71") 14 | name = &"add_to_group" 15 | target_node_class = "" 16 | description = "Add this node into the group" 17 | category = "Communication | Groups" 18 | type = 2 19 | variant_type = 0 20 | display_template = "add to group {group: STRING}" 21 | code_template = "add_to_group({group})" 22 | defaults = { 23 | "group": SubResource("Resource_fk0wa") 24 | } 25 | signal_name = "" 26 | is_advanced = false 27 | extension_script = ExtResource("2_42ixf") 28 | -------------------------------------------------------------------------------- /blocks/communication/area2d_on_entered.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Resource" load_steps=2 format=3 uid="uid://de4k7t7uqws1j"] 2 | 3 | [ext_resource type="Script" path="res://addons/reblocks/code_generation/block_definition.gd" id="1_xotf5"] 4 | 5 | [resource] 6 | script = ExtResource("1_xotf5") 7 | name = &"area2d_on_entered" 8 | target_node_class = "Area2D" 9 | description = "" 10 | category = "Communication | Methods" 11 | type = 1 12 | variant_type = 0 13 | display_template = "when this node collides with [something: OBJECT]" 14 | code_template = "func _on_body_entered(something: Node2D):" 15 | defaults = {} 16 | signal_name = "body_entered" 17 | scope = "" 18 | -------------------------------------------------------------------------------- /blocks/communication/area2d_on_exited.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Resource" load_steps=2 format=3 uid="uid://b36nq4mau6lu6"] 2 | 3 | [ext_resource type="Script" path="res://addons/reblocks/code_generation/block_definition.gd" id="1_21qth"] 4 | 5 | [resource] 6 | script = ExtResource("1_21qth") 7 | name = &"area2d_on_exited" 8 | target_node_class = "Area2D" 9 | description = "" 10 | category = "Communication | Methods" 11 | type = 1 12 | variant_type = 0 13 | display_template = "when this node stops colliding with [something: OBJECT]" 14 | code_template = "func _on_body_exited(something: Node2D):" 15 | defaults = {} 16 | signal_name = "body_exited" 17 | scope = "" 18 | -------------------------------------------------------------------------------- /blocks/communication/call_method_group.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Resource" load_steps=5 format=3 uid="uid://c15vtdfihdxb8"] 2 | 3 | [ext_resource type="Script" path="res://addons/reblocks/code_generation/option_data.gd" id="1_3nuts"] 4 | [ext_resource type="Script" path="res://addons/reblocks/code_generation/block_definition.gd" id="1_mlm68"] 5 | [ext_resource type="Script" path="res://addons/reblocks/blocks/communication/groups.gd" id="1_of577"] 6 | 7 | [sub_resource type="Resource" id="Resource_f4ctg"] 8 | script = ExtResource("1_3nuts") 9 | selected = 0 10 | items = [] 11 | 12 | [resource] 13 | script = ExtResource("1_mlm68") 14 | name = &"call_method_group" 15 | target_node_class = "" 16 | description = "Calls the method/function on each member of the given group" 17 | category = "Communication | Methods" 18 | type = 2 19 | variant_type = 0 20 | display_template = "call method {method_name: STRING} in group {group: STRING}" 21 | code_template = "get_tree().call_group({group}, {method_name})" 22 | defaults = { 23 | "group": SubResource("Resource_f4ctg") 24 | } 25 | signal_name = "" 26 | is_advanced = false 27 | extension_script = ExtResource("1_of577") 28 | -------------------------------------------------------------------------------- /blocks/communication/call_method_node.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Resource" load_steps=2 format=3 uid="uid://c04j5flmimjvf"] 2 | 3 | [ext_resource type="Script" path="res://addons/reblocks/code_generation/block_definition.gd" id="1_pg363"] 4 | 5 | [resource] 6 | script = ExtResource("1_pg363") 7 | name = &"call_method_node" 8 | target_node_class = "" 9 | description = "Calls the method/function of the given node" 10 | category = "Communication | Methods" 11 | type = 2 12 | variant_type = 0 13 | display_template = "call method {method_name: STRING} on node {node: OBJECT}" 14 | code_template = "{node}.call({method_name})" 15 | defaults = {} 16 | signal_name = "" 17 | scope = "" 18 | -------------------------------------------------------------------------------- /blocks/communication/define_method.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Resource" load_steps=2 format=3 uid="uid://7r2b2griss3i"] 2 | 3 | [ext_resource type="Script" path="res://addons/reblocks/code_generation/block_definition.gd" id="1_6e473"] 4 | 5 | [resource] 6 | script = ExtResource("1_6e473") 7 | name = &"define_method" 8 | target_node_class = "" 9 | description = "Define a method/function with following statements" 10 | category = "Communication | Methods" 11 | type = 1 12 | variant_type = 0 13 | display_template = "define method {method_name: STRING_NAME}" 14 | code_template = "func {method_name}():" 15 | defaults = {} 16 | signal_name = "" 17 | scope = "" 18 | -------------------------------------------------------------------------------- /blocks/communication/get_node.gd: -------------------------------------------------------------------------------- 1 | @tool 2 | extends BlockExtension 3 | 4 | const OptionData = preload("res://addons/reblocks/code_generation/option_data.gd") 5 | const Util = preload("res://addons/reblocks/ui/util.gd") 6 | 7 | 8 | func _find_paths(paths: Array[NodePath], node: Node, path_root: Node, block_parent: Node): 9 | # Add any non-BlockCode nodes that aren't the parent of the current 10 | # BlockCode node. 11 | if not node is BlockCode: 12 | var node_path: NodePath = Util.node_scene_path(node, block_parent, path_root) 13 | if not node_path in [^"", ^"."]: 14 | paths.append(node_path) 15 | 16 | for child in node.get_children(): 17 | _find_paths(paths, child, path_root, block_parent) 18 | 19 | 20 | func get_defaults_for_node(context_node: Node) -> Dictionary: 21 | # The default paths are only needed in the editor. 22 | if not Engine.is_editor_hint(): 23 | return {} 24 | 25 | var scene_root: Node = EditorInterface.get_edited_scene_root() 26 | var path_root: Node = scene_root.get_parent() 27 | var paths: Array[NodePath] 28 | _find_paths(paths, scene_root, path_root, context_node) 29 | 30 | if not paths: 31 | return {} 32 | 33 | return {"path": OptionData.new(paths)} 34 | -------------------------------------------------------------------------------- /blocks/communication/get_node.gd.uid: -------------------------------------------------------------------------------- 1 | uid://dqb1cqabkq52o 2 | -------------------------------------------------------------------------------- /blocks/communication/get_node.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Resource" load_steps=5 format=3 uid="uid://canpdkahokjqs"] 2 | 3 | [ext_resource type="Script" path="res://addons/reblocks/code_generation/option_data.gd" id="1_bk47y"] 4 | [ext_resource type="Script" path="res://addons/reblocks/code_generation/block_definition.gd" id="1_d60g7"] 5 | [ext_resource type="Script" path="res://addons/reblocks/blocks/communication/get_node.gd" id="1_we5wl"] 6 | 7 | [sub_resource type="Resource" id="Resource_esr4a"] 8 | script = ExtResource("1_bk47y") 9 | selected = 0 10 | items = [] 11 | 12 | [resource] 13 | script = ExtResource("1_d60g7") 14 | name = &"get_node" 15 | target_node_class = "" 16 | description = "Get the node at the given path" 17 | category = "Communication | Nodes" 18 | type = 3 19 | variant_type = 24 20 | display_template = "{path: NIL}" 21 | code_template = "get_node(\"{path}\")" 22 | defaults = { 23 | "path": SubResource("Resource_esr4a") 24 | } 25 | signal_name = "" 26 | is_advanced = false 27 | extension_script = ExtResource("1_we5wl") 28 | 29 | -------------------------------------------------------------------------------- /blocks/communication/groups.gd: -------------------------------------------------------------------------------- 1 | @tool 2 | ## Common BlockExtension for scene group options. 3 | extends BlockExtension 4 | 5 | const OptionData = preload("res://addons/reblocks/code_generation/option_data.gd") 6 | 7 | 8 | # Global groups are just project settings in the global_group group. 9 | # ProjectSettings doesn't offer an API to get the project groups or to get all 10 | # settings. Fortunately, settings are simply implemented as properties on the 11 | # ProjectSettings object. 12 | static func _add_global_groups(groups: Dictionary): 13 | for prop in ProjectSettings.get_property_list(): 14 | var name: String = prop["name"] 15 | var parts := name.split("/", false, 1) 16 | if parts[0] == "global_group": 17 | groups[parts[1]] = null 18 | 19 | 20 | # Add all the groups in a node and its children, ignoring internal _ prefixed 21 | # groups. 22 | static func _add_node_groups(groups: Dictionary, node: Node): 23 | for group in node.get_groups(): 24 | if not group.begins_with("_"): 25 | groups[String(group)] = null 26 | 27 | for child in node.get_children(): 28 | _add_node_groups(groups, child) 29 | 30 | 31 | func _get_edited_scene_groups() -> Array[String]: 32 | var groups: Dictionary 33 | _add_global_groups(groups) 34 | 35 | var root := context_node.get_tree().edited_scene_root 36 | _add_node_groups(groups, root) 37 | 38 | var sorted_groups: Array[String] 39 | sorted_groups.assign(groups.keys()) 40 | sorted_groups.sort() 41 | return sorted_groups 42 | 43 | 44 | func _init(): 45 | # FIXME: Only global group changes are monitored. Scene local groups should 46 | # also be monitored, but godot does not have any reasonable API to do that. 47 | ProjectSettings.settings_changed.connect(_on_project_settings_changed) 48 | 49 | 50 | func _context_node_changed(): 51 | # If the context node changed, the scene local groups need to be updated. 52 | changed.emit() 53 | 54 | 55 | func get_defaults() -> Dictionary: 56 | if not context_node: 57 | return {} 58 | 59 | # The default groups are only needed in the editor. 60 | if not context_node.is_part_of_edited_scene(): 61 | return {} 62 | 63 | var groups: Array[String] = _get_edited_scene_groups() 64 | return {"group": OptionData.new(groups)} 65 | 66 | 67 | func _on_project_settings_changed(): 68 | # FIXME: The global groups should be cached and compared so that the 69 | # defaults are only changed when the global groups actually change. 70 | changed.emit() 71 | -------------------------------------------------------------------------------- /blocks/communication/groups.gd.uid: -------------------------------------------------------------------------------- 1 | uid://cgegsolf0rww1 2 | -------------------------------------------------------------------------------- /blocks/communication/is_in_group.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Resource" load_steps=5 format=3 uid="uid://q4cnstftvsiu"] 2 | 3 | [ext_resource type="Script" path="res://addons/reblocks/code_generation/option_data.gd" id="1_cla3i"] 4 | [ext_resource type="Script" path="res://addons/reblocks/code_generation/block_definition.gd" id="1_tjyq5"] 5 | [ext_resource type="Script" path="res://addons/reblocks/blocks/communication/groups.gd" id="2_o165d"] 6 | 7 | [sub_resource type="Resource" id="Resource_d0v0d"] 8 | script = ExtResource("1_cla3i") 9 | selected = 0 10 | items = [] 11 | 12 | [resource] 13 | script = ExtResource("1_tjyq5") 14 | name = &"is_in_group" 15 | target_node_class = "" 16 | description = "Is this node in the group" 17 | category = "Communication | Groups" 18 | type = 3 19 | variant_type = 1 20 | display_template = "is in group {group: STRING}" 21 | code_template = "is_in_group({group})" 22 | defaults = { 23 | "group": SubResource("Resource_d0v0d") 24 | } 25 | signal_name = "" 26 | is_advanced = false 27 | extension_script = ExtResource("2_o165d") 28 | -------------------------------------------------------------------------------- /blocks/communication/is_node_in_group.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Resource" load_steps=5 format=3 uid="uid://bbtdxeey74x67"] 2 | 3 | [ext_resource type="Script" path="res://addons/reblocks/code_generation/block_definition.gd" id="1_5krrs"] 4 | [ext_resource type="Script" path="res://addons/reblocks/blocks/communication/groups.gd" id="1_r4prw"] 5 | [ext_resource type="Script" path="res://addons/reblocks/code_generation/option_data.gd" id="1_y4j0k"] 6 | 7 | [sub_resource type="Resource" id="Resource_o38ym"] 8 | script = ExtResource("1_y4j0k") 9 | selected = 0 10 | items = [] 11 | 12 | [resource] 13 | script = ExtResource("1_5krrs") 14 | name = &"is_node_in_group" 15 | target_node_class = "" 16 | description = "Is the node in the group" 17 | category = "Communication | Groups" 18 | type = 3 19 | variant_type = 1 20 | display_template = "{node: OBJECT} is in group {group: STRING}" 21 | code_template = "{node}.is_in_group({group})" 22 | defaults = { 23 | "group": SubResource("Resource_o38ym") 24 | } 25 | signal_name = "" 26 | is_advanced = false 27 | extension_script = ExtResource("1_r4prw") 28 | -------------------------------------------------------------------------------- /blocks/communication/remove_from_group.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Resource" load_steps=5 format=3 uid="uid://dgenw5wyqorvq"] 2 | 3 | [ext_resource type="Script" path="res://addons/reblocks/code_generation/block_definition.gd" id="1_cdwef"] 4 | [ext_resource type="Script" path="res://addons/reblocks/blocks/communication/groups.gd" id="1_i50fw"] 5 | [ext_resource type="Script" path="res://addons/reblocks/code_generation/option_data.gd" id="1_mnxp7"] 6 | 7 | [sub_resource type="Resource" id="Resource_45b71"] 8 | script = ExtResource("1_mnxp7") 9 | selected = 0 10 | items = [] 11 | 12 | [resource] 13 | script = ExtResource("1_cdwef") 14 | name = &"remove_from_group" 15 | target_node_class = "" 16 | description = "Remove this node from the group" 17 | category = "Communication | Groups" 18 | type = 2 19 | variant_type = 0 20 | display_template = "remove from group {group: STRING}" 21 | code_template = "remove_from_group({group})" 22 | defaults = { 23 | "group": SubResource("Resource_45b71") 24 | } 25 | signal_name = "" 26 | is_advanced = false 27 | extension_script = ExtResource("1_i50fw") 28 | -------------------------------------------------------------------------------- /blocks/communication/remove_node_from_group.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Resource" load_steps=5 format=3 uid="uid://b2dwk77hnri8y"] 2 | 3 | [ext_resource type="Script" path="res://addons/reblocks/code_generation/option_data.gd" id="1_clwhe"] 4 | [ext_resource type="Script" path="res://addons/reblocks/blocks/communication/groups.gd" id="1_h3lhb"] 5 | [ext_resource type="Script" path="res://addons/reblocks/code_generation/block_definition.gd" id="1_pec24"] 6 | 7 | [sub_resource type="Resource" id="Resource_03rge"] 8 | script = ExtResource("1_clwhe") 9 | selected = 0 10 | items = [] 11 | 12 | [resource] 13 | script = ExtResource("1_pec24") 14 | name = &"remove_node_from_group" 15 | target_node_class = "" 16 | description = "Remove the node from the group" 17 | category = "Communication | Groups" 18 | type = 2 19 | variant_type = 0 20 | display_template = "remove {node: OBJECT} from group {group: NIL}" 21 | code_template = "{node}.remove_from_group(\\\"{group}\\\")" 22 | defaults = { 23 | "group": SubResource("Resource_03rge") 24 | } 25 | signal_name = "" 26 | is_advanced = false 27 | extension_script = ExtResource("1_h3lhb") 28 | -------------------------------------------------------------------------------- /blocks/communication/rigidbody2d_on_entered.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Resource" load_steps=2 format=3 uid="uid://dl1xd1jit2mlp"] 2 | 3 | [ext_resource type="Script" path="res://addons/reblocks/code_generation/block_definition.gd" id="1_v2421"] 4 | 5 | [resource] 6 | script = ExtResource("1_v2421") 7 | name = &"rigidbody2d_on_entered" 8 | target_node_class = "RigidBody2D" 9 | description = "" 10 | category = "Communication | Methods" 11 | type = 1 12 | variant_type = 0 13 | display_template = "when this node collides with [something: OBJECT]" 14 | code_template = "func _on_body_entered(something: Node2D):" 15 | defaults = {} 16 | signal_name = "body_entered" 17 | scope = "" 18 | -------------------------------------------------------------------------------- /blocks/communication/rigidbody2d_on_exited.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Resource" load_steps=2 format=3 uid="uid://c15ymi1kxb570"] 2 | 3 | [ext_resource type="Script" path="res://addons/reblocks/code_generation/block_definition.gd" id="1_sahiu"] 4 | 5 | [resource] 6 | script = ExtResource("1_sahiu") 7 | name = &"rigidbody2d_on_exited" 8 | target_node_class = "RigidBody2D" 9 | description = "" 10 | category = "Communication | Methods" 11 | type = 1 12 | variant_type = 0 13 | display_template = "when this node stops colliding with [something: OBJECT]" 14 | code_template = "func _on_body_exited(something: Node2D):" 15 | defaults = {} 16 | signal_name = "body_exited" 17 | scope = "" 18 | -------------------------------------------------------------------------------- /blocks/communication/switch_scene.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Resource" load_steps=2 format=3 uid="uid://dnc2555wnobks"] 2 | 3 | [ext_resource type="Script" path="res://addons/reblocks/code_generation/block_definition.gd" id="1_rnqd5"] 4 | 5 | [resource] 6 | script = ExtResource("1_rnqd5") 7 | name = &"switch_scene" 8 | target_node_class = "" 9 | description = "Stop playing the current scene, and switch to a different one. You might use this to switch to a new level." 10 | category = "Communication | Methods" 11 | type = 2 12 | variant_type = 0 13 | display_template = "switch the scene to {file_path: STRING}" 14 | code_template = "get_tree().change_scene_to_file({file_path}) 15 | " 16 | defaults = {} 17 | signal_name = "" 18 | scope = "" 19 | -------------------------------------------------------------------------------- /blocks/graphics/animationplayer_is_playing.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Resource" load_steps=2 format=3 uid="uid://mg4y3o0rsqd5"] 2 | 3 | [ext_resource type="Script" path="res://addons/reblocks/code_generation/block_definition.gd" id="1_xr50b"] 4 | 5 | [resource] 6 | script = ExtResource("1_xr50b") 7 | name = &"animationplayer_is_playing" 8 | target_node_class = "AnimationPlayer" 9 | description = "Check if an animation is currently playing." 10 | category = "Graphics | Animation" 11 | type = 3 12 | variant_type = 1 13 | display_template = "is playing" 14 | code_template = "is_playing()" 15 | defaults = {} 16 | signal_name = "" 17 | scope = "" 18 | -------------------------------------------------------------------------------- /blocks/graphics/animationplayer_pause.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Resource" load_steps=2 format=3 uid="uid://clopo7gmje5a"] 2 | 3 | [ext_resource type="Script" path="res://addons/reblocks/code_generation/block_definition.gd" id="1_2enqv"] 4 | 5 | [resource] 6 | script = ExtResource("1_2enqv") 7 | name = &"animationplayer_pause" 8 | target_node_class = "AnimationPlayer" 9 | description = "Pause the currently playing animation." 10 | category = "Graphics | Animation" 11 | type = 2 12 | variant_type = 0 13 | display_template = "pause" 14 | code_template = "pause()" 15 | defaults = {} 16 | signal_name = "" 17 | scope = "" 18 | -------------------------------------------------------------------------------- /blocks/graphics/animationplayer_play.gd: -------------------------------------------------------------------------------- 1 | @tool 2 | extends BlockExtension 3 | 4 | const OptionData = preload("res://addons/reblocks/code_generation/option_data.gd") 5 | 6 | 7 | func get_defaults() -> Dictionary: 8 | var animation_player = context_node as AnimationPlayer 9 | 10 | if not animation_player: 11 | return {} 12 | 13 | var animation_list = animation_player.get_animation_list() 14 | 15 | return {"animation": OptionData.new(animation_list)} 16 | 17 | 18 | func _context_node_changed(): 19 | var animation_player = context_node as AnimationPlayer 20 | 21 | if not animation_player: 22 | return 23 | 24 | animation_player.animation_list_changed.connect(_on_animation_list_changed) 25 | 26 | 27 | func _on_animation_list_changed(): 28 | _emit_changed() 29 | -------------------------------------------------------------------------------- /blocks/graphics/animationplayer_play.gd.uid: -------------------------------------------------------------------------------- 1 | uid://cx6c5ey7kmdcp 2 | -------------------------------------------------------------------------------- /blocks/graphics/animationplayer_play.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Resource" load_steps=5 format=3 uid="uid://c5e1byehtxwc0"] 2 | 3 | [ext_resource type="Script" path="res://addons/reblocks/code_generation/block_definition.gd" id="1_emeuv"] 4 | [ext_resource type="Script" path="res://addons/reblocks/code_generation/option_data.gd" id="1_xu43h"] 5 | [ext_resource type="Script" path="res://addons/reblocks/blocks/graphics/animationplayer_play.gd" id="2_7ymgi"] 6 | 7 | [sub_resource type="Resource" id="Resource_qpxn2"] 8 | script = ExtResource("1_xu43h") 9 | selected = 0 10 | items = [] 11 | 12 | [resource] 13 | script = ExtResource("1_emeuv") 14 | name = &"animationplayer_play" 15 | target_node_class = "AnimationPlayer" 16 | description = "Play the animation." 17 | category = "Graphics | Animation" 18 | type = 2 19 | variant_type = 0 20 | display_template = "play {animation: STRING}" 21 | code_template = "play({animation}) 22 | 23 | 24 | " 25 | defaults = { 26 | "animation": SubResource("Resource_qpxn2") 27 | } 28 | signal_name = "" 29 | is_advanced = false 30 | extension_script = ExtResource("2_7ymgi") 31 | -------------------------------------------------------------------------------- /blocks/graphics/animationplayer_stop.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Resource" load_steps=2 format=3 uid="uid://b4v00oxoxbfet"] 2 | 3 | [ext_resource type="Script" path="res://addons/reblocks/code_generation/block_definition.gd" id="1_wp8gr"] 4 | 5 | [resource] 6 | script = ExtResource("1_wp8gr") 7 | name = &"animationplayer_stop" 8 | target_node_class = "AnimationPlayer" 9 | description = "Stop the currently playing animation." 10 | category = "Graphics | Animation" 11 | type = 2 12 | variant_type = 0 13 | display_template = "stop" 14 | code_template = "stop()" 15 | defaults = {} 16 | signal_name = "" 17 | scope = "" 18 | -------------------------------------------------------------------------------- /blocks/graphics/viewport_center.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Resource" load_steps=2 format=3 uid="uid://1536itmdu8yo"] 2 | 3 | [ext_resource type="Script" path="res://addons/reblocks/code_generation/block_definition.gd" id="1_rc1so"] 4 | 5 | [resource] 6 | script = ExtResource("1_rc1so") 7 | name = &"viewport_center" 8 | target_node_class = "" 9 | description = "Coordinates of the middle of the viewable screen when playing." 10 | category = "Graphics | Viewport" 11 | type = 3 12 | variant_type = 5 13 | display_template = "viewport center" 14 | code_template = "(func (): var transform: Transform2D = get_viewport_transform(); var scale: Vector2 = transform.get_scale(); return -transform.origin / scale + get_viewport_rect().size / scale / 2).call()" 15 | defaults = {} 16 | signal_name = "" 17 | scope = "" 18 | -------------------------------------------------------------------------------- /blocks/graphics/viewport_height.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Resource" load_steps=2 format=3 uid="uid://bdm4yr68mdf4d"] 2 | 3 | [ext_resource type="Script" path="res://addons/reblocks/code_generation/block_definition.gd" id="1_1debb"] 4 | 5 | [resource] 6 | script = ExtResource("1_1debb") 7 | name = &"viewport_height" 8 | target_node_class = "" 9 | description = "How tall the viewable screen is when playing." 10 | category = "Graphics | Viewport" 11 | type = 3 12 | variant_type = 3 13 | display_template = "viewport height" 14 | code_template = "(func (): var transform: Transform2D = get_viewport_transform(); var scale: Vector2 = transform.get_scale(); return -transform.origin.y / scale.y + get_viewport_rect().size.y / scale.y).call()" 15 | defaults = {} 16 | signal_name = "" 17 | scope = "" 18 | -------------------------------------------------------------------------------- /blocks/graphics/viewport_width.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Resource" load_steps=2 format=3 uid="uid://bt78ajp56ga24"] 2 | 3 | [ext_resource type="Script" path="res://addons/reblocks/code_generation/block_definition.gd" id="1_ll4rh"] 4 | 5 | [resource] 6 | script = ExtResource("1_ll4rh") 7 | name = &"viewport_width" 8 | target_node_class = "" 9 | description = "How wide the viewable screen is when playing." 10 | category = "Graphics | Viewport" 11 | type = 3 12 | variant_type = 3 13 | display_template = "viewport width" 14 | code_template = "(func (): var transform: Transform2D = get_viewport_transform(); var scale: Vector2 = transform.get_scale(); return -transform.origin.x / scale.x + get_viewport_rect().size.x / scale.x).call()" 15 | defaults = {} 16 | signal_name = "" 17 | scope = "" 18 | -------------------------------------------------------------------------------- /blocks/input/characterbody2d_is_on_floor.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Resource" load_steps=2 format=3 uid="uid://cbpicqif1ddro"] 2 | 3 | [ext_resource type="Script" path="res://addons/reblocks/code_generation/block_definition.gd" id="1_btxic"] 4 | 5 | [resource] 6 | script = ExtResource("1_btxic") 7 | name = &"characterbody2d_is_on_floor" 8 | target_node_class = "CharacterBody2D" 9 | description = "True if the character is on the floor." 10 | category = "Physics | Velocity" 11 | type = 3 12 | variant_type = 1 13 | display_template = "is on floor" 14 | code_template = "is_on_floor()" 15 | defaults = {} 16 | signal_name = "" 17 | scope = "" 18 | -------------------------------------------------------------------------------- /blocks/input/characterbody2d_move.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Resource" load_steps=2 format=3 uid="uid://cu3ru61vg6bx5"] 2 | 3 | [ext_resource type="Script" path="res://addons/reblocks/code_generation/block_definition.gd" id="1_btxic"] 4 | 5 | [resource] 6 | script = ExtResource("1_btxic") 7 | name = &"characterbody2d_move" 8 | target_node_class = "CharacterBody2D" 9 | description = "Move the character up, down, left, and right with the keyboard using the given keys. The speed of movement can be adjusted separately for x (left and right) and y (up and down)." 10 | category = "Input" 11 | type = 2 12 | variant_type = 0 13 | display_template = "move with keys {up: STRING} {down: STRING} {left: STRING} {right: STRING} at speed {speed: VECTOR2}" 14 | code_template = "var dir = Vector2() 15 | dir.x += float(Input.is_key_pressed(OS.find_keycode_from_string({right}))) 16 | dir.x -= float(Input.is_key_pressed(OS.find_keycode_from_string({left}))) 17 | dir.y += float(Input.is_key_pressed(OS.find_keycode_from_string({down}))) 18 | dir.y -= float(Input.is_key_pressed(OS.find_keycode_from_string({up}))) 19 | dir = dir.normalized() 20 | velocity = dir*{speed} 21 | move_and_slide() 22 | " 23 | defaults = { 24 | "down": "S", 25 | "left": "A", 26 | "right": "D", 27 | "speed": Vector2(100, 100), 28 | "up": "W" 29 | } 30 | signal_name = "" 31 | scope = "" 32 | -------------------------------------------------------------------------------- /blocks/input/is_input_actioned.gd: -------------------------------------------------------------------------------- 1 | @tool 2 | extends BlockExtension 3 | 4 | const OptionData = preload("res://addons/reblocks/code_generation/option_data.gd") 5 | 6 | 7 | func get_defaults() -> Dictionary: 8 | var inputmap_actions = _get_inputmap_actions() 9 | return {"action_name": OptionData.new(inputmap_actions)} 10 | 11 | 12 | static func _get_inputmap_actions() -> Array[StringName]: 13 | var inputmap_actions: Array[StringName] 14 | 15 | var editor_input_actions: Dictionary = {} 16 | var editor_input_action_deadzones: Dictionary = {} 17 | if Engine.is_editor_hint(): 18 | var actions := InputMap.get_actions() 19 | for action in actions: 20 | if action.begins_with("spatial_editor"): 21 | var events := InputMap.action_get_events(action) 22 | editor_input_actions[action] = events 23 | editor_input_action_deadzones[action] = InputMap.action_get_deadzone(action) 24 | 25 | InputMap.load_from_project_settings() 26 | 27 | inputmap_actions = InputMap.get_actions() 28 | 29 | if Engine.is_editor_hint(): 30 | for action in editor_input_actions.keys(): 31 | InputMap.add_action(action, editor_input_action_deadzones[action]) 32 | for event in editor_input_actions[action]: 33 | InputMap.action_add_event(action, event) 34 | 35 | return inputmap_actions 36 | -------------------------------------------------------------------------------- /blocks/input/is_input_actioned.gd.uid: -------------------------------------------------------------------------------- 1 | uid://dg44v8wyteiqi 2 | -------------------------------------------------------------------------------- /blocks/input/is_input_actioned.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Resource" load_steps=5 format=3 uid="uid://86j17le5e58u"] 2 | 3 | [ext_resource type="Script" path="res://addons/reblocks/code_generation/option_data.gd" id="1_d8i05"] 4 | [ext_resource type="Script" path="res://addons/reblocks/code_generation/block_definition.gd" id="1_rprh7"] 5 | [ext_resource type="Script" path="res://addons/reblocks/blocks/input/is_input_actioned.gd" id="2_h11b7"] 6 | 7 | [sub_resource type="Resource" id="Resource_ai5in"] 8 | script = ExtResource("1_d8i05") 9 | selected = 0 10 | items = ["pressed", "just_pressed", "just_released"] 11 | 12 | [resource] 13 | script = ExtResource("1_rprh7") 14 | name = &"is_input_actioned" 15 | target_node_class = "" 16 | description = "True if the specified input action has been pressed or released." 17 | category = "Input" 18 | type = 3 19 | variant_type = 1 20 | display_template = "action {action_name: STRING_NAME} is {action: NIL}" 21 | code_template = "Input.is_action_{{action}}('{{action_name}}')" 22 | defaults = { 23 | "action": SubResource("Resource_ai5in") 24 | } 25 | signal_name = "" 26 | is_advanced = false 27 | extension_script = ExtResource("2_h11b7") 28 | -------------------------------------------------------------------------------- /blocks/lifecycle/physics_process.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Resource" load_steps=2 format=3 uid="uid://3l8wefwlme2v"] 2 | 3 | [ext_resource type="Script" path="res://addons/reblocks/code_generation/block_definition.gd" id="1_pmina"] 4 | 5 | [resource] 6 | script = ExtResource("1_pmina") 7 | name = &"physics_process" 8 | target_node_class = "" 9 | description = "Attached blocks will be executed before each physics step" 10 | category = "Lifecycle" 11 | type = 1 12 | variant_type = 0 13 | display_template = "every physics step" 14 | code_template = "func _physics_process(delta):" 15 | defaults = {} 16 | signal_name = "" 17 | scope = "" 18 | is_advanced = true 19 | -------------------------------------------------------------------------------- /blocks/lifecycle/process.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Resource" load_steps=2 format=3 uid="uid://chioedvp50013"] 2 | 3 | [ext_resource type="Script" path="res://addons/reblocks/code_generation/block_definition.gd" id="1_pmina"] 4 | 5 | [resource] 6 | script = ExtResource("1_pmina") 7 | name = &"process" 8 | target_node_class = "" 9 | description = "Attached blocks will be executed during the processing step of the main loop" 10 | category = "Lifecycle" 11 | type = 1 12 | variant_type = 0 13 | display_template = "every frame" 14 | code_template = "func _process(delta):" 15 | defaults = {} 16 | signal_name = "" 17 | scope = "" 18 | -------------------------------------------------------------------------------- /blocks/lifecycle/queue_free.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Resource" load_steps=2 format=3 uid="uid://4hj5b3xaiuy8"] 2 | 3 | [ext_resource type="Script" path="res://addons/reblocks/code_generation/block_definition.gd" id="1_75fle"] 4 | 5 | [resource] 6 | script = ExtResource("1_75fle") 7 | name = &"queue_free" 8 | target_node_class = "" 9 | description = "Queues this node to be deleted at the end of the current frame" 10 | category = "Lifecycle" 11 | type = 2 12 | variant_type = 0 13 | display_template = "remove" 14 | code_template = "queue_free()" 15 | defaults = {} 16 | signal_name = "" 17 | scope = "" 18 | -------------------------------------------------------------------------------- /blocks/lifecycle/queue_free_node.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Resource" load_steps=2 format=3 uid="uid://d31lkxkm5lww7"] 2 | 3 | [ext_resource type="Script" path="res://addons/reblocks/code_generation/block_definition.gd" id="1_75fle"] 4 | 5 | [resource] 6 | script = ExtResource("1_75fle") 7 | name = &"queue_free_node" 8 | target_node_class = "" 9 | description = "Queues the given node to be deleted at the end of the current frame" 10 | category = "Lifecycle" 11 | type = 2 12 | variant_type = 0 13 | display_template = "remove {node: OBJECT}" 14 | code_template = "{node}.queue_free()" 15 | defaults = {} 16 | signal_name = "" 17 | scope = "" 18 | -------------------------------------------------------------------------------- /blocks/lifecycle/ready.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Resource" load_steps=2 format=3 uid="uid://dgwfoepoejlom"] 2 | 3 | [ext_resource type="Script" path="res://addons/reblocks/code_generation/block_definition.gd" id="1_vk0xk"] 4 | 5 | [resource] 6 | script = ExtResource("1_vk0xk") 7 | name = &"ready" 8 | target_node_class = "" 9 | description = "Attached blocks will be executed once when the node is \"ready\"" 10 | category = "Lifecycle" 11 | type = 1 12 | variant_type = 0 13 | display_template = "when starting" 14 | code_template = "func _ready():" 15 | defaults = {} 16 | signal_name = "" 17 | scope = "" 18 | -------------------------------------------------------------------------------- /blocks/log/breakpoint.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Resource" load_steps=2 format=3 uid="uid://bddy0d4xdv20c"] 2 | 3 | [ext_resource type="Script" path="res://addons/reblocks/code_generation/block_definition.gd" id="1_xva04"] 4 | 5 | [resource] 6 | script = ExtResource("1_xva04") 7 | name = &"breakpoint" 8 | target_node_class = "" 9 | description = "Pause execution and show the current line of code in the debugger." 10 | category = "Log" 11 | type = 2 12 | variant_type = 0 13 | display_template = "breakpoint" 14 | code_template = "breakpoint" 15 | defaults = {} 16 | signal_name = "" 17 | scope = "" 18 | -------------------------------------------------------------------------------- /blocks/log/comment.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Resource" load_steps=2 format=3 uid="uid://c4qpkgyd7kfp4"] 2 | 3 | [ext_resource type="Script" path="res://addons/reblocks/code_generation/block_definition.gd" id="1_44emg"] 4 | 5 | [resource] 6 | script = ExtResource("1_44emg") 7 | name = &"comment" 8 | target_node_class = "" 9 | description = "Add a comment to the code" 10 | category = "Log" 11 | type = 2 12 | variant_type = 0 13 | display_template = "comment {text}" 14 | code_template = "## {text}" 15 | defaults = { 16 | "text": "Hello" 17 | } 18 | signal_name = "" 19 | is_advanced = false 20 | -------------------------------------------------------------------------------- /blocks/log/concat.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Resource" load_steps=2 format=3 uid="uid://cb6ux0amdhhlw"] 2 | 3 | [ext_resource type="Script" path="res://addons/reblocks/code_generation/block_definition.gd" id="1_lstbo"] 4 | 5 | [resource] 6 | script = ExtResource("1_lstbo") 7 | name = &"concat" 8 | description = "" 9 | category = "Log" 10 | type = 3 11 | variant_type = 4 12 | display_template = "{string1: STRING} + {string2: STRING}" 13 | code_template = "{string1} + {string2}" 14 | defaults = {} 15 | signal_name = "" 16 | -------------------------------------------------------------------------------- /blocks/log/print.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Resource" load_steps=2 format=3 uid="uid://barxsapb8tl0r"] 2 | 3 | [ext_resource type="Script" path="res://addons/reblocks/code_generation/block_definition.gd" id="1_0lih2"] 4 | 5 | [resource] 6 | script = ExtResource("1_0lih2") 7 | name = &"print" 8 | target_node_class = "" 9 | description = "Print the text to output" 10 | category = "Log" 11 | type = 2 12 | variant_type = 0 13 | display_template = "log text {text: STRING}" 14 | code_template = "print({text})" 15 | defaults = { 16 | "text": "Hello" 17 | } 18 | signal_name = "" 19 | scope = "" 20 | -------------------------------------------------------------------------------- /blocks/logic/and.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Resource" load_steps=2 format=3 uid="uid://d0g11cp3ff81i"] 2 | 3 | [ext_resource type="Script" path="res://addons/reblocks/code_generation/block_definition.gd" id="2_lxlcw"] 4 | 5 | [resource] 6 | script = ExtResource("2_lxlcw") 7 | name = &"and" 8 | description = "" 9 | category = "Logic | Boolean" 10 | type = 3 11 | variant_type = 1 12 | display_template = "{bool1: BOOL} and {bool2: BOOL}" 13 | code_template = "{bool1} and {bool2}" 14 | defaults = {} 15 | signal_name = "" 16 | scope = "" 17 | -------------------------------------------------------------------------------- /blocks/logic/compare.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Resource" load_steps=4 format=3 uid="uid://pr5wnn3ltkbo"] 2 | 3 | [ext_resource type="Script" path="res://addons/reblocks/code_generation/option_data.gd" id="1_hcv2h"] 4 | [ext_resource type="Script" path="res://addons/reblocks/code_generation/block_definition.gd" id="1_wp40r"] 5 | 6 | [sub_resource type="Resource" id="Resource_ie4sg"] 7 | script = ExtResource("1_hcv2h") 8 | selected = 0 9 | items = ["==", ">", "<", ">=", "<=", "!="] 10 | 11 | [resource] 12 | script = ExtResource("1_wp40r") 13 | name = &"compare" 14 | target_node_class = "" 15 | description = "" 16 | category = "Logic | Comparison" 17 | type = 3 18 | variant_type = 1 19 | display_template = "{float1: FLOAT} {op: NIL} {float2: FLOAT}" 20 | code_template = "{float1} {{op}} {float2}" 21 | defaults = { 22 | "float1": 1.0, 23 | "float2": 1.0, 24 | "op": SubResource("Resource_ie4sg") 25 | } 26 | signal_name = "" 27 | is_advanced = false 28 | -------------------------------------------------------------------------------- /blocks/logic/else.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Resource" load_steps=2 format=3 uid="uid://dpgx8j3veifgl"] 2 | 3 | [ext_resource type="Script" path="res://addons/reblocks/code_generation/block_definition.gd" id="1_x816c"] 4 | 5 | [resource] 6 | script = ExtResource("1_x816c") 7 | name = &"else" 8 | target_node_class = "" 9 | description = "" 10 | category = "Logic | Conditionals" 11 | type = 4 12 | variant_type = 0 13 | display_template = "else" 14 | code_template = "else:" 15 | defaults = {} 16 | signal_name = "" 17 | scope = "" 18 | -------------------------------------------------------------------------------- /blocks/logic/else_if.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Resource" load_steps=2 format=3 uid="uid://by53vmmn3wtny"] 2 | 3 | [ext_resource type="Script" path="res://addons/reblocks/code_generation/block_definition.gd" id="1_kgjks"] 4 | 5 | [resource] 6 | script = ExtResource("1_kgjks") 7 | name = &"else_if" 8 | target_node_class = "" 9 | description = "" 10 | category = "Logic | Conditionals" 11 | type = 4 12 | variant_type = 0 13 | display_template = "else if {condition: BOOL}" 14 | code_template = "elif {condition}:" 15 | defaults = {} 16 | signal_name = "" 17 | scope = "" 18 | -------------------------------------------------------------------------------- /blocks/logic/flip.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Resource" load_steps=2 format=3 uid="uid://d3yr42a1ba0c8"] 2 | 3 | [ext_resource type="Script" path="res://addons/reblocks/code_generation/block_definition.gd" id="1_nsxuk"] 4 | 5 | [resource] 6 | script = ExtResource("1_nsxuk") 7 | name = &"flip" 8 | target_node_class = "" 9 | description = "" 10 | category = "Logic | Conditionals" 11 | type = 2 12 | variant_type = 0 13 | display_template = "flip {condition: BOOL}" 14 | code_template = "flip_h = {condition}" 15 | defaults = {} 16 | signal_name = "" 17 | is_advanced = false 18 | -------------------------------------------------------------------------------- /blocks/logic/if.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Resource" load_steps=2 format=3 uid="uid://cxvoo3jassq8c"] 2 | 3 | [ext_resource type="Script" path="res://addons/reblocks/code_generation/block_definition.gd" id="1_c6ly3"] 4 | 5 | [resource] 6 | script = ExtResource("1_c6ly3") 7 | name = &"if" 8 | target_node_class = "" 9 | description = "" 10 | category = "Logic | Conditionals" 11 | type = 4 12 | variant_type = 0 13 | display_template = "if {condition: BOOL}" 14 | code_template = "if {condition}:" 15 | defaults = {} 16 | signal_name = "" 17 | scope = "" 18 | -------------------------------------------------------------------------------- /blocks/logic/not.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Resource" load_steps=2 format=3 uid="uid://d6asv53q6ok8"] 2 | 3 | [ext_resource type="Script" path="res://addons/reblocks/code_generation/block_definition.gd" id="1_6igv6"] 4 | 5 | [resource] 6 | script = ExtResource("1_6igv6") 7 | name = &"not" 8 | target_node_class = "" 9 | description = "" 10 | category = "Logic | Boolean" 11 | type = 3 12 | variant_type = 1 13 | display_template = "not {bool: BOOL}" 14 | code_template = "not {bool}" 15 | defaults = {} 16 | signal_name = "" 17 | scope = "" 18 | -------------------------------------------------------------------------------- /blocks/logic/or.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Resource" load_steps=2 format=3 uid="uid://cyu2tntoqf85m"] 2 | 3 | [ext_resource type="Script" path="res://addons/reblocks/code_generation/block_definition.gd" id="1_oets3"] 4 | 5 | [resource] 6 | script = ExtResource("1_oets3") 7 | name = &"or" 8 | description = "" 9 | category = "Logic | Boolean" 10 | type = 3 11 | variant_type = 1 12 | display_template = "{bool1: BOOL} or {bool2: BOOL}" 13 | code_template = "{bool1} or {bool2}" 14 | defaults = {} 15 | signal_name = "" 16 | scope = "" 17 | -------------------------------------------------------------------------------- /blocks/loops/await_scene_ready.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Resource" load_steps=2 format=3 uid="uid://bkdmiqavhqrph"] 2 | 3 | [ext_resource type="Script" path="res://addons/reblocks/code_generation/block_definition.gd" id="1_qy2t4"] 4 | 5 | [resource] 6 | script = ExtResource("1_qy2t4") 7 | name = &"await_scene_ready" 8 | target_node_class = "" 9 | description = "" 10 | category = "Loops" 11 | type = 2 12 | variant_type = 0 13 | display_template = "wait for the scene to be ready" 14 | code_template = "if not get_tree().root.is_node_ready(): 15 | await get_tree().root.ready" 16 | defaults = {} 17 | signal_name = "" 18 | scope = "" 19 | -------------------------------------------------------------------------------- /blocks/loops/break.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Resource" load_steps=2 format=3 uid="uid://dwteydig4c6hi"] 2 | 3 | [ext_resource type="Script" path="res://addons/reblocks/code_generation/block_definition.gd" id="1_4rhsl"] 4 | 5 | [resource] 6 | script = ExtResource("1_4rhsl") 7 | name = &"break" 8 | target_node_class = "" 9 | description = "" 10 | category = "Loops" 11 | type = 2 12 | variant_type = 0 13 | display_template = "break" 14 | code_template = "break" 15 | defaults = {} 16 | signal_name = "" 17 | scope = "" 18 | -------------------------------------------------------------------------------- /blocks/loops/continue.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Resource" load_steps=2 format=3 uid="uid://srm0bee85n0d"] 2 | 3 | [ext_resource type="Script" path="res://addons/reblocks/code_generation/block_definition.gd" id="1_junev"] 4 | 5 | [resource] 6 | script = ExtResource("1_junev") 7 | name = &"continue" 8 | target_node_class = "" 9 | description = "" 10 | category = "Loops" 11 | type = 2 12 | variant_type = 0 13 | display_template = "continue" 14 | code_template = "continue" 15 | defaults = {} 16 | signal_name = "" 17 | scope = "" 18 | -------------------------------------------------------------------------------- /blocks/loops/for.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Resource" load_steps=2 format=3 uid="uid://0g4njflvemaa"] 2 | 3 | [ext_resource type="Script" path="res://addons/reblocks/code_generation/block_definition.gd" id="1_u01bi"] 4 | 5 | [resource] 6 | script = ExtResource("1_u01bi") 7 | name = &"for" 8 | target_node_class = "" 9 | description = "Run the connected blocks [i]number[/i] times" 10 | category = "Loops" 11 | type = 4 12 | variant_type = 0 13 | display_template = "repeat {number: INT}" 14 | code_template = "for __i in {number}:" 15 | defaults = {} 16 | signal_name = "" 17 | scope = "" 18 | -------------------------------------------------------------------------------- /blocks/loops/while.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Resource" load_steps=2 format=3 uid="uid://ccnjk5s5qb2xe"] 2 | 3 | [ext_resource type="Script" path="res://addons/reblocks/code_generation/block_definition.gd" id="1_fxxh0"] 4 | 5 | [resource] 6 | script = ExtResource("1_fxxh0") 7 | name = &"while" 8 | target_node_class = "" 9 | description = "Run the connected blocks as long as [i]condition[/i] is true. 10 | 11 | Hint: snap a [b]Comparison[/b] block into the condition." 12 | category = "Loops" 13 | type = 4 14 | variant_type = 0 15 | display_template = "while {condition: BOOL}" 16 | code_template = "while {condition}:" 17 | defaults = {} 18 | signal_name = "" 19 | scope = "" 20 | -------------------------------------------------------------------------------- /blocks/math/add.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Resource" load_steps=2 format=3 uid="uid://coy3o7q0x0y60"] 2 | 3 | [ext_resource type="Script" path="res://addons/reblocks/code_generation/block_definition.gd" id="1_rks7c"] 4 | 5 | [resource] 6 | script = ExtResource("1_rks7c") 7 | name = &"add" 8 | target_node_class = "" 9 | description = "" 10 | category = "Math" 11 | type = 3 12 | variant_type = 3 13 | display_template = "{a: FLOAT} + {b: FLOAT}" 14 | code_template = "{a} + {b}" 15 | defaults = { 16 | "a": 1.0, 17 | "b": 1.0 18 | } 19 | signal_name = "" 20 | scope = "" 21 | -------------------------------------------------------------------------------- /blocks/math/cos.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Resource" load_steps=2 format=3 uid="uid://c6g6ljp46lfrj"] 2 | 3 | [ext_resource type="Script" path="res://addons/reblocks/code_generation/block_definition.gd" id="1_lxbvo"] 4 | 5 | [resource] 6 | script = ExtResource("1_lxbvo") 7 | name = &"cos" 8 | description = "Calculate the cosine of [i]angle[/i]" 9 | category = "Math" 10 | type = 3 11 | variant_type = 3 12 | display_template = "cos {angle: FLOAT}" 13 | code_template = "cos(deg_to_rad({angle}))" 14 | defaults = { 15 | "angle": 0.0 16 | } 17 | signal_name = "" 18 | scope = "" 19 | -------------------------------------------------------------------------------- /blocks/math/divide.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Resource" load_steps=2 format=3 uid="uid://dwk6c70c4ta0"] 2 | 3 | [ext_resource type="Script" path="res://addons/reblocks/code_generation/block_definition.gd" id="1_rhh7v"] 4 | 5 | [resource] 6 | script = ExtResource("1_rhh7v") 7 | name = &"divide" 8 | target_node_class = "" 9 | description = "" 10 | category = "Math" 11 | type = 3 12 | variant_type = 3 13 | display_template = "{a: FLOAT} / {b: FLOAT}" 14 | code_template = "{a} / {b}" 15 | defaults = { 16 | "a": 1.0, 17 | "b": 1.0 18 | } 19 | signal_name = "" 20 | scope = "" 21 | -------------------------------------------------------------------------------- /blocks/math/multiply.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Resource" load_steps=2 format=3 uid="uid://yipjitb3p66q"] 2 | 3 | [ext_resource type="Script" path="res://addons/reblocks/code_generation/block_definition.gd" id="1_c5vny"] 4 | 5 | [resource] 6 | script = ExtResource("1_c5vny") 7 | name = &"multiply" 8 | target_node_class = "" 9 | description = "" 10 | category = "Math" 11 | type = 3 12 | variant_type = 3 13 | display_template = "{a: FLOAT} * {b: FLOAT}" 14 | code_template = "{a} * {b}" 15 | defaults = { 16 | "a": 1.0, 17 | "b": 1.0 18 | } 19 | signal_name = "" 20 | scope = "" 21 | -------------------------------------------------------------------------------- /blocks/math/pow.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Resource" load_steps=2 format=3 uid="uid://bib11ow5t44to"] 2 | 3 | [ext_resource type="Script" path="res://addons/reblocks/code_generation/block_definition.gd" id="1_cx5g5"] 4 | 5 | [resource] 6 | script = ExtResource("1_cx5g5") 7 | name = &"pow" 8 | target_node_class = "" 9 | description = "" 10 | category = "Math" 11 | type = 3 12 | variant_type = 3 13 | display_template = "{base: FLOAT} ^ {exp: FLOAT}" 14 | code_template = "pow({base}, {exp})" 15 | defaults = { 16 | "base": 1.0, 17 | "exp": 1.0 18 | } 19 | signal_name = "" 20 | scope = "" 21 | -------------------------------------------------------------------------------- /blocks/math/randf_range.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Resource" load_steps=2 format=3 uid="uid://u35glf576fue"] 2 | 3 | [ext_resource type="Script" path="res://addons/reblocks/code_generation/block_definition.gd" id="1_03jps"] 4 | 5 | [resource] 6 | script = ExtResource("1_03jps") 7 | name = &"randf_range" 8 | target_node_class = "" 9 | description = "Generate a random floating point number between [i]from[/i] and [i]to[/i] inclusively" 10 | category = "Math" 11 | type = 3 12 | variant_type = 3 13 | display_template = "random floating point number between {from: FLOAT} and {to: FLOAT}" 14 | code_template = "randf_range({from}, {to})" 15 | defaults = { 16 | "from": -1.0, 17 | "to": 1.0 18 | } 19 | signal_name = "" 20 | scope = "" 21 | -------------------------------------------------------------------------------- /blocks/math/randi_range.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Resource" load_steps=2 format=3 uid="uid://b3b1dyarh2hmo"] 2 | 3 | [ext_resource type="Script" path="res://addons/reblocks/code_generation/block_definition.gd" id="1_hk574"] 4 | 5 | [resource] 6 | script = ExtResource("1_hk574") 7 | name = &"randi_range" 8 | target_node_class = "" 9 | description = "Generate a random signed 32-bits integer number between [i]from[/i] and [i]to[/i] inclusively. [i]from[/i] and [i]to[/i] can be a negative or positive number" 10 | category = "Math" 11 | type = 3 12 | variant_type = 2 13 | display_template = "random integer number between {from: INT} and {to: INT}" 14 | code_template = "randi_range({from}, {to})" 15 | defaults = { 16 | "from": 0, 17 | "to": 100 18 | } 19 | signal_name = "" 20 | scope = "" 21 | -------------------------------------------------------------------------------- /blocks/math/sin.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Resource" load_steps=2 format=3 uid="uid://b1r7f06rfci6o"] 2 | 3 | [ext_resource type="Script" path="res://addons/reblocks/code_generation/block_definition.gd" id="1_dlr47"] 4 | 5 | [resource] 6 | script = ExtResource("1_dlr47") 7 | name = &"sin" 8 | description = "Calculate the sine of [i]angle[/i]" 9 | category = "Math" 10 | type = 3 11 | variant_type = 3 12 | display_template = "sin {angle: FLOAT}" 13 | code_template = "sin(deg_to_rad({angle}))" 14 | defaults = { 15 | "angle": 0.0 16 | } 17 | signal_name = "" 18 | scope = "" 19 | -------------------------------------------------------------------------------- /blocks/math/subtract.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Resource" load_steps=2 format=3 uid="uid://dkt135xfcklya"] 2 | 3 | [ext_resource type="Script" path="res://addons/reblocks/code_generation/block_definition.gd" id="1_n0dmm"] 4 | 5 | [resource] 6 | script = ExtResource("1_n0dmm") 7 | name = &"subtract" 8 | target_node_class = "" 9 | description = "" 10 | category = "Math" 11 | type = 3 12 | variant_type = 3 13 | display_template = "{a: FLOAT} - {b: FLOAT}" 14 | code_template = "{a} - {b}" 15 | defaults = { 16 | "a": 1.0, 17 | "b": 1.0 18 | } 19 | signal_name = "" 20 | scope = "" 21 | -------------------------------------------------------------------------------- /blocks/math/tan.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Resource" load_steps=2 format=3 uid="uid://blpo01pjjheqb"] 2 | 3 | [ext_resource type="Script" path="res://addons/reblocks/code_generation/block_definition.gd" id="1_e2566"] 4 | 5 | [resource] 6 | script = ExtResource("1_e2566") 7 | name = &"tan" 8 | description = "Calculate the tangent of [i]angle[/i]" 9 | category = "Math" 10 | type = 3 11 | variant_type = 3 12 | display_template = "tan {angle: FLOAT}" 13 | code_template = "tan(deg_to_rad({angle}))" 14 | defaults = { 15 | "angle": 0.0 16 | } 17 | signal_name = "" 18 | scope = "" 19 | -------------------------------------------------------------------------------- /blocks/math/vector2_xy.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Resource" load_steps=4 format=3 uid="uid://bpdjqy6oidfo4"] 2 | 3 | [ext_resource type="Script" path="res://addons/reblocks/code_generation/option_data.gd" id="1_p8v57"] 4 | [ext_resource type="Script" path="res://addons/reblocks/code_generation/block_definition.gd" id="2_207xo"] 5 | 6 | [sub_resource type="Resource" id="Resource_ie4sg"] 7 | script = ExtResource("1_p8v57") 8 | selected = 0 9 | items = ["x", "y"] 10 | 11 | [resource] 12 | script = ExtResource("2_207xo") 13 | name = &"vector2_xy" 14 | target_node_class = "" 15 | description = "Gives the x or y of a [b]Vector2[/b]" 16 | category = "Math" 17 | type = 3 18 | variant_type = 3 19 | display_template = "{xy: NIL} of {vector2: VECTOR2}" 20 | code_template = "{vector2}.{{xy}}" 21 | defaults = { 22 | "xy": SubResource("Resource_ie4sg") 23 | } 24 | signal_name = "" 25 | is_advanced = false 26 | -------------------------------------------------------------------------------- /blocks/math/vector3_multiply.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Resource" load_steps=2 format=3 uid="uid://bff7cwmpisihj"] 2 | 3 | [ext_resource type="Script" path="res://addons/reblocks/code_generation/block_definition.gd" id="1_52jwf"] 4 | 5 | [resource] 6 | script = ExtResource("1_52jwf") 7 | name = &"vector3_multiply" 8 | target_node_class = "" 9 | description = "Multiplies a Vector3 with a number. Use this, for example, to get a point some distance away along an angle." 10 | category = "Math" 11 | type = 3 12 | variant_type = 9 13 | display_template = "multiply {vector: VECTOR3} by {number: FLOAT}" 14 | code_template = "{vector} * {number}" 15 | defaults = { 16 | "number": 1.0, 17 | "vector": Vector3(1, 1, 1) 18 | } 19 | signal_name = "" 20 | scope = "" 21 | -------------------------------------------------------------------------------- /blocks/math/vector3_xyz.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Resource" load_steps=4 format=3 uid="uid://s72tgtbci1ui"] 2 | 3 | [ext_resource type="Script" path="res://addons/reblocks/code_generation/option_data.gd" id="1_0wc0o"] 4 | [ext_resource type="Script" path="res://addons/reblocks/code_generation/block_definition.gd" id="2_e6ohf"] 5 | 6 | [sub_resource type="Resource" id="Resource_ie4sg"] 7 | script = ExtResource("1_0wc0o") 8 | selected = 0 9 | items = ["x", "y", "z"] 10 | 11 | [resource] 12 | script = ExtResource("2_e6ohf") 13 | name = &"vector3_xyz" 14 | target_node_class = "" 15 | description = "Gives the x, y, or z of a [b]Vector3[/b]" 16 | category = "Math" 17 | type = 3 18 | variant_type = 3 19 | display_template = "{xyz: NIL} of {vector3: VECTOR3}" 20 | code_template = "{vector3}.{{xyz}}" 21 | defaults = { 22 | "xyz": SubResource("Resource_ie4sg") 23 | } 24 | signal_name = "" 25 | is_advanced = false 26 | -------------------------------------------------------------------------------- /blocks/math/vector_from_angle.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Resource" load_steps=2 format=3 uid="uid://c7a6wnxegkfd5"] 2 | 3 | [ext_resource type="Script" path="res://addons/reblocks/code_generation/block_definition.gd" id="1_1p1ve"] 4 | 5 | [resource] 6 | script = ExtResource("1_1p1ve") 7 | name = &"from_angle" 8 | target_node_class = "" 9 | description = "Creates a unit Vector2 rotated to the given angle in radians." 10 | category = "Math" 11 | type = 3 12 | variant_type = 5 13 | display_template = "vector from {angle: FLOAT}" 14 | code_template = "Vector2.from_angle({angle})" 15 | defaults = {} 16 | signal_name = "" 17 | scope = "" 18 | -------------------------------------------------------------------------------- /blocks/math/vector_multiply.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Resource" load_steps=2 format=3 uid="uid://bff7cwmpisihj"] 2 | 3 | [ext_resource type="Script" path="res://addons/reblocks/code_generation/block_definition.gd" id="1_52jwf"] 4 | 5 | [resource] 6 | script = ExtResource("1_52jwf") 7 | name = &"vector_multiply" 8 | target_node_class = "" 9 | description = "Multiplies a vector with a number. Use this, for example, to get a point some distance away along an angle." 10 | category = "Math" 11 | type = 3 12 | variant_type = 5 13 | display_template = "multiply {vector: VECTOR2} by {number: FLOAT}" 14 | code_template = "{vector} * {number}" 15 | defaults = { 16 | "number": 1.0, 17 | "vector": Vector2(1, 1) 18 | } 19 | signal_name = "" 20 | scope = "" 21 | -------------------------------------------------------------------------------- /blocks/physics/characterbody2d_move_and_slide.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Resource" load_steps=2 format=3 uid="uid://cp6ak6wea8ogh"] 2 | 3 | [ext_resource type="Script" path="res://addons/reblocks/code_generation/block_definition.gd" id="1_e3r2r"] 4 | 5 | [resource] 6 | script = ExtResource("1_e3r2r") 7 | name = &"characterbody2d_move_and_slide" 8 | target_node_class = "CharacterBody2D" 9 | description = "" 10 | category = "Physics | Velocity" 11 | type = 2 12 | variant_type = 0 13 | display_template = "move and slide" 14 | code_template = "move_and_slide()" 15 | defaults = {} 16 | signal_name = "" 17 | scope = "" 18 | -------------------------------------------------------------------------------- /blocks/physics/characterbody3d_move_and_slide.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Resource" load_steps=2 format=3 uid="uid://cp6ak6wea8ogh"] 2 | 3 | [ext_resource type="Script" path="res://addons/reblocks/code_generation/block_definition.gd" id="1_e3r2r"] 4 | 5 | [resource] 6 | script = ExtResource("1_e3r2r") 7 | name = &"characterbody3d_move_and_slide" 8 | target_node_class = "CharacterBody3D" 9 | description = "" 10 | category = "Physics | Velocity" 11 | type = 2 12 | variant_type = 0 13 | display_template = "move and slide" 14 | code_template = "move_and_slide()" 15 | defaults = {} 16 | signal_name = "" 17 | scope = "" 18 | -------------------------------------------------------------------------------- /blocks/sounds/audiostreamplayer_play.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Resource" load_steps=2 format=3 uid="uid://bxjjml7u3rokv"] 2 | 3 | [ext_resource type="Script" path="res://addons/reblocks/code_generation/block_definition.gd" id="1_vyl5w"] 4 | 5 | [resource] 6 | script = ExtResource("1_vyl5w") 7 | name = &"audiostreamplayer_play" 8 | target_node_class = "AudioStreamPlayer" 9 | description = "Play the audio stream" 10 | category = "Sounds" 11 | type = 2 12 | variant_type = 0 13 | display_template = "play" 14 | code_template = "play()" 15 | defaults = {} 16 | signal_name = "" 17 | scope = "" 18 | -------------------------------------------------------------------------------- /blocks/sounds/audiostreamplayer_stop.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Resource" load_steps=2 format=3 uid="uid://ib16grbtduab"] 2 | 3 | [ext_resource type="Script" path="res://addons/reblocks/code_generation/block_definition.gd" id="1_db4g2"] 4 | 5 | [resource] 6 | script = ExtResource("1_db4g2") 7 | name = &"audiostreamplayer_stop" 8 | target_node_class = "AudioStreamPlayer" 9 | description = "Stop the audio stream" 10 | category = "Sounds" 11 | type = 2 12 | variant_type = 0 13 | display_template = "stop" 14 | code_template = "stop()" 15 | defaults = {} 16 | signal_name = "" 17 | scope = "" 18 | -------------------------------------------------------------------------------- /blocks/sounds/load_sound.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Resource" load_steps=2 format=3 uid="uid://coefocdmytg0j"] 2 | 3 | [ext_resource type="Script" path="res://addons/reblocks/code_generation/block_definition.gd" id="1_4w4si"] 4 | 5 | [resource] 6 | script = ExtResource("1_4w4si") 7 | name = &"load_sound" 8 | target_node_class = "" 9 | description = "Load a resource file as the audio stream" 10 | category = "Sounds" 11 | type = 2 12 | variant_type = 0 13 | display_template = "load file {file_path: STRING} as sound {name: STRING}" 14 | code_template = "var __sound = AudioStreamPlayer.new() 15 | __sound.name = {name} 16 | __sound.set_stream(load({file_path})) 17 | add_child(__sound) 18 | " 19 | defaults = {} 20 | signal_name = "" 21 | scope = "" 22 | -------------------------------------------------------------------------------- /blocks/sounds/pause_continue_sound.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Resource" load_steps=4 format=3 uid="uid://wpdspamg3f6g"] 2 | 3 | [ext_resource type="Script" path="res://addons/reblocks/code_generation/option_data.gd" id="1_ilhdq"] 4 | [ext_resource type="Script" path="res://addons/reblocks/code_generation/block_definition.gd" id="1_q04gm"] 5 | 6 | [sub_resource type="Resource" id="Resource_lalgp"] 7 | script = ExtResource("1_ilhdq") 8 | selected = 0 9 | items = ["pause", "continue"] 10 | 11 | [resource] 12 | script = ExtResource("1_q04gm") 13 | name = &"pause_continue_sound" 14 | target_node_class = "" 15 | description = "Pause/Continue the audio stream" 16 | category = "Sounds" 17 | type = 2 18 | variant_type = 0 19 | display_template = "{pause: NIL} the sound {name: STRING}" 20 | code_template = "var __sound_node = get_node({name}) 21 | if {pause} == \"pause\": 22 | __sound_node.stream_paused = true 23 | else: 24 | __sound_node.stream_paused = false 25 | " 26 | defaults = { 27 | "pause": SubResource("Resource_lalgp") 28 | } 29 | signal_name = "" 30 | is_advanced = false 31 | -------------------------------------------------------------------------------- /blocks/sounds/play_sound.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Resource" load_steps=2 format=3 uid="uid://dt022ilveapt5"] 2 | 3 | [ext_resource type="Script" path="res://addons/reblocks/code_generation/block_definition.gd" id="1_llfp1"] 4 | 5 | [resource] 6 | script = ExtResource("1_llfp1") 7 | name = &"play_sound" 8 | target_node_class = "" 9 | description = "Play the audio stream with volume and pitch" 10 | category = "Sounds" 11 | type = 2 12 | variant_type = 0 13 | display_template = "play the sound {name: STRING} | with volume {db: FLOAT} dB and pitch scale {pitch: FLOAT}" 14 | code_template = "var __sound_node = get_node({name}) 15 | __sound_node.volume_db = {db} 16 | __sound_node.pitch_scale = {pitch} 17 | __sound_node.play() 18 | " 19 | defaults = { 20 | "db": 0.0, 21 | "pitch": 1.0 22 | } 23 | signal_name = "" 24 | scope = "" 25 | -------------------------------------------------------------------------------- /blocks/sounds/stop_sound.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Resource" load_steps=2 format=3 uid="uid://csg40u5awp1sy"] 2 | 3 | [ext_resource type="Script" path="res://addons/reblocks/code_generation/block_definition.gd" id="1_rfujh"] 4 | 5 | [resource] 6 | script = ExtResource("1_rfujh") 7 | name = &"stop_sound" 8 | target_node_class = "" 9 | description = "Stop the audio stream" 10 | category = "Sounds" 11 | type = 2 12 | variant_type = 0 13 | display_template = "stop the sound {name: STRING}" 14 | code_template = "var __sound_node = get_node({name}) 15 | __sound_node.stop() 16 | " 17 | defaults = { 18 | "db": 0.0, 19 | "pitch": 1.0 20 | } 21 | signal_name = "" 22 | scope = "" 23 | -------------------------------------------------------------------------------- /blocks/spawn/cpuparticles2d_finished.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Resource" load_steps=2 format=3 uid="uid://c188gpgf4rpns"] 2 | 3 | [ext_resource type="Script" path="res://addons/reblocks/code_generation/block_definition.gd" id="1_pmpup"] 4 | 5 | [resource] 6 | script = ExtResource("1_pmpup") 7 | name = &"cpuparticles2d_finished" 8 | target_node_class = "CPUParticles2D" 9 | description = "Emitted when all active particles have finished processing." 10 | category = "Lifecycle | Spawn" 11 | type = 1 12 | variant_type = 0 13 | display_template = "when particles are finished" 14 | code_template = "func _on_finished():" 15 | defaults = {} 16 | signal_name = "finished" 17 | scope = "" 18 | -------------------------------------------------------------------------------- /blocks/transform/rigidbody2d_physics_position.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Resource" load_steps=2 format=3 uid="uid://ses5486g56q"] 2 | 3 | [ext_resource type="Script" path="res://addons/reblocks/code_generation/block_definition.gd" id="1_72i54"] 4 | 5 | [resource] 6 | script = ExtResource("1_72i54") 7 | name = &"rigidbody2d_physics_position" 8 | target_node_class = "RigidBody2D" 9 | description = "" 10 | category = "Transform | Position" 11 | type = 2 12 | variant_type = 0 13 | display_template = "set physics position {position: VECTOR2}" 14 | code_template = "PhysicsServer2D.body_set_state( 15 | get_rid(), 16 | PhysicsServer2D.BODY_STATE_TRANSFORM, 17 | Transform2D.IDENTITY.translated({position}) 18 | ) 19 | " 20 | defaults = {} 21 | signal_name = "" 22 | scope = "" 23 | -------------------------------------------------------------------------------- /blocks/ui/label_set_text.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Resource" load_steps=2 format=3 uid="uid://ciqkywxdk4uht"] 2 | 3 | [ext_resource type="Script" path="res://addons/reblocks/code_generation/block_definition.gd" id="1_bofov"] 4 | 5 | [resource] 6 | script = ExtResource("1_bofov") 7 | name = &"label_set_text" 8 | target_node_class = "Label" 9 | description = "Set the text for the label." 10 | category = "UI" 11 | type = 2 12 | variant_type = 0 13 | display_template = "set text to {text: STRING}" 14 | code_template = "text = {text}" 15 | defaults = {} 16 | signal_name = "" 17 | scope = "" 18 | -------------------------------------------------------------------------------- /blocks/variables/vector2.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Resource" load_steps=2 format=3 uid="uid://ddj24k1fp0s82"] 2 | 3 | [ext_resource type="Script" path="res://addons/reblocks/code_generation/block_definition.gd" id="1_ilw3v"] 4 | 5 | [resource] 6 | script = ExtResource("1_ilw3v") 7 | name = &"vector2" 8 | target_node_class = "" 9 | description = "" 10 | category = "Math" 11 | type = 3 12 | variant_type = 5 13 | display_template = "vector2 x: {x: FLOAT} y: {y: FLOAT}" 14 | code_template = "Vector2({x}, {y})" 15 | defaults = { 16 | "x": 0.0, 17 | "y": 0.0 18 | } 19 | signal_name = "" 20 | scope = "" 21 | -------------------------------------------------------------------------------- /blocks/variables/vector3.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Resource" load_steps=2 format=3 uid="uid://ddj24k1fp0s82"] 2 | 3 | [ext_resource type="Script" path="res://addons/reblocks/code_generation/block_definition.gd" id="1_ilw3v"] 4 | 5 | [resource] 6 | script = ExtResource("1_ilw3v") 7 | name = &"vector3" 8 | target_node_class = "" 9 | description = "" 10 | category = "Math" 11 | type = 3 12 | variant_type = 9 13 | display_template = "vector3 x: {x: FLOAT} y: {y: FLOAT}: z: {z: FLOAT}" 14 | code_template = "Vector3({x}, {y}, {z})" 15 | defaults = { 16 | "x": 0.0, 17 | "y": 0.0, 18 | "z": 0.0 19 | } 20 | signal_name = "" 21 | scope = "" 22 | -------------------------------------------------------------------------------- /code_generation/ast_list.gd: -------------------------------------------------------------------------------- 1 | extends RefCounted 2 | 3 | const Types = preload("res://addons/reblocks/types/types.gd") 4 | const BlockAST = preload("res://addons/reblocks/code_generation/block_ast.gd") 5 | 6 | var array: Array[ASTPair] 7 | 8 | 9 | class ASTPair: 10 | var ast: BlockAST 11 | var canvas_position: Vector2 12 | 13 | func _init(p_ast: BlockAST, p_canvas_position: Vector2): 14 | ast = p_ast 15 | canvas_position = p_canvas_position 16 | 17 | 18 | func _init(): 19 | array = [] 20 | 21 | 22 | func append(ast: BlockAST, canvas_position: Vector2): 23 | array.append(ASTPair.new(ast, canvas_position)) 24 | 25 | 26 | func clear(): 27 | array.clear() 28 | 29 | 30 | func get_top_level_nodes_of_type(block_type: Types.BlockType) -> Array[BlockAST]: 31 | var asts: Array[BlockAST] = [] 32 | 33 | for ast_pair in array: 34 | if ast_pair.ast.root.data.type == block_type: 35 | asts.append(ast_pair.ast) 36 | 37 | return asts 38 | -------------------------------------------------------------------------------- /code_generation/ast_list.gd.uid: -------------------------------------------------------------------------------- 1 | uid://b5txthy46jhqc 2 | -------------------------------------------------------------------------------- /code_generation/block_ast.gd.uid: -------------------------------------------------------------------------------- 1 | uid://b3v0lvdpx7tge 2 | -------------------------------------------------------------------------------- /code_generation/block_definition.gd.uid: -------------------------------------------------------------------------------- 1 | uid://cfmvxsm2ok4ek 2 | -------------------------------------------------------------------------------- /code_generation/block_extension.gd: -------------------------------------------------------------------------------- 1 | @tool 2 | ## Block extensions interface. 3 | ## 4 | ## A BlockExtension provides additional, context-sensitive information for the 5 | ## user interface of a particular type of block. An instance of BlockExtension 6 | ## belongs to a specific [Block] in the block canvas, but an extension does not 7 | ## have direct access to its block. Instead, it can use the [member context_node] 8 | ## property to draw information about the scene.[br] 9 | ## [br] 10 | ## To customize the user interface for a block, override public functions such 11 | ## as [method get_defaults].[br] 12 | ## [br] 13 | ## In some cases, an extension may need to monitor the scene to determine if it 14 | ## has changed. To achieve this, override [method _context_node_changed] to 15 | ## connect the relevant signals, and call [method _emit_changed] when a 16 | ## significant change has occurred. 17 | class_name BlockExtension 18 | extends RefCounted 19 | 20 | signal changed 21 | 22 | var context_node: Node: 23 | set(value): 24 | if context_node != value: 25 | context_node = value 26 | _context_node_changed() 27 | 28 | 29 | ## Called when the value of context_node changes. Use this for connecting 30 | ## signals to monitor for changes. 31 | func _context_node_changed(): 32 | pass 33 | 34 | 35 | ## Generate a set of defaults for this block extension based on the current 36 | ## context. The return value will be merged with the defaults specified in the 37 | ## static block definition. 38 | func get_defaults() -> Dictionary: 39 | return get_defaults_for_node(context_node) 40 | 41 | 42 | ## @deprecated: Use [method get_defaults] instead. 43 | func get_defaults_for_node(context_node: Node) -> Dictionary: 44 | return {} 45 | 46 | 47 | ## Emit the "changed" signal. Use this when an event has occurred which may 48 | ## cause [method get_defaults] to return a different value. 49 | func _emit_changed(): 50 | changed.emit() 51 | -------------------------------------------------------------------------------- /code_generation/block_extension.gd.uid: -------------------------------------------------------------------------------- 1 | uid://g3dafc46bkmv 2 | -------------------------------------------------------------------------------- /code_generation/blocks_catalog.gd.uid: -------------------------------------------------------------------------------- 1 | uid://cjytr0p78b3x7 2 | -------------------------------------------------------------------------------- /code_generation/option_data.gd: -------------------------------------------------------------------------------- 1 | extends Resource 2 | 3 | @export var selected: int 4 | @export var items: Array 5 | 6 | 7 | func _init(p_items: Array = [], p_selected: int = 0): 8 | items = p_items 9 | selected = p_selected 10 | -------------------------------------------------------------------------------- /code_generation/option_data.gd.uid: -------------------------------------------------------------------------------- 1 | uid://cteah6oqsmew0 2 | -------------------------------------------------------------------------------- /code_generation/script_generator.gd: -------------------------------------------------------------------------------- 1 | extends Object 2 | 3 | const Types = preload("res://addons/reblocks/types/types.gd") 4 | const ASTList = preload("res://addons/reblocks/code_generation/ast_list.gd") 5 | const BlockAST = preload("res://addons/reblocks/code_generation/block_ast.gd") 6 | const BlockDefinition = preload("res://addons/reblocks/code_generation/block_definition.gd") 7 | 8 | 9 | static func generate_script(ast_list: ASTList, block_script: BlockScriptSerialization) -> String: 10 | var entry_asts: Array[BlockAST] = ast_list.get_top_level_nodes_of_type(Types.BlockType.ENTRY) 11 | 12 | var init_ast := BlockAST.new() 13 | init_ast.root = BlockAST.ASTNode.new() 14 | init_ast.root.data = BlockDefinition.new() 15 | init_ast.root.data.type = Types.BlockType.ENTRY 16 | init_ast.root.data.code_template = "func _init():" 17 | 18 | var combined_entry_asts = {} 19 | 20 | # Combine entry asts with same root statement 21 | for entry_ast in entry_asts: 22 | var statement = entry_ast.root.get_code(0) 23 | if not statement in combined_entry_asts: 24 | var new_ast := BlockAST.new() 25 | var root = BlockAST.ASTNode.new() 26 | root.data = entry_ast.root.data 27 | root.arguments = entry_ast.root.arguments 28 | root.children = entry_ast.root.children.duplicate() 29 | new_ast.root = root 30 | combined_entry_asts[statement] = new_ast 31 | else: 32 | combined_entry_asts[statement].root.children.append_array(entry_ast.root.children) 33 | 34 | # Connect signals on _init 35 | for entry_statement in combined_entry_asts: 36 | var entry_ast: BlockAST = combined_entry_asts[entry_statement] 37 | var signal_name = entry_ast.root.data.signal_name 38 | if signal_name != "": 39 | var signal_node := BlockAST.ASTNode.new() 40 | signal_node.data = BlockDefinition.new() 41 | signal_node.data.code_template = "{0}.connect(_on_{0})".format([signal_name]) 42 | init_ast.root.children.append(signal_node) 43 | 44 | # Generate script extends statement 45 | var script := "extends %s\n\n" % block_script.script_inherits 46 | 47 | # Generate variables 48 | for variable in block_script.variables: 49 | script += "var %s: %s\n\n" % [variable.var_name, type_string(variable.var_type)] 50 | 51 | script += "\n" 52 | 53 | # Generate _init 54 | if not init_ast.root.children.is_empty(): 55 | script += init_ast.get_code() + "\n" 56 | 57 | # Generate other entry methods 58 | for entry_statement in combined_entry_asts: 59 | var entry_ast: BlockAST = combined_entry_asts[entry_statement] 60 | script += entry_ast.get_code() 61 | script += "\n" 62 | 63 | return script 64 | -------------------------------------------------------------------------------- /code_generation/script_generator.gd.uid: -------------------------------------------------------------------------------- 1 | uid://62nuwoymwimu 2 | -------------------------------------------------------------------------------- /code_generation/util.gd: -------------------------------------------------------------------------------- 1 | extends Object 2 | 3 | 4 | static func get_files_in_dir_recursive(path: String, pattern: String) -> Array: 5 | var files = [] 6 | var dir := DirAccess.open(path) 7 | 8 | if not dir: 9 | return files 10 | 11 | dir.list_dir_begin() 12 | 13 | var file_name = dir.get_next() 14 | 15 | while file_name != "": 16 | var file_path = path + "/" + file_name 17 | if dir.current_is_dir(): 18 | files.append_array(get_files_in_dir_recursive(file_path, pattern)) 19 | elif file_name.matchn(pattern): 20 | files.append(file_path) 21 | 22 | file_name = dir.get_next() 23 | 24 | return files 25 | -------------------------------------------------------------------------------- /code_generation/util.gd.uid: -------------------------------------------------------------------------------- 1 | uid://b35g67ql6vfvl 2 | -------------------------------------------------------------------------------- /code_generation/variable_definition.gd: -------------------------------------------------------------------------------- 1 | extends Resource 2 | 3 | @export var var_name: String 4 | @export var var_type: Variant.Type 5 | 6 | 7 | func _init(p_var_name: String = "", p_var_type: Variant.Type = TYPE_NIL): 8 | var_name = p_var_name 9 | var_type = p_var_type 10 | -------------------------------------------------------------------------------- /code_generation/variable_definition.gd.uid: -------------------------------------------------------------------------------- 1 | uid://cfnl76l82sw64 2 | -------------------------------------------------------------------------------- /drag_manager/drag.gd.uid: -------------------------------------------------------------------------------- 1 | uid://2ota6mvwaf1k 2 | -------------------------------------------------------------------------------- /drag_manager/drag_manager.gd: -------------------------------------------------------------------------------- 1 | @tool 2 | extends Control 3 | 4 | signal block_dropped 5 | signal block_modified 6 | 7 | const BlockCanvas = preload("res://addons/reblocks/ui/block_canvas/block_canvas.gd") 8 | const BlockTreeUtil = preload("res://addons/reblocks/ui/block_tree_util.gd") 9 | const Drag = preload("res://addons/reblocks/drag_manager/drag.gd") 10 | const Picker = preload("res://addons/reblocks/ui/picker/picker.gd") 11 | const Util = preload("res://addons/reblocks/ui/util.gd") 12 | 13 | @export var picker_path: NodePath 14 | @export var block_canvas_path: NodePath 15 | 16 | const Constants = preload("res://addons/reblocks/ui/constants.gd") 17 | 18 | @onready var _context := BlockEditorContext.get_default() 19 | 20 | var _picker: Picker 21 | var _block_canvas: BlockCanvas 22 | 23 | var drag: Drag = null 24 | 25 | 26 | func _ready(): 27 | _picker = get_node(picker_path) 28 | _block_canvas = get_node(block_canvas_path) 29 | 30 | 31 | func _process(_delta): 32 | if drag: 33 | drag.update_drag_state() 34 | 35 | 36 | func drag_block(block: Block, copied_from: Block = null, offset: Vector2 = Vector2.ZERO): 37 | if copied_from and copied_from.is_inside_tree(): 38 | offset += get_global_mouse_position() - copied_from.global_position 39 | elif block.is_inside_tree(): 40 | offset += get_global_mouse_position() - block.global_position 41 | 42 | if _block_canvas.is_ancestor_of(block): 43 | offset /= _block_canvas.zoom 44 | 45 | var parent = block.get_parent() 46 | 47 | if parent: 48 | parent.remove_child(block) 49 | 50 | block.disconnect_signals() 51 | 52 | var block_scope := BlockTreeUtil.get_tree_scope(block) 53 | if block_scope != "": 54 | _block_canvas.set_scope(block_scope) 55 | 56 | drag = Drag.new(block, block_scope, offset, _block_canvas) 57 | drag.set_snap_points(get_tree().get_nodes_in_group("snap_point")) 58 | drag.add_delete_area(_picker.get_global_rect()) 59 | if block is ParameterBlock and block.spawned_by: 60 | drag.add_delete_area(block.spawned_by.get_global_rect()) 61 | add_child(drag) 62 | 63 | 64 | func copy_block(block: Block) -> Block: 65 | if _context.block_script == null: 66 | return null 67 | return _context.block_script.instantiate_block(block.definition) 68 | 69 | 70 | func copy_picked_block_and_drag(block: Block, offset: Vector2): 71 | var new_block: Block = copy_block(block) 72 | drag_block(new_block, block, offset) 73 | 74 | 75 | func drag_ended(): 76 | if not drag: 77 | return 78 | 79 | var block = drag.apply_drag() 80 | 81 | if block: 82 | connect_block_canvas_signals(block) 83 | block.grab_focus() 84 | 85 | # Allow the block to be deleted and edited now that it's on the canvas. 86 | block.can_delete = true 87 | block.editable = true 88 | 89 | _block_canvas.release_scope() 90 | 91 | drag.queue_free() 92 | drag = null 93 | 94 | block_dropped.emit() 95 | 96 | 97 | func connect_block_canvas_signals(block: Block): 98 | if block.drag_started.get_connections().size() == 0: 99 | block.drag_started.connect(_on_block_drag_started) 100 | if block.modified.get_connections().size() == 0: 101 | block.modified.connect(func(): block_modified.emit()) 102 | 103 | 104 | func _on_block_drag_started(block: Block, offset: Vector2): 105 | drag_block(block, null, offset) 106 | -------------------------------------------------------------------------------- /drag_manager/drag_manager.gd.uid: -------------------------------------------------------------------------------- 1 | uid://c00bv7tp7np7c 2 | -------------------------------------------------------------------------------- /drag_manager/drag_manager.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=2 format=3 uid="uid://cph1k5cfximbf"] 2 | 3 | [ext_resource type="Script" path="res://addons/reblocks/drag_manager/drag_manager.gd" id="1_rif3x"] 4 | 5 | [node name="DragManager" type="Control"] 6 | layout_mode = 3 7 | anchors_preset = 0 8 | mouse_filter = 1 9 | script = ExtResource("1_rif3x") 10 | -------------------------------------------------------------------------------- /image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Redot-Experimental/reblocks/c80e8b09503556f4fba4c436dc7bb5dcb0c51804/image.png -------------------------------------------------------------------------------- /image.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://wgc6ps8n8r8f" 6 | path="res://.godot/imported/image.png-89b02f89c22769258962765d13ebb6bd.ctex" 7 | metadata={ 8 | "vram_texture": false 9 | } 10 | 11 | [deps] 12 | 13 | source_file="res://addons/reblocks/image.png" 14 | dest_files=["res://.godot/imported/image.png-89b02f89c22769258962765d13ebb6bd.ctex"] 15 | 16 | [params] 17 | 18 | compress/mode=0 19 | compress/high_quality=false 20 | compress/lossy_quality=0.7 21 | compress/hdr_compression=1 22 | compress/normal_map=0 23 | compress/channel_pack=0 24 | mipmaps/generate=false 25 | mipmaps/limit=-1 26 | roughness/mode=0 27 | roughness/src_normal="" 28 | process/fix_alpha_border=true 29 | process/premult_alpha=false 30 | process/normal_map_invert_y=false 31 | process/hdr_as_srgb=false 32 | process/hdr_clamp_exposure=false 33 | process/size_limit=0 34 | detect_3d/compress_to=1 35 | -------------------------------------------------------------------------------- /inspector_plugin/block_script_inspector.gd: -------------------------------------------------------------------------------- 1 | extends EditorInspectorPlugin 2 | 3 | const BlockCodePlugin = preload("res://addons/reblocks/block_code_plugin.gd") 4 | const TxUtils := preload("res://addons/reblocks/translation/utils.gd") 5 | 6 | 7 | func _init(): 8 | TxUtils.set_block_translation_domain(self) 9 | 10 | 11 | func _can_handle(object): 12 | return object is BlockCode 13 | 14 | 15 | func _parse_begin(object): 16 | var block_code := object as BlockCode 17 | 18 | var button := Button.new() 19 | button.text = tr("Open Block Script") 20 | button.pressed.connect(func(): BlockCodePlugin.main_panel.switch_block_code_node(block_code)) 21 | 22 | var container := MarginContainer.new() 23 | container.add_theme_constant_override("margin_bottom", 10) 24 | container.add_child(button) 25 | 26 | add_custom_control(container) 27 | -------------------------------------------------------------------------------- /inspector_plugin/block_script_inspector.gd.uid: -------------------------------------------------------------------------------- 1 | uid://cfmu6utfadohw 2 | -------------------------------------------------------------------------------- /plugin.cfg: -------------------------------------------------------------------------------- 1 | [plugin] 2 | 3 | name="ReBlocks" 4 | description="Create games using a high-level, block-based visual programming language." 5 | author="Redot" 6 | version="v0.1" 7 | script="block_code_plugin.gd" 8 | -------------------------------------------------------------------------------- /serialization/block_script_serialization.gd.uid: -------------------------------------------------------------------------------- 1 | uid://chygx3dlf1fcl 2 | -------------------------------------------------------------------------------- /serialization/block_serialization.gd: -------------------------------------------------------------------------------- 1 | @tool 2 | extends Resource 3 | 4 | const BlockSerialization = preload("res://addons/reblocks/serialization/block_serialization.gd") 5 | 6 | @export var name: StringName: 7 | set = _set_name 8 | @export var children: Array[BlockSerialization] 9 | @export var arguments: Dictionary: # String, ValueBlockSerialization 10 | set = _set_arguments 11 | 12 | 13 | func _init(p_name: StringName = &"", p_children: Array[BlockSerialization] = [], p_arguments: Dictionary = {}): 14 | name = p_name 15 | children = p_children 16 | arguments = p_arguments 17 | 18 | 19 | # Block name and arguments backwards compatibility handling. 20 | const _renamed_blocks: Dictionary = { 21 | &"simplespawner_set_spawn_frequency": &"simplespawner_set_spawn_period", 22 | } 23 | 24 | 25 | func _set_name(value): 26 | var new_name = _renamed_blocks.get(value) 27 | if new_name: 28 | print("Migrating block %s to new name %s" % [value, new_name]) 29 | name = new_name 30 | if Engine.is_editor_hint(): 31 | EditorInterface.mark_scene_as_unsaved() 32 | else: 33 | name = value 34 | 35 | 36 | const _renamed_arguments: Dictionary = { 37 | &"simplespawner_set_spawn_period": 38 | { 39 | "new_frequency": "new_period", 40 | }, 41 | } 42 | 43 | 44 | func _set_arguments(value): 45 | if not value is Dictionary: 46 | return 47 | 48 | var renamed_args = _renamed_arguments.get(name) 49 | if not renamed_args: 50 | # Try with the new block name if it hasn't been migrated yet. 51 | var new_block_name = _renamed_blocks.get(name) 52 | if new_block_name: 53 | renamed_args = _renamed_arguments.get(new_block_name) 54 | 55 | if renamed_args: 56 | var changed: bool = false 57 | value = value.duplicate() 58 | for old_arg in renamed_args.keys(): 59 | if not old_arg in value: 60 | continue 61 | 62 | var new_arg = renamed_args[old_arg] 63 | print("Migrating block %s argument %s to new name %s" % [name, old_arg, new_arg]) 64 | value[new_arg] = value[old_arg] 65 | value.erase(old_arg) 66 | changed = true 67 | 68 | if changed and Engine.is_editor_hint(): 69 | EditorInterface.mark_scene_as_unsaved() 70 | 71 | arguments = value 72 | -------------------------------------------------------------------------------- /serialization/block_serialization.gd.uid: -------------------------------------------------------------------------------- 1 | uid://wy5ivwnaavm 2 | -------------------------------------------------------------------------------- /serialization/block_serialization_tree.gd: -------------------------------------------------------------------------------- 1 | extends Resource 2 | 3 | const BlockSerialization = preload("res://addons/reblocks/serialization/block_serialization.gd") 4 | 5 | @export var root: BlockSerialization 6 | @export var canvas_position: Vector2 7 | 8 | 9 | func _init(p_root: BlockSerialization = null, p_canvas_position: Vector2 = Vector2(0, 0)): 10 | root = p_root 11 | canvas_position = p_canvas_position 12 | 13 | 14 | func _to_string(): 15 | return to_string_recursive(root, 0) 16 | 17 | 18 | func to_string_recursive(node: BlockSerialization, depth: int) -> String: 19 | var string: String = "%s %s\n" % ["-".repeat(depth), node.block_name] 20 | 21 | for c in node.children: 22 | string += to_string_recursive(c, depth + 1) 23 | 24 | return string 25 | -------------------------------------------------------------------------------- /serialization/block_serialization_tree.gd.uid: -------------------------------------------------------------------------------- 1 | uid://dfuwu7thoved7 2 | -------------------------------------------------------------------------------- /serialization/default_block_script.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Resource" script_class="BlockScriptSerialization" load_steps=7 format=3 uid="uid://i7adsp6x51ml"] 2 | 3 | [ext_resource type="Script" path="res://addons/reblocks/serialization/block_serialization_tree.gd" id="1_opywe"] 4 | [ext_resource type="Script" path="res://addons/reblocks/serialization/block_serialization.gd" id="2_h8ehk"] 5 | [ext_resource type="Script" path="res://addons/reblocks/serialization/block_script_serialization.gd" id="2_yjlcv"] 6 | [ext_resource type="Script" path="res://addons/reblocks/code_generation/variable_definition.gd" id="3_wb2fg"] 7 | 8 | [sub_resource type="Resource" id="Resource_oalom"] 9 | script = ExtResource("2_h8ehk") 10 | name = &"ready" 11 | children = Array[ExtResource("2_h8ehk")]([]) 12 | arguments = {} 13 | 14 | [sub_resource type="Resource" id="Resource_8sqy5"] 15 | script = ExtResource("1_opywe") 16 | root = SubResource("Resource_oalom") 17 | canvas_position = Vector2(54, 47) 18 | 19 | [resource] 20 | script = ExtResource("2_yjlcv") 21 | script_inherits = "INHERIT_DEFAULT" 22 | block_serialization_trees = Array[ExtResource("1_opywe")]([SubResource("Resource_8sqy5")]) 23 | variables = Array[ExtResource("3_wb2fg")]([]) 24 | generated_script = "extends INHERIT_DEFAULT" 25 | version = 0 26 | -------------------------------------------------------------------------------- /serialization/value_block_serialization.gd: -------------------------------------------------------------------------------- 1 | @tool 2 | extends Resource 3 | 4 | @export var name: StringName: 5 | set = _set_name 6 | @export var arguments: Dictionary: # String, ValueBlockSerialization 7 | set = _set_arguments 8 | 9 | 10 | func _init(p_name: StringName = &"", p_arguments: Dictionary = {}): 11 | name = p_name 12 | arguments = p_arguments 13 | 14 | 15 | # Block name and arguments backwards compatibility handling. 16 | const _renamed_blocks: Dictionary = { 17 | &"simplespawner_get_spawn_frequency": &"simplespawner_get_spawn_period", 18 | } 19 | 20 | 21 | func _set_name(value): 22 | var new_name = _renamed_blocks.get(value) 23 | if new_name: 24 | print("Migrating block %s to new name %s" % [value, new_name]) 25 | name = new_name 26 | if Engine.is_editor_hint(): 27 | EditorInterface.mark_scene_as_unsaved() 28 | else: 29 | name = value 30 | 31 | 32 | const _renamed_arguments: Dictionary = {} 33 | 34 | 35 | func _set_arguments(value): 36 | if not value is Dictionary: 37 | return 38 | 39 | var renamed_args = _renamed_arguments.get(name) 40 | if not renamed_args: 41 | # Try with the new block name if it hasn't been migrated yet. 42 | var new_block_name = _renamed_blocks.get(name) 43 | if new_block_name: 44 | renamed_args = _renamed_arguments.get(new_block_name) 45 | 46 | if renamed_args: 47 | var changed: bool = false 48 | value = value.duplicate() 49 | for old_arg in renamed_args.keys(): 50 | if not old_arg in value: 51 | continue 52 | 53 | var new_arg = renamed_args[old_arg] 54 | print("Migrating block %s argument %s to new name %s" % [name, old_arg, new_arg]) 55 | value[new_arg] = value[old_arg] 56 | value.erase(old_arg) 57 | changed = true 58 | 59 | if changed and Engine.is_editor_hint(): 60 | EditorInterface.mark_scene_as_unsaved() 61 | 62 | arguments = value 63 | -------------------------------------------------------------------------------- /serialization/value_block_serialization.gd.uid: -------------------------------------------------------------------------------- 1 | uid://ctw0ps1sk6d74 2 | -------------------------------------------------------------------------------- /translation/parser.gd: -------------------------------------------------------------------------------- 1 | @tool 2 | ## BlockCode translation parser plugin. 3 | ## 4 | ## Extracts translatable strings from BlockCode resources. Currently only 5 | ## BlockDefinition resources are handled. 6 | extends EditorTranslationParserPlugin 7 | 8 | const BLOCK_DEFINITION_SCRIPT_PATH := "res://addons/reblocks/code_generation/block_definition.gd" 9 | 10 | # BlockDefinition properties for translation 11 | const block_def_tx_properties: Array[String] = [ 12 | "category", 13 | "description", 14 | "display_template", 15 | ] 16 | 17 | 18 | func _get_recognized_extensions() -> PackedStringArray: 19 | # BlockDefinition resources currently use the generic tres extension. 20 | return ["tres"] 21 | 22 | 23 | func _resource_is_block_definition(resource: Resource) -> bool: 24 | var script := resource.get_script() 25 | if not script: 26 | return false 27 | return script.resource_path == BLOCK_DEFINITION_SCRIPT_PATH 28 | 29 | 30 | func _parse_file(path: String, msgids: Array[String], msgids_context_plural: Array[Array]) -> void: 31 | # Only BlockDefinition resources are supported. 32 | var res = ResourceLoader.load(path, "Resource") 33 | if not res or not _resource_is_block_definition(res): 34 | return 35 | for prop in block_def_tx_properties: 36 | var value: String = res.get(prop) 37 | if value: 38 | # For now just the messages are used. It might be better to provide 39 | # context with msgids_context_plural to avoid conflicts. 40 | msgids.append(value) 41 | -------------------------------------------------------------------------------- /translation/parser.gd.uid: -------------------------------------------------------------------------------- 1 | uid://lc46rs8la81q 2 | -------------------------------------------------------------------------------- /translation/utils.gd.uid: -------------------------------------------------------------------------------- 1 | uid://ce0vcyai6vjvy 2 | -------------------------------------------------------------------------------- /types/types.gd.uid: -------------------------------------------------------------------------------- 1 | uid://dmu5h51au2g1c 2 | -------------------------------------------------------------------------------- /ui/block_canvas/block_canvas.gd.uid: -------------------------------------------------------------------------------- 1 | uid://5i4d33gig2gj 2 | -------------------------------------------------------------------------------- /ui/block_editor_context.gd: -------------------------------------------------------------------------------- 1 | class_name BlockEditorContext 2 | extends Object 3 | 4 | signal changed 5 | 6 | static var _instance: BlockEditorContext 7 | 8 | var block_code_node: BlockCode: 9 | set(value): 10 | block_code_node = value 11 | changed.emit() 12 | 13 | var block_script: BlockScriptSerialization: 14 | get: 15 | if block_code_node == null: 16 | return null 17 | return block_code_node.block_script 18 | 19 | var parent_node: Node: 20 | get: 21 | if block_code_node == null: 22 | return null 23 | return block_code_node.get_parent() 24 | 25 | 26 | func force_update() -> void: 27 | changed.emit() 28 | 29 | 30 | static func get_default() -> BlockEditorContext: 31 | if _instance == null: 32 | _instance = BlockEditorContext.new() 33 | return _instance 34 | -------------------------------------------------------------------------------- /ui/block_editor_context.gd.uid: -------------------------------------------------------------------------------- 1 | uid://8y6lwtx6tyjn 2 | -------------------------------------------------------------------------------- /ui/block_tree_util.gd: -------------------------------------------------------------------------------- 1 | extends Object 2 | 3 | 4 | ## Returns the scope of the first non-empty scope child block 5 | static func get_tree_scope(node: Node) -> String: 6 | if node is Block: 7 | if node.definition.scope != "": 8 | return node.definition.scope 9 | 10 | for c in node.get_children(): 11 | var scope := get_tree_scope(c) 12 | if scope != "": 13 | return scope 14 | return "" 15 | 16 | 17 | ## Get the nearest Block node that is a parent of the provided node. 18 | static func get_parent_block(node: Node) -> Block: 19 | var parent = node.get_parent() 20 | while parent and not parent is Block: 21 | parent = parent.get_parent() 22 | return parent as Block 23 | -------------------------------------------------------------------------------- /ui/block_tree_util.gd.uid: -------------------------------------------------------------------------------- 1 | uid://w013b34y4cbd 2 | -------------------------------------------------------------------------------- /ui/blocks/block/block.gd.uid: -------------------------------------------------------------------------------- 1 | uid://cgc1aedsgtm8k 2 | -------------------------------------------------------------------------------- /ui/blocks/control_block/control_block.gd: -------------------------------------------------------------------------------- 1 | @tool 2 | class_name ControlBlock 3 | extends Block 4 | 5 | const Constants = preload("res://addons/reblocks/ui/constants.gd") 6 | 7 | 8 | func _ready(): 9 | super() 10 | 11 | %TopBackground.color = color 12 | %BottomBackground.color = color 13 | %SnapPoint.add_theme_constant_override("margin_left", Constants.CONTROL_MARGIN) 14 | %SnapGutter.color = color 15 | %SnapGutter.custom_minimum_size.x = Constants.CONTROL_MARGIN 16 | 17 | 18 | func _on_drag_drop_area_drag_started(offset: Vector2) -> void: 19 | _drag_started(offset) 20 | 21 | 22 | static func get_block_class(): 23 | return "ControlBlock" 24 | 25 | 26 | static func get_scene_path(): 27 | return "res://addons/reblocks/ui/blocks/control_block/control_block.tscn" 28 | -------------------------------------------------------------------------------- /ui/blocks/control_block/control_block.gd.uid: -------------------------------------------------------------------------------- 1 | uid://k4parnn65f1r 2 | -------------------------------------------------------------------------------- /ui/blocks/entry_block/entry_block.gd: -------------------------------------------------------------------------------- 1 | @tool 2 | class_name EntryBlock 3 | extends StatementBlock 4 | 5 | ## if non-empty, this block defines a callback that will be connected to the signal with this name 6 | @export var signal_name: String 7 | 8 | 9 | func _ready(): 10 | super() 11 | bottom_snap = null 12 | 13 | 14 | static func get_block_class(): 15 | return "EntryBlock" 16 | 17 | 18 | static func get_scene_path(): 19 | return "res://addons/reblocks/ui/blocks/entry_block/entry_block.tscn" 20 | -------------------------------------------------------------------------------- /ui/blocks/entry_block/entry_block.gd.uid: -------------------------------------------------------------------------------- 1 | uid://i1nt7sa7gn5r 2 | -------------------------------------------------------------------------------- /ui/blocks/entry_block/entry_block.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=6 format=3 uid="uid://d2fibflv3ojys"] 2 | 3 | [ext_resource type="Script" path="res://addons/reblocks/ui/blocks/entry_block/entry_block.gd" id="2_3ik8h"] 4 | [ext_resource type="Script" path="res://addons/reblocks/ui/blocks/utilities/background/background.gd" id="2_yrw8l"] 5 | [ext_resource type="PackedScene" uid="uid://c7puyxpqcq6xo" path="res://addons/reblocks/ui/blocks/utilities/drag_drop_area/drag_drop_area.tscn" id="3_swkpp"] 6 | [ext_resource type="PackedScene" uid="uid://b1xvp3u11h41s" path="res://addons/reblocks/ui/blocks/utilities/template_editor/template_editor.tscn" id="4_1gwsm"] 7 | [ext_resource type="PackedScene" uid="uid://b1oge52xhjqnu" path="res://addons/reblocks/ui/blocks/utilities/snap_point/snap_point.tscn" id="4_yj206"] 8 | 9 | [node name="EntryBlock" type="MarginContainer" node_paths=PackedStringArray("child_snap", "template_editor")] 10 | size_flags_horizontal = 0 11 | focus_mode = 2 12 | mouse_filter = 2 13 | script = ExtResource("2_3ik8h") 14 | child_snap = NodePath("VBoxContainer/SnapPoint") 15 | template_editor = NodePath("VBoxContainer/TopMarginContainer/MarginContainer/TemplateEditor") 16 | 17 | [node name="VBoxContainer" type="VBoxContainer" parent="."] 18 | layout_mode = 2 19 | mouse_filter = 2 20 | theme_override_constants/separation = 0 21 | 22 | [node name="DragDropArea" parent="VBoxContainer" instance=ExtResource("3_swkpp")] 23 | custom_minimum_size = Vector2(80, 16) 24 | layout_mode = 2 25 | size_flags_horizontal = 0 26 | mouse_default_cursor_shape = 2 27 | 28 | [node name="TopMarginContainer" type="MarginContainer" parent="VBoxContainer"] 29 | custom_minimum_size = Vector2(0, 30) 30 | layout_mode = 2 31 | size_flags_horizontal = 0 32 | mouse_filter = 2 33 | theme_override_constants/margin_left = 0 34 | theme_override_constants/margin_top = 0 35 | theme_override_constants/margin_right = 0 36 | theme_override_constants/margin_bottom = 0 37 | 38 | [node name="Background" type="Control" parent="VBoxContainer/TopMarginContainer"] 39 | unique_name_in_owner = true 40 | layout_mode = 2 41 | mouse_filter = 1 42 | script = ExtResource("2_yrw8l") 43 | color = Color(1, 1, 1, 1) 44 | block_type = 1 45 | 46 | [node name="DragDropArea" parent="VBoxContainer/TopMarginContainer" instance=ExtResource("3_swkpp")] 47 | layout_mode = 2 48 | mouse_default_cursor_shape = 2 49 | 50 | [node name="MarginContainer" type="MarginContainer" parent="VBoxContainer/TopMarginContainer"] 51 | layout_mode = 2 52 | mouse_filter = 2 53 | theme_override_constants/margin_left = 10 54 | theme_override_constants/margin_top = 6 55 | theme_override_constants/margin_right = 12 56 | theme_override_constants/margin_bottom = 6 57 | 58 | [node name="TemplateEditor" parent="VBoxContainer/TopMarginContainer/MarginContainer" instance=ExtResource("4_1gwsm")] 59 | unique_name_in_owner = true 60 | layout_mode = 2 61 | 62 | [node name="SnapPoint" parent="VBoxContainer" instance=ExtResource("4_yj206")] 63 | layout_mode = 2 64 | 65 | [connection signal="drag_started" from="VBoxContainer/DragDropArea" to="." method="_on_drag_drop_area_drag_started"] 66 | [connection signal="drag_started" from="VBoxContainer/TopMarginContainer/DragDropArea" to="." method="_on_drag_drop_area_drag_started"] 67 | -------------------------------------------------------------------------------- /ui/blocks/parameter_block/parameter_block.gd: -------------------------------------------------------------------------------- 1 | @tool 2 | class_name ParameterBlock 3 | extends Block 4 | 5 | const Constants = preload("res://addons/reblocks/ui/constants.gd") 6 | const Util = preload("res://addons/reblocks/ui/util.gd") 7 | const ParameterOutput = preload("res://addons/reblocks/ui/blocks/utilities/parameter_output/parameter_output.gd") 8 | 9 | @onready var _background := %Background 10 | 11 | var args_to_add_after_format: Dictionary # Only used when loading 12 | var spawned_by: ParameterOutput 13 | 14 | 15 | func _ready(): 16 | super() 17 | _background.color = color 18 | _update_block_shape() 19 | 20 | 21 | func _on_definition_changed(): 22 | super() 23 | _update_block_shape() 24 | 25 | 26 | func _update_block_shape(): 27 | if not definition: 28 | return 29 | await ready 30 | _background.is_pointy_value = definition.variant_type == TYPE_BOOL 31 | 32 | 33 | func _on_drag_drop_area_drag_started(offset: Vector2) -> void: 34 | _drag_started(offset) 35 | 36 | 37 | static func get_block_class(): 38 | return "ParameterBlock" 39 | 40 | 41 | static func get_scene_path(): 42 | return "res://addons/reblocks/ui/blocks/parameter_block/parameter_block.tscn" 43 | -------------------------------------------------------------------------------- /ui/blocks/parameter_block/parameter_block.gd.uid: -------------------------------------------------------------------------------- 1 | uid://b6w7djlymksvj 2 | -------------------------------------------------------------------------------- /ui/blocks/parameter_block/parameter_block.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=5 format=3 uid="uid://clipm2dd28jde"] 2 | 3 | [ext_resource type="Script" path="res://addons/reblocks/ui/blocks/parameter_block/parameter_block.gd" id="1_0hajy"] 4 | [ext_resource type="PackedScene" uid="uid://c7puyxpqcq6xo" path="res://addons/reblocks/ui/blocks/utilities/drag_drop_area/drag_drop_area.tscn" id="2_0eadx"] 5 | [ext_resource type="Script" path="res://addons/reblocks/ui/blocks/utilities/background/background.gd" id="2_oimwh"] 6 | [ext_resource type="PackedScene" uid="uid://b1xvp3u11h41s" path="res://addons/reblocks/ui/blocks/utilities/template_editor/template_editor.tscn" id="3_shl1a"] 7 | 8 | [node name="ParameterBlock" type="MarginContainer" node_paths=PackedStringArray("template_editor")] 9 | offset_right = 16.0 10 | offset_bottom = 8.0 11 | size_flags_horizontal = 0 12 | focus_mode = 2 13 | mouse_filter = 2 14 | script = ExtResource("1_0hajy") 15 | template_editor = NodePath("MarginContainer/TemplateEditor") 16 | 17 | [node name="Background" type="Control" parent="."] 18 | unique_name_in_owner = true 19 | layout_mode = 2 20 | script = ExtResource("2_oimwh") 21 | color = Color(1, 1, 1, 1) 22 | block_type = 3 23 | is_pointy_value = null 24 | 25 | [node name="DragDropArea" parent="." instance=ExtResource("2_0eadx")] 26 | layout_mode = 2 27 | mouse_default_cursor_shape = 2 28 | 29 | [node name="MarginContainer" type="MarginContainer" parent="."] 30 | layout_mode = 2 31 | mouse_filter = 2 32 | theme_override_constants/margin_left = 10 33 | theme_override_constants/margin_right = 10 34 | 35 | [node name="TemplateEditor" parent="MarginContainer" instance=ExtResource("3_shl1a")] 36 | unique_name_in_owner = true 37 | layout_mode = 2 38 | size_flags_horizontal = 0 39 | theme_override_constants/margin_left = 10 40 | theme_override_constants/margin_top = 8 41 | theme_override_constants/margin_right = 10 42 | theme_override_constants/margin_bottom = 8 43 | 44 | [connection signal="focus_entered" from="." to="." method="_on_focus_entered"] 45 | [connection signal="focus_exited" from="." to="." method="_on_focus_exited"] 46 | [connection signal="drag_started" from="DragDropArea" to="." method="_on_drag_drop_area_drag_started"] 47 | -------------------------------------------------------------------------------- /ui/blocks/statement_block/statement_block.gd: -------------------------------------------------------------------------------- 1 | @tool 2 | class_name StatementBlock 3 | extends Block 4 | 5 | const Types = preload("res://addons/reblocks/types/types.gd") 6 | 7 | @onready var _background := %Background 8 | 9 | var arg_name_to_param_input_dict: Dictionary 10 | var args_to_add_after_format: Dictionary # Only used when loading 11 | 12 | 13 | func _ready(): 14 | super() 15 | _background.color = color 16 | 17 | 18 | func _on_drag_drop_area_drag_started(offset: Vector2) -> void: 19 | _drag_started(offset) 20 | 21 | 22 | static func get_block_class(): 23 | return "StatementBlock" 24 | 25 | 26 | static func get_scene_path(): 27 | return "res://addons/reblocks/ui/blocks/statement_block/statement_block.tscn" 28 | -------------------------------------------------------------------------------- /ui/blocks/statement_block/statement_block.gd.uid: -------------------------------------------------------------------------------- 1 | uid://di3niamt3587v 2 | -------------------------------------------------------------------------------- /ui/blocks/statement_block/statement_block.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=6 format=3 uid="uid://c84vmg3odrtxt"] 2 | 3 | [ext_resource type="Script" path="res://addons/reblocks/ui/blocks/statement_block/statement_block.gd" id="1_6wvlf"] 4 | [ext_resource type="Script" path="res://addons/reblocks/ui/blocks/utilities/background/background.gd" id="2_lctqt"] 5 | [ext_resource type="PackedScene" uid="uid://b1oge52xhjqnu" path="res://addons/reblocks/ui/blocks/utilities/snap_point/snap_point.tscn" id="3_5vaov"] 6 | [ext_resource type="PackedScene" uid="uid://c7puyxpqcq6xo" path="res://addons/reblocks/ui/blocks/utilities/drag_drop_area/drag_drop_area.tscn" id="3_mbxhq"] 7 | [ext_resource type="PackedScene" uid="uid://b1xvp3u11h41s" path="res://addons/reblocks/ui/blocks/utilities/template_editor/template_editor.tscn" id="4_vky23"] 8 | 9 | [node name="StatementBlock" type="MarginContainer" node_paths=PackedStringArray("bottom_snap", "template_editor")] 10 | size_flags_horizontal = 0 11 | focus_mode = 2 12 | mouse_filter = 2 13 | script = ExtResource("1_6wvlf") 14 | bottom_snap = NodePath("VBoxContainer/SnapPoint") 15 | template_editor = NodePath("VBoxContainer/TopMarginContainer/MarginContainer/TemplateEditor") 16 | 17 | [node name="VBoxContainer" type="VBoxContainer" parent="."] 18 | layout_mode = 2 19 | mouse_filter = 2 20 | theme_override_constants/separation = 0 21 | 22 | [node name="TopMarginContainer" type="MarginContainer" parent="VBoxContainer"] 23 | custom_minimum_size = Vector2(0, 30) 24 | layout_mode = 2 25 | size_flags_horizontal = 0 26 | mouse_filter = 2 27 | theme_override_constants/margin_left = 0 28 | theme_override_constants/margin_top = 0 29 | theme_override_constants/margin_right = 0 30 | theme_override_constants/margin_bottom = 0 31 | 32 | [node name="Background" type="Control" parent="VBoxContainer/TopMarginContainer"] 33 | unique_name_in_owner = true 34 | layout_mode = 2 35 | mouse_filter = 1 36 | script = ExtResource("2_lctqt") 37 | 38 | [node name="DragDropArea" parent="VBoxContainer/TopMarginContainer" instance=ExtResource("3_mbxhq")] 39 | layout_mode = 2 40 | mouse_default_cursor_shape = 2 41 | 42 | [node name="MarginContainer" type="MarginContainer" parent="VBoxContainer/TopMarginContainer"] 43 | layout_mode = 2 44 | mouse_filter = 2 45 | theme_override_constants/margin_left = 10 46 | theme_override_constants/margin_top = 6 47 | theme_override_constants/margin_right = 12 48 | theme_override_constants/margin_bottom = 6 49 | 50 | [node name="TemplateEditor" parent="VBoxContainer/TopMarginContainer/MarginContainer" instance=ExtResource("4_vky23")] 51 | unique_name_in_owner = true 52 | layout_mode = 2 53 | 54 | [node name="SnapPoint" parent="VBoxContainer" instance=ExtResource("3_5vaov")] 55 | layout_mode = 2 56 | 57 | [connection signal="drag_started" from="VBoxContainer/TopMarginContainer/DragDropArea" to="." method="_on_drag_drop_area_drag_started"] 58 | -------------------------------------------------------------------------------- /ui/blocks/utilities/background/background.gd.uid: -------------------------------------------------------------------------------- 1 | uid://cv33xhf4grjdh 2 | -------------------------------------------------------------------------------- /ui/blocks/utilities/background/gutter.gd: -------------------------------------------------------------------------------- 1 | @tool 2 | extends Control 3 | 4 | const BlockTreeUtil = preload("res://addons/reblocks/ui/block_tree_util.gd") 5 | const Constants = preload("res://addons/reblocks/ui/constants.gd") 6 | 7 | var outline_color: Color 8 | var parent_block: Block 9 | 10 | @export var color: Color: 11 | set = _set_color 12 | 13 | 14 | func _set_color(new_color): 15 | color = new_color 16 | outline_color = color.darkened(0.2) 17 | queue_redraw() 18 | 19 | 20 | func _ready(): 21 | parent_block = BlockTreeUtil.get_parent_block(self) 22 | parent_block.focus_entered.connect(queue_redraw) 23 | parent_block.focus_exited.connect(queue_redraw) 24 | 25 | 26 | func _draw(): 27 | var fill_polygon: PackedVector2Array 28 | fill_polygon.append(Vector2(0.0, 0.0)) 29 | fill_polygon.append(Vector2(size.x, 0.0)) 30 | fill_polygon.append(Vector2(size.x, size.y)) 31 | fill_polygon.append(Vector2(0.0, size.y)) 32 | fill_polygon.append(Vector2(0.0, 0.0)) 33 | 34 | var left_polygon: PackedVector2Array 35 | var right_polygon: PackedVector2Array 36 | 37 | left_polygon.append(Vector2(0.0, 0.0)) 38 | left_polygon.append(Vector2(0.0, size.y)) 39 | 40 | right_polygon.append(Vector2(size.x, 0.0)) 41 | right_polygon.append(Vector2(size.x, size.y)) 42 | 43 | draw_colored_polygon(fill_polygon, color) 44 | draw_polyline(left_polygon, Constants.FOCUS_BORDER_COLOR if parent_block.has_focus() else outline_color, Constants.OUTLINE_WIDTH) 45 | draw_polyline(right_polygon, Constants.FOCUS_BORDER_COLOR if parent_block.has_focus() else outline_color, Constants.OUTLINE_WIDTH) 46 | -------------------------------------------------------------------------------- /ui/blocks/utilities/background/gutter.gd.uid: -------------------------------------------------------------------------------- 1 | uid://byvmxt4jx7ht6 2 | -------------------------------------------------------------------------------- /ui/blocks/utilities/drag_drop_area/drag_drop_area.gd: -------------------------------------------------------------------------------- 1 | @tool 2 | ## Drag drop area. 3 | ## 4 | ## A Control which watches for click and drag gestures beginning from itself. 5 | ## It propagates events up to its parent, so it is possible to place this 6 | ## control inside a control which processes input events such as [LineEdit]. 7 | ## If a drag occurs, it emits [signal drag_started]. 8 | extends Control 9 | 10 | const Constants = preload("res://addons/reblocks/ui/constants.gd") 11 | const BlockTreeUtil = preload("res://addons/reblocks/ui/block_tree_util.gd") 12 | 13 | signal drag_started(offset: Vector2) 14 | 15 | ## True to require that the mouse move outside of the component before 16 | ## [signal drag_started] is emitted. 17 | @export var drag_outside: bool = false 18 | 19 | var _drag_start_position: Vector2 = Vector2.INF 20 | var parent_block: Block 21 | 22 | 23 | func _gui_input(event: InputEvent) -> void: 24 | # Watch for mouse clicks using _gui_input, so events are filtered based on 25 | # rules of the GUI system. 26 | 27 | if not event is InputEventMouseButton: 28 | return 29 | 30 | var button_event: InputEventMouseButton = event as InputEventMouseButton 31 | 32 | if button_event.button_index != MOUSE_BUTTON_LEFT and button_event.button_index != MOUSE_BUTTON_RIGHT: 33 | return 34 | 35 | if button_event.double_click: 36 | # Double click event (with the mouse released) has both pressed=true 37 | # and double_click=true, so ignore it as a special case. 38 | pass 39 | elif button_event.pressed: 40 | # Keep track of where the mouse click originated, but allow this 41 | # event to propagate to other nodes. 42 | if button_event.button_index == MOUSE_BUTTON_LEFT: 43 | _drag_start_position = event.global_position 44 | else: 45 | if not parent_block: 46 | parent_block = BlockTreeUtil.get_parent_block(self) 47 | 48 | if parent_block and parent_block.can_delete: 49 | # Accepts to avoid menu conflicts 50 | accept_event() 51 | 52 | # A new right-click menu with items 53 | var _context_menu := PopupMenu.new() 54 | _context_menu.add_icon_item(EditorInterface.get_editor_theme().get_icon("Duplicate", "EditorIcons"), "Duplicate") 55 | _context_menu.add_icon_item(EditorInterface.get_editor_theme().get_icon("Remove", "EditorIcons"), "Delete") 56 | _context_menu.popup_hide.connect(_cleanup) 57 | _context_menu.id_pressed.connect(_menu_pressed.bind(_context_menu)) 58 | 59 | _context_menu.position = DisplayServer.mouse_get_position() 60 | add_child(_context_menu) 61 | 62 | _context_menu.show() 63 | else: 64 | _drag_start_position = Vector2.INF 65 | 66 | 67 | func _input(event: InputEvent) -> void: 68 | # Watch for mouse movements using _input. This way, we receive mouse 69 | # motion events that occur outside of the component before the GUI system 70 | # does. 71 | 72 | if not event is InputEventMouseMotion: 73 | return 74 | 75 | if _drag_start_position == Vector2.INF: 76 | return 77 | 78 | var motion_event: InputEventMouseMotion = event as InputEventMouseMotion 79 | 80 | if drag_outside and get_global_rect().has_point(motion_event.global_position): 81 | return 82 | 83 | if _drag_start_position.distance_to(motion_event.global_position) < Constants.MINIMUM_DRAG_THRESHOLD: 84 | return 85 | 86 | get_viewport().set_input_as_handled() 87 | drag_started.emit(_drag_start_position - motion_event.global_position) 88 | _drag_start_position = Vector2.INF 89 | 90 | 91 | func _menu_pressed(_index: int, _context_menu: PopupMenu): 92 | # Getting which item was pressed and the corresponding function 93 | var _pressed_label: String = _context_menu.get_item_text(_index) 94 | 95 | if _pressed_label == "Duplicate": 96 | parent_block.confirm_duplicate() 97 | elif _pressed_label == "Delete": 98 | parent_block.confirm_delete() 99 | 100 | 101 | func _cleanup(): 102 | for child in get_children(): 103 | remove_child(child) 104 | child.queue_free() 105 | -------------------------------------------------------------------------------- /ui/blocks/utilities/drag_drop_area/drag_drop_area.gd.uid: -------------------------------------------------------------------------------- 1 | uid://cdhofr7vgp1tw 2 | -------------------------------------------------------------------------------- /ui/blocks/utilities/drag_drop_area/drag_drop_area.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=2 format=3 uid="uid://c7puyxpqcq6xo"] 2 | 3 | [ext_resource type="Script" path="res://addons/reblocks/ui/blocks/utilities/drag_drop_area/drag_drop_area.gd" id="1_5vdxp"] 4 | 5 | [node name="DragDropArea" type="Control"] 6 | layout_mode = 3 7 | anchors_preset = 15 8 | anchor_right = 1.0 9 | anchor_bottom = 1.0 10 | grow_horizontal = 2 11 | grow_vertical = 2 12 | mouse_filter = 1 13 | script = ExtResource("1_5vdxp") 14 | -------------------------------------------------------------------------------- /ui/blocks/utilities/parameter_input/parameter_input.gd.uid: -------------------------------------------------------------------------------- 1 | uid://ci3p07wpcslkb 2 | -------------------------------------------------------------------------------- /ui/blocks/utilities/parameter_output/parameter_output.gd: -------------------------------------------------------------------------------- 1 | @tool 2 | extends MarginContainer 3 | 4 | const Types = preload("res://addons/reblocks/types/types.gd") 5 | const ParameterBlock = preload("res://addons/reblocks/ui/blocks/parameter_block/parameter_block.gd") 6 | 7 | var block: Block 8 | var parameter_name: String 9 | var _block_name: String: 10 | get: 11 | return block.definition.name if block else "" 12 | 13 | @export var block_params: Dictionary 14 | 15 | @onready var _context := BlockEditorContext.get_default() 16 | 17 | @onready var _snap_point := %SnapPoint 18 | 19 | 20 | func _ready(): 21 | _update_parameter_block.call_deferred() 22 | 23 | 24 | func _update_parameter_block(): 25 | if _snap_point == null: 26 | return 27 | 28 | if _snap_point.has_snapped_block(): 29 | return 30 | 31 | if _context.block_script == null: 32 | return 33 | 34 | var block_name = &"%s:%s" % [_block_name, parameter_name] 35 | var parameter_block: ParameterBlock = _context.block_script.instantiate_block_by_name(block_name) 36 | 37 | if parameter_block == null: 38 | # FIXME: This sometimes occurs when a script is loaded but it is unclear why 39 | #push_error("Unable to create output block %s." % block_name) 40 | return 41 | 42 | _snap_point.add_child.call_deferred(parameter_block) 43 | 44 | 45 | func _on_parameter_block_drag_started(drag_block: Block, offset: Vector2): 46 | block.drag_started.emit(drag_block, offset) 47 | 48 | 49 | func _on_snap_point_snapped_block_changed(snap_block: Block): 50 | if snap_block == null: 51 | return 52 | # FIXME: The spawned_by property isn't serialized, so we'll set it here to 53 | # be sure. In the future, we should try to get rid of this property. 54 | snap_block.spawned_by = self 55 | snap_block.drag_started.connect(_on_parameter_block_drag_started) 56 | 57 | 58 | func _on_snap_point_snapped_block_removed(snap_block: Block): 59 | snap_block.drag_started.disconnect(_on_parameter_block_drag_started) 60 | _update_parameter_block.call_deferred() 61 | -------------------------------------------------------------------------------- /ui/blocks/utilities/parameter_output/parameter_output.gd.uid: -------------------------------------------------------------------------------- 1 | uid://bgx7kphxxwdtt 2 | -------------------------------------------------------------------------------- /ui/blocks/utilities/parameter_output/parameter_output.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=4 format=3 uid="uid://dp01u74qkty7r"] 2 | 3 | [ext_resource type="Script" path="res://addons/reblocks/ui/blocks/utilities/parameter_output/parameter_output.gd" id="1_eebb2"] 4 | [ext_resource type="PackedScene" uid="uid://b1oge52xhjqnu" path="res://addons/reblocks/ui/blocks/utilities/snap_point/snap_point.tscn" id="2_ngr7c"] 5 | 6 | [sub_resource type="StyleBoxFlat" id="StyleBoxFlat_tn6h4"] 7 | bg_color = Color(1, 1, 1, 1) 8 | corner_radius_top_left = 40 9 | corner_radius_top_right = 40 10 | corner_radius_bottom_right = 40 11 | corner_radius_bottom_left = 40 12 | 13 | [node name="ParameterOutput" type="MarginContainer"] 14 | anchors_preset = 15 15 | anchor_right = 1.0 16 | anchor_bottom = 1.0 17 | offset_right = -1052.0 18 | offset_bottom = -617.0 19 | grow_horizontal = 2 20 | grow_vertical = 2 21 | mouse_filter = 2 22 | script = ExtResource("1_eebb2") 23 | 24 | [node name="Panel" type="Panel" parent="."] 25 | unique_name_in_owner = true 26 | layout_mode = 2 27 | mouse_filter = 2 28 | theme_override_styles/panel = SubResource("StyleBoxFlat_tn6h4") 29 | 30 | [node name="SnapPoint" parent="." instance=ExtResource("2_ngr7c")] 31 | unique_name_in_owner = true 32 | layout_mode = 2 33 | block_type = 0 34 | variant_type = 4 35 | 36 | [connection signal="snapped_block_changed" from="SnapPoint" to="." method="_on_snap_point_snapped_block_changed"] 37 | [connection signal="snapped_block_removed" from="SnapPoint" to="." method="_on_snap_point_snapped_block_removed"] 38 | -------------------------------------------------------------------------------- /ui/blocks/utilities/snap_point/snap_point.gd: -------------------------------------------------------------------------------- 1 | @tool 2 | class_name SnapPoint 3 | extends MarginContainer 4 | 5 | const Types = preload("res://addons/reblocks/types/types.gd") 6 | 7 | @export var block_type: Types.BlockType = Types.BlockType.STATEMENT 8 | 9 | @export var snapped_block: Block: 10 | get: 11 | return snapped_block 12 | set(value): 13 | if value != snapped_block: 14 | var old_block = snapped_block 15 | snapped_block = value 16 | snapped_block_changed.emit(snapped_block) 17 | if value == null and old_block: 18 | snapped_block_removed.emit(old_block) 19 | 20 | ## When block_type is [enum Types.BlockType.VALUE], the type of the value that can be used at this snap point. 21 | @export var variant_type: Variant.Type 22 | 23 | signal drag_started(block: Block) 24 | signal snapped_block_changed(block: Block) 25 | signal snapped_block_removed(block: Block) 26 | 27 | 28 | func _ready(): 29 | _update_snapped_block_from_children() 30 | 31 | 32 | func _update_snapped_block_from_children(): 33 | # Temporary migration to set the snapped_block property based on children 34 | # of this node. 35 | if snapped_block: 36 | return 37 | for node in get_children(): 38 | var child_block = node as Block 39 | if child_block: 40 | snapped_block = child_block 41 | return 42 | 43 | 44 | func get_snapped_block() -> Block: 45 | return snapped_block 46 | 47 | 48 | func has_snapped_block() -> bool: 49 | return snapped_block != null 50 | 51 | 52 | func replace_snapped_block(new_block: Block): 53 | var old_block = get_snapped_block() 54 | 55 | if old_block: 56 | remove_child(old_block) 57 | 58 | if new_block: 59 | add_child(new_block) 60 | 61 | 62 | func insert_snapped_block(new_block: Block) -> Block: 63 | var old_block = get_snapped_block() 64 | 65 | if old_block: 66 | remove_child(old_block) 67 | 68 | if new_block: 69 | add_child(new_block) 70 | 71 | if new_block and old_block: 72 | var last_snap = _get_last_snap(new_block) 73 | if last_snap: 74 | old_block = last_snap.insert_snapped_block(old_block) 75 | 76 | return old_block 77 | 78 | 79 | func _get_last_snap(next_block: Block) -> SnapPoint: 80 | var last_snap: SnapPoint 81 | while next_block: 82 | last_snap = next_block.bottom_snap 83 | next_block = last_snap.get_snapped_block() if last_snap else null 84 | return last_snap 85 | 86 | 87 | func _on_child_entered_tree(node): 88 | var new_block = node as Block 89 | if not new_block: 90 | return 91 | if new_block == snapped_block: 92 | return 93 | if snapped_block: 94 | # We only allow a single snapped block at a time 95 | push_warning("Attempted to add more than one Block node ({block}) to the same SnapPoint ({snap_point})".format({"block": new_block, "snap_point": self})) 96 | remove_child.call_deferred(snapped_block) 97 | snapped_block = new_block 98 | 99 | 100 | func _on_child_exiting_tree(node): 101 | var old_block = node as Block 102 | if old_block and old_block == snapped_block: 103 | snapped_block = null 104 | -------------------------------------------------------------------------------- /ui/blocks/utilities/snap_point/snap_point.gd.uid: -------------------------------------------------------------------------------- 1 | uid://be4hpnullwwgp 2 | -------------------------------------------------------------------------------- /ui/blocks/utilities/snap_point/snap_point.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=2 format=3 uid="uid://b1oge52xhjqnu"] 2 | 3 | [ext_resource type="Script" path="res://addons/reblocks/ui/blocks/utilities/snap_point/snap_point.gd" id="1_kseym"] 4 | 5 | [node name="SnapPoint" type="MarginContainer" groups=["snap_point"]] 6 | anchors_preset = 15 7 | anchor_right = 1.0 8 | anchor_bottom = 1.0 9 | offset_right = -1152.0 10 | offset_bottom = -648.0 11 | grow_horizontal = 2 12 | grow_vertical = 2 13 | mouse_filter = 2 14 | script = ExtResource("1_kseym") 15 | 16 | [connection signal="child_entered_tree" from="." to="." method="_on_child_entered_tree"] 17 | [connection signal="child_exiting_tree" from="." to="." method="_on_child_exiting_tree"] 18 | -------------------------------------------------------------------------------- /ui/blocks/utilities/template_editor/collapsable_settings.gd: -------------------------------------------------------------------------------- 1 | @tool 2 | class_name CollapsableSettings 3 | extends HBoxContainer 4 | 5 | @onready var _expand_button: Button = %ExpandSettingsButton 6 | @onready var _collapse_button: Button = %CollapseSettingsButton 7 | var _collapsed := false 8 | 9 | 10 | func _ready() -> void: 11 | _collapse() 12 | move_child(_expand_button, 0) 13 | move_child(_collapse_button, -1) 14 | _expand_button.connect("button_up", _expand) 15 | _collapse_button.connect("button_up", _collapse) 16 | 17 | 18 | func _expand() -> void: 19 | if not _collapsed: 20 | return 21 | for child in get_children(true): 22 | child.visible = true 23 | _expand_button.visible = false 24 | _collapse_button.visible = true 25 | _collapsed = false 26 | 27 | 28 | func _collapse() -> void: 29 | if _collapsed: 30 | return 31 | for child in get_children(true): 32 | child.visible = false 33 | _expand_button.visible = true 34 | _collapsed = true 35 | -------------------------------------------------------------------------------- /ui/blocks/utilities/template_editor/collapsable_settings.gd.uid: -------------------------------------------------------------------------------- 1 | uid://b2ir1wey2qtyo 2 | -------------------------------------------------------------------------------- /ui/blocks/utilities/template_editor/collapsable_settings.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=4 format=3 uid="uid://1xfpd777g8pf"] 2 | 3 | [ext_resource type="Script" path="res://addons/reblocks/ui/blocks/utilities/template_editor/collapsable_settings.gd" id="1_f0ssn"] 4 | [ext_resource type="Texture2D" uid="uid://cd243la33evh" path="res://addons/reblocks/ui/blocks/utilities/template_editor/plus.svg" id="2_mp58d"] 5 | [ext_resource type="Texture2D" uid="uid://dmplpvmlpcdrk" path="res://addons/reblocks/ui/blocks/utilities/template_editor/minus.svg" id="3_adq5s"] 6 | 7 | [node name="CollapsableSettings" type="HBoxContainer"] 8 | offset_right = 36.0 9 | offset_bottom = 31.0 10 | script = ExtResource("1_f0ssn") 11 | 12 | [node name="ExpandSettingsButton" type="Button" parent="."] 13 | unique_name_in_owner = true 14 | layout_mode = 2 15 | icon = ExtResource("2_mp58d") 16 | flat = true 17 | icon_alignment = 1 18 | 19 | [node name="CollapseSettingsButton" type="Button" parent="."] 20 | unique_name_in_owner = true 21 | custom_minimum_size = Vector2(20, 20) 22 | layout_mode = 2 23 | icon = ExtResource("3_adq5s") 24 | flat = true 25 | icon_alignment = 1 26 | -------------------------------------------------------------------------------- /ui/blocks/utilities/template_editor/minus.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 16 | 35 | 37 | 41 | 47 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /ui/blocks/utilities/template_editor/minus.svg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://dmplpvmlpcdrk" 6 | path="res://.godot/imported/minus.svg-d7eb9fd8d189f35d0738132dd443fd4c.ctex" 7 | metadata={ 8 | "vram_texture": false 9 | } 10 | 11 | [deps] 12 | 13 | source_file="res://addons/reblocks/ui/blocks/utilities/template_editor/minus.svg" 14 | dest_files=["res://.godot/imported/minus.svg-d7eb9fd8d189f35d0738132dd443fd4c.ctex"] 15 | 16 | [params] 17 | 18 | compress/mode=0 19 | compress/high_quality=false 20 | compress/lossy_quality=0.7 21 | compress/hdr_compression=1 22 | compress/normal_map=0 23 | compress/channel_pack=0 24 | mipmaps/generate=false 25 | mipmaps/limit=-1 26 | roughness/mode=0 27 | roughness/src_normal="" 28 | process/fix_alpha_border=true 29 | process/premult_alpha=false 30 | process/normal_map_invert_y=false 31 | process/hdr_as_srgb=false 32 | process/hdr_clamp_exposure=false 33 | process/size_limit=0 34 | detect_3d/compress_to=1 35 | svg/scale=1.0 36 | editor/scale_with_editor_scale=false 37 | editor/convert_colors_with_editor_theme=false 38 | -------------------------------------------------------------------------------- /ui/blocks/utilities/template_editor/plus.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 16 | 35 | 37 | 41 | 47 | 54 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /ui/blocks/utilities/template_editor/plus.svg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://cd243la33evh" 6 | path="res://.godot/imported/plus.svg-18d400f84cd1d85e41a3d9ade4846429.ctex" 7 | metadata={ 8 | "vram_texture": false 9 | } 10 | 11 | [deps] 12 | 13 | source_file="res://addons/reblocks/ui/blocks/utilities/template_editor/plus.svg" 14 | dest_files=["res://.godot/imported/plus.svg-18d400f84cd1d85e41a3d9ade4846429.ctex"] 15 | 16 | [params] 17 | 18 | compress/mode=0 19 | compress/high_quality=false 20 | compress/lossy_quality=0.7 21 | compress/hdr_compression=1 22 | compress/normal_map=0 23 | compress/channel_pack=0 24 | mipmaps/generate=false 25 | mipmaps/limit=-1 26 | roughness/mode=0 27 | roughness/src_normal="" 28 | process/fix_alpha_border=true 29 | process/premult_alpha=false 30 | process/normal_map_invert_y=false 31 | process/hdr_as_srgb=false 32 | process/hdr_clamp_exposure=false 33 | process/size_limit=0 34 | detect_3d/compress_to=1 35 | svg/scale=1.0 36 | editor/scale_with_editor_scale=false 37 | editor/convert_colors_with_editor_theme=false 38 | -------------------------------------------------------------------------------- /ui/blocks/utilities/template_editor/template_editor.gd.uid: -------------------------------------------------------------------------------- 1 | uid://o6f8yps7ppb7 2 | -------------------------------------------------------------------------------- /ui/blocks/utilities/template_editor/template_editor.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=2 format=3 uid="uid://b1xvp3u11h41s"] 2 | 3 | [ext_resource type="Script" path="res://addons/reblocks/ui/blocks/utilities/template_editor/template_editor.gd" id="1_7extq"] 4 | 5 | [node name="TemplateEditor" type="MarginContainer"] 6 | anchors_preset = 15 7 | anchor_right = 1.0 8 | anchor_bottom = 1.0 9 | grow_horizontal = 2 10 | grow_vertical = 2 11 | mouse_filter = 2 12 | script = ExtResource("1_7extq") 13 | editable = null 14 | 15 | [node name="Container" type="HBoxContainer" parent="."] 16 | unique_name_in_owner = true 17 | layout_mode = 2 18 | mouse_filter = 2 19 | -------------------------------------------------------------------------------- /ui/constants.gd: -------------------------------------------------------------------------------- 1 | extends Object 2 | 3 | const CURRENT_DATA_VERSION = 0 4 | 5 | const KNOB_X = 10.0 6 | const KNOB_W = 20.0 7 | const KNOB_H = 5.0 8 | const KNOB_Z = 5.0 9 | const CONTROL_MARGIN = 20.0 10 | const OUTLINE_WIDTH = 3.0 11 | const MINIMUM_SNAP_DISTANCE = 80.0 12 | const MINIMUM_DRAG_THRESHOLD = 25 13 | const ROUND_RESOLUTION = 10 14 | 15 | const FOCUS_BORDER_COLOR = Color(225, 242, 0) 16 | const DRAG_REMOVE_COLOR = Color(1, 1, 1, 0.5) 17 | const DRAG_PREVIEW_COLOR = Color(225, 242, 0, 0.3) 18 | 19 | ## Properties for builtin categories. Order starts at 10 for the first 20 | ## category and then are separated by 10 to allow custom categories to 21 | ## be easily placed between builtin categories. 22 | const BUILTIN_CATEGORIES_PROPS: Dictionary = { 23 | "Lifecycle": 24 | { 25 | "color": Color("ff001aff"), 26 | "order": 10, 27 | }, 28 | "Lifecycle | Game": 29 | { 30 | "color": Color("ff001aff"), 31 | "order": 12, 32 | }, 33 | "Lifecycle | Spawn": 34 | { 35 | "color": Color("ff001aff"), 36 | "order": 15, 37 | }, 38 | "Transform | Position": 39 | { 40 | "color": Color("773344ff"), 41 | "order": 20, 42 | }, 43 | "Transform | Rotation": 44 | { 45 | "color": Color("773344ff"), 46 | "order": 30, 47 | }, 48 | "Transform | Scale": 49 | { 50 | "color": Color("773344ff"), 51 | "order": 40, 52 | }, 53 | "Graphics | Modulate": 54 | { 55 | "color": Color("a37276ff"), 56 | "order": 50, 57 | }, 58 | "Graphics | Visibility": 59 | { 60 | "color": Color("a37276ff"), 61 | "order": 60, 62 | }, 63 | "Graphics | Viewport": 64 | { 65 | "color": Color("a37276ff"), 66 | "order": 61, 67 | }, 68 | "Graphics | Animation": 69 | { 70 | "color": Color("a37276ff"), 71 | "order": 62, 72 | }, 73 | "UI": 74 | { 75 | "color": Color("03aa74"), 76 | "order": 65, 77 | }, 78 | "Sounds": 79 | { 80 | "color": Color("7606B8"), 81 | "order": 70, 82 | }, 83 | "Physics | Mass": 84 | { 85 | "color": Color("264653ff"), 86 | "order": 80, 87 | }, 88 | "Physics | Velocity": 89 | { 90 | "color": Color("264653ff"), 91 | "order": 90, 92 | }, 93 | "Input": 94 | { 95 | "color": Color("e76f51ff"), 96 | "order": 100, 97 | }, 98 | "Communication | Methods": 99 | { 100 | "color": Color("2a9d8fff"), 101 | "order": 110, 102 | }, 103 | "Communication | Nodes": 104 | { 105 | "color": Color("2a9d8fff"), 106 | "order": 115, 107 | }, 108 | "Communication | Groups": 109 | { 110 | "color": Color("2a9d8fff"), 111 | "order": 120, 112 | }, 113 | "Info | Score": 114 | { 115 | "color": Color("FF5000"), 116 | "order": 130, 117 | }, 118 | "Loops": 119 | { 120 | "color": Color("e9c46aff"), 121 | "order": 140, 122 | }, 123 | "Logic | Conditionals": 124 | { 125 | "color": Color("e9c46aff"), 126 | "order": 150, 127 | }, 128 | "Logic | Comparison": 129 | { 130 | "color": Color("e9c46aff"), 131 | "order": 160, 132 | }, 133 | "Logic | Boolean": 134 | { 135 | "color": Color("e9c46aff"), 136 | "order": 170, 137 | }, 138 | "Variables": 139 | { 140 | "color": Color("e76f51ff"), 141 | "order": 180, 142 | }, 143 | "Math": 144 | { 145 | "color": Color("f4a261ff"), 146 | "order": 190, 147 | }, 148 | "Log": 149 | { 150 | "color": Color("002050"), 151 | "order": 200, 152 | }, 153 | "Node | Properties": 154 | { 155 | "color": Color("002050"), 156 | "order": 210, 157 | } 158 | } -------------------------------------------------------------------------------- /ui/constants.gd.uid: -------------------------------------------------------------------------------- 1 | uid://d0e278swld54t 2 | -------------------------------------------------------------------------------- /ui/main_panel.gd.uid: -------------------------------------------------------------------------------- 1 | uid://b4f4roenpifgk 2 | -------------------------------------------------------------------------------- /ui/picker/categories/block_category.gd: -------------------------------------------------------------------------------- 1 | extends RefCounted 2 | 3 | var name: String 4 | var color: Color 5 | var order: int 6 | 7 | 8 | func _init(p_name: String = "", p_color: Color = Color.WHITE, p_order: int = 0): 9 | name = p_name 10 | color = p_color 11 | order = p_order 12 | 13 | 14 | ## Compare block categories for sorting. Compare by order then name. 15 | static func sort_by_order(a, b) -> bool: 16 | if a.order != b.order: 17 | return a.order < b.order 18 | return a.name.naturalcasecmp_to(b.name) < 0 19 | -------------------------------------------------------------------------------- /ui/picker/categories/block_category.gd.uid: -------------------------------------------------------------------------------- 1 | uid://crxpqbcd55h5a 2 | -------------------------------------------------------------------------------- /ui/picker/categories/block_category_button.gd: -------------------------------------------------------------------------------- 1 | @tool 2 | extends MarginContainer 3 | 4 | const BlockCategory = preload("res://addons/reblocks/ui/picker/categories/block_category.gd") 5 | const Util = preload("res://addons/reblocks/ui/util.gd") 6 | 7 | signal selected 8 | 9 | var category: BlockCategory 10 | 11 | @onready var _panel := %Panel 12 | @onready var _button := %Button 13 | 14 | 15 | func _ready(): 16 | if not category: 17 | category = BlockCategory.new("Example", Color.RED) 18 | var category_title = category.name.get_slice(" |", 0) 19 | 20 | if not self.is_part_of_edited_scene(): 21 | var texture = load("res://addons/reblocks/ui/picker/categories/icons/" + category_title.to_lower() + ".svg") 22 | _button.icon = texture 23 | _panel.modulate = category.color 24 | 25 | _button.tooltip_text = tr(category_title) 26 | 27 | 28 | func _on_button_pressed(): 29 | selected.emit() 30 | -------------------------------------------------------------------------------- /ui/picker/categories/block_category_button.gd.uid: -------------------------------------------------------------------------------- 1 | uid://y2srodxufo03 2 | -------------------------------------------------------------------------------- /ui/picker/categories/block_category_button.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=8 format=3 uid="uid://bdtetj0gs45hv"] 2 | 3 | [ext_resource type="Script" path="res://addons/reblocks/ui/picker/categories/block_category_button.gd" id="1_pxxnl"] 4 | [ext_resource type="Texture2D" uid="uid://g10ct6m5goi6" path="res://addons/reblocks/ui/picker/categories/icons/file_broken.svg" id="2_0c1ke"] 5 | 6 | [sub_resource type="StyleBoxFlat" id="StyleBoxFlat_w0e7p"] 7 | bg_color = Color(1, 1, 1, 1) 8 | corner_radius_top_left = 5 9 | corner_radius_top_right = 5 10 | corner_radius_bottom_right = 5 11 | corner_radius_bottom_left = 5 12 | 13 | [sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_dgecf"] 14 | 15 | [sub_resource type="StyleBoxFlat" id="StyleBoxFlat_fyk0j"] 16 | bg_color = Color(1, 1, 1, 0.196078) 17 | corner_radius_top_left = 5 18 | corner_radius_top_right = 5 19 | corner_radius_bottom_right = 5 20 | corner_radius_bottom_left = 5 21 | 22 | [sub_resource type="StyleBoxFlat" id="StyleBoxFlat_ha83k"] 23 | bg_color = Color(1, 1, 1, 0.392157) 24 | corner_radius_top_left = 5 25 | corner_radius_top_right = 5 26 | corner_radius_bottom_right = 5 27 | corner_radius_bottom_left = 5 28 | 29 | [sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_ousiv"] 30 | 31 | [node name="BlockCategoryButton" type="MarginContainer"] 32 | script = ExtResource("1_pxxnl") 33 | 34 | [node name="Panel" type="Panel" parent="."] 35 | unique_name_in_owner = true 36 | layout_mode = 2 37 | theme_override_styles/panel = SubResource("StyleBoxFlat_w0e7p") 38 | 39 | [node name="Button" type="Button" parent="."] 40 | unique_name_in_owner = true 41 | layout_mode = 2 42 | size_flags_horizontal = 4 43 | tooltip_text = "Example" 44 | mouse_default_cursor_shape = 2 45 | theme_override_styles/focus = SubResource("StyleBoxEmpty_dgecf") 46 | theme_override_styles/hover = SubResource("StyleBoxFlat_fyk0j") 47 | theme_override_styles/pressed = SubResource("StyleBoxFlat_ha83k") 48 | theme_override_styles/normal = SubResource("StyleBoxEmpty_ousiv") 49 | icon = ExtResource("2_0c1ke") 50 | icon_alignment = 1 51 | 52 | [connection signal="pressed" from="Button" to="." method="_on_button_pressed"] 53 | -------------------------------------------------------------------------------- /ui/picker/categories/block_category_display.gd: -------------------------------------------------------------------------------- 1 | @tool 2 | extends MarginContainer 3 | 4 | signal block_picked(block: Block, offset: Vector2) 5 | 6 | const BlockCategory = preload("res://addons/reblocks/ui/picker/categories/block_category.gd") 7 | const BlockDefinition = preload("res://addons/reblocks/code_generation/block_definition.gd") 8 | const Util = preload("res://addons/reblocks/ui/util.gd") 9 | 10 | @export var title: String: 11 | set = _set_title 12 | @export var block_definitions: Array[BlockDefinition]: 13 | set = _set_block_definitions 14 | 15 | @onready var _context := BlockEditorContext.get_default() 16 | 17 | @onready var _label := %Label 18 | @onready var _blocks_container := %BlocksContainer 19 | 20 | var _blocks: Dictionary # String, Block 21 | 22 | 23 | func _ready(): 24 | _update_label() 25 | _update_blocks() 26 | 27 | 28 | func _set_title(value): 29 | title = value 30 | _update_label() 31 | 32 | 33 | func _set_block_definitions(value): 34 | block_definitions = value 35 | _update_blocks() 36 | 37 | 38 | func _update_label(): 39 | if not _label: 40 | return 41 | 42 | _label.text = tr(title) 43 | 44 | 45 | func _update_blocks(): 46 | if not _blocks_container: 47 | return 48 | 49 | if not _context: 50 | return 51 | 52 | for block in _blocks.values(): 53 | block.hide() 54 | 55 | for block_definition in block_definitions: 56 | var block = _get_or_create_block(block_definition) 57 | _blocks_container.move_child(block, -1) 58 | block.show() 59 | 60 | _blocks_container.visible = not block_definitions.is_empty() 61 | 62 | 63 | func _get_or_create_block(block_definition: BlockDefinition) -> Block: 64 | var block: Block = _blocks.get(block_definition.name) 65 | 66 | if block == null: 67 | block = _context.block_script.instantiate_block(block_definition) 68 | block.can_delete = false 69 | block.editable = false 70 | block.drag_started.connect(func(block: Block, offset: Vector2): block_picked.emit(block, offset)) 71 | _blocks_container.add_child(block) 72 | _blocks[block_definition.name] = block 73 | else: 74 | # If the block is being reused, make sure the context corresponds to 75 | # the current BlockCode node. 76 | block.refresh_context() 77 | 78 | return block 79 | -------------------------------------------------------------------------------- /ui/picker/categories/block_category_display.gd.uid: -------------------------------------------------------------------------------- 1 | uid://bwwcj18bxjudi 2 | -------------------------------------------------------------------------------- /ui/picker/categories/block_category_display.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=2 format=3 uid="uid://duhpwtfo3k0sk"] 2 | 3 | [ext_resource type="Script" path="res://addons/reblocks/ui/picker/categories/block_category_display.gd" id="1_wkdht"] 4 | 5 | [node name="BlockCategoryDisplay" type="MarginContainer"] 6 | anchors_preset = 15 7 | anchor_right = 1.0 8 | anchor_bottom = 1.0 9 | offset_right = -918.0 10 | offset_bottom = -246.0 11 | grow_horizontal = 2 12 | grow_vertical = 2 13 | theme_override_constants/margin_left = 4 14 | theme_override_constants/margin_bottom = 40 15 | script = ExtResource("1_wkdht") 16 | 17 | [node name="VBoxContainer" type="VBoxContainer" parent="."] 18 | layout_mode = 2 19 | 20 | [node name="MarginContainer" type="MarginContainer" parent="VBoxContainer"] 21 | layout_mode = 2 22 | theme_override_constants/margin_bottom = 4 23 | 24 | [node name="Label" type="Label" parent="VBoxContainer/MarginContainer"] 25 | unique_name_in_owner = true 26 | layout_mode = 2 27 | theme_override_font_sizes/font_size = 18 28 | 29 | [node name="BlocksContainer" type="VBoxContainer" parent="VBoxContainer"] 30 | unique_name_in_owner = true 31 | layout_mode = 2 32 | theme_override_constants/separation = 14 33 | -------------------------------------------------------------------------------- /ui/picker/categories/category_factory.gd: -------------------------------------------------------------------------------- 1 | class_name CategoryFactory 2 | extends Object 3 | 4 | const BlockCategory = preload("res://addons/reblocks/ui/picker/categories/block_category.gd") 5 | const Constants = preload("res://addons/reblocks/ui/constants.gd") 6 | 7 | 8 | ## Returns a list of BlockCategory instances for all block categories. 9 | static func get_all_categories(custom_categories: Array[BlockCategory] = []) -> Array[BlockCategory]: 10 | var result: Array[BlockCategory] 11 | 12 | for category_name in Constants.BUILTIN_CATEGORIES_PROPS: 13 | var props: Dictionary = Constants.BUILTIN_CATEGORIES_PROPS.get(category_name, {}) 14 | var color: Color = props.get("color", Color.SLATE_GRAY) 15 | var order: int = props.get("order", 0) 16 | result.append(BlockCategory.new(category_name, color, order)) 17 | 18 | # TODO: Should we deduplicate custom_categories here? 19 | result.append_array(custom_categories) 20 | 21 | return result 22 | -------------------------------------------------------------------------------- /ui/picker/categories/category_factory.gd.uid: -------------------------------------------------------------------------------- 1 | uid://bcdwygabsc65o 2 | -------------------------------------------------------------------------------- /ui/picker/categories/icons/communication.svg: -------------------------------------------------------------------------------- 1 | 2 | 10 | 12 | 14 | 18 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /ui/picker/categories/icons/communication.svg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://d0agg8648xht3" 6 | path="res://.godot/imported/communication.svg-947c90ab31319a267db7fe17ba69d837.ctex" 7 | metadata={ 8 | "has_editor_variant": true, 9 | "vram_texture": false 10 | } 11 | 12 | [deps] 13 | 14 | source_file="res://addons/reblocks/ui/picker/categories/icons/communication.svg" 15 | dest_files=["res://.godot/imported/communication.svg-947c90ab31319a267db7fe17ba69d837.ctex"] 16 | 17 | [params] 18 | 19 | compress/mode=0 20 | compress/high_quality=false 21 | compress/lossy_quality=0.7 22 | compress/hdr_compression=1 23 | compress/normal_map=0 24 | compress/channel_pack=0 25 | mipmaps/generate=false 26 | mipmaps/limit=-1 27 | roughness/mode=0 28 | roughness/src_normal="" 29 | process/fix_alpha_border=true 30 | process/premult_alpha=false 31 | process/normal_map_invert_y=false 32 | process/hdr_as_srgb=false 33 | process/hdr_clamp_exposure=false 34 | process/size_limit=0 35 | detect_3d/compress_to=1 36 | svg/scale=1.0 37 | editor/scale_with_editor_scale=true 38 | editor/convert_colors_with_editor_theme=false 39 | -------------------------------------------------------------------------------- /ui/picker/categories/icons/file_broken.svg: -------------------------------------------------------------------------------- 1 | 2 | 10 | 12 | 14 | 18 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /ui/picker/categories/icons/file_broken.svg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://g10ct6m5goi6" 6 | path="res://.godot/imported/file_broken.svg-4eaab408643b07ce95d90d59c6c11ee5.ctex" 7 | metadata={ 8 | "has_editor_variant": true, 9 | "vram_texture": false 10 | } 11 | 12 | [deps] 13 | 14 | source_file="res://addons/reblocks/ui/picker/categories/icons/file_broken.svg" 15 | dest_files=["res://.godot/imported/file_broken.svg-4eaab408643b07ce95d90d59c6c11ee5.ctex"] 16 | 17 | [params] 18 | 19 | compress/mode=0 20 | compress/high_quality=false 21 | compress/lossy_quality=0.7 22 | compress/hdr_compression=1 23 | compress/normal_map=0 24 | compress/channel_pack=0 25 | mipmaps/generate=false 26 | mipmaps/limit=-1 27 | roughness/mode=0 28 | roughness/src_normal="" 29 | process/fix_alpha_border=true 30 | process/premult_alpha=false 31 | process/normal_map_invert_y=false 32 | process/hdr_as_srgb=false 33 | process/hdr_clamp_exposure=false 34 | process/size_limit=0 35 | detect_3d/compress_to=1 36 | svg/scale=1.0 37 | editor/scale_with_editor_scale=true 38 | editor/convert_colors_with_editor_theme=false 39 | -------------------------------------------------------------------------------- /ui/picker/categories/icons/graphics.svg: -------------------------------------------------------------------------------- 1 | 2 | 10 | 12 | 14 | 18 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /ui/picker/categories/icons/graphics.svg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://bfvq21qp2l363" 6 | path="res://.godot/imported/graphics.svg-a28b663c4f820bd8c41e895b8bfaf874.ctex" 7 | metadata={ 8 | "has_editor_variant": true, 9 | "vram_texture": false 10 | } 11 | 12 | [deps] 13 | 14 | source_file="res://addons/reblocks/ui/picker/categories/icons/graphics.svg" 15 | dest_files=["res://.godot/imported/graphics.svg-a28b663c4f820bd8c41e895b8bfaf874.ctex"] 16 | 17 | [params] 18 | 19 | compress/mode=0 20 | compress/high_quality=false 21 | compress/lossy_quality=0.7 22 | compress/hdr_compression=1 23 | compress/normal_map=0 24 | compress/channel_pack=0 25 | mipmaps/generate=false 26 | mipmaps/limit=-1 27 | roughness/mode=0 28 | roughness/src_normal="" 29 | process/fix_alpha_border=true 30 | process/premult_alpha=false 31 | process/normal_map_invert_y=false 32 | process/hdr_as_srgb=false 33 | process/hdr_clamp_exposure=false 34 | process/size_limit=0 35 | detect_3d/compress_to=1 36 | svg/scale=1.0 37 | editor/scale_with_editor_scale=true 38 | editor/convert_colors_with_editor_theme=false 39 | -------------------------------------------------------------------------------- /ui/picker/categories/icons/info.svg: -------------------------------------------------------------------------------- 1 | 2 | 10 | 12 | 14 | 18 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /ui/picker/categories/icons/info.svg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://bw76iiilnqfsn" 6 | path="res://.godot/imported/info.svg-9f3e9c8144e7ee8ec6ef26d98cf6f8af.ctex" 7 | metadata={ 8 | "has_editor_variant": true, 9 | "vram_texture": false 10 | } 11 | 12 | [deps] 13 | 14 | source_file="res://addons/reblocks/ui/picker/categories/icons/info.svg" 15 | dest_files=["res://.godot/imported/info.svg-9f3e9c8144e7ee8ec6ef26d98cf6f8af.ctex"] 16 | 17 | [params] 18 | 19 | compress/mode=0 20 | compress/high_quality=false 21 | compress/lossy_quality=0.7 22 | compress/hdr_compression=1 23 | compress/normal_map=0 24 | compress/channel_pack=0 25 | mipmaps/generate=false 26 | mipmaps/limit=-1 27 | roughness/mode=0 28 | roughness/src_normal="" 29 | process/fix_alpha_border=true 30 | process/premult_alpha=false 31 | process/normal_map_invert_y=false 32 | process/hdr_as_srgb=false 33 | process/hdr_clamp_exposure=false 34 | process/size_limit=0 35 | detect_3d/compress_to=1 36 | svg/scale=1.0 37 | editor/scale_with_editor_scale=true 38 | editor/convert_colors_with_editor_theme=false 39 | -------------------------------------------------------------------------------- /ui/picker/categories/icons/input.svg: -------------------------------------------------------------------------------- 1 | 2 | 10 | 12 | 14 | 18 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /ui/picker/categories/icons/input.svg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://bqlh8yalvn3qt" 6 | path="res://.godot/imported/input.svg-8ff23e911a11ca01b6173c036b07dd03.ctex" 7 | metadata={ 8 | "has_editor_variant": true, 9 | "vram_texture": false 10 | } 11 | 12 | [deps] 13 | 14 | source_file="res://addons/reblocks/ui/picker/categories/icons/input.svg" 15 | dest_files=["res://.godot/imported/input.svg-8ff23e911a11ca01b6173c036b07dd03.ctex"] 16 | 17 | [params] 18 | 19 | compress/mode=0 20 | compress/high_quality=false 21 | compress/lossy_quality=0.7 22 | compress/hdr_compression=1 23 | compress/normal_map=0 24 | compress/channel_pack=0 25 | mipmaps/generate=false 26 | mipmaps/limit=-1 27 | roughness/mode=0 28 | roughness/src_normal="" 29 | process/fix_alpha_border=true 30 | process/premult_alpha=false 31 | process/normal_map_invert_y=false 32 | process/hdr_as_srgb=false 33 | process/hdr_clamp_exposure=false 34 | process/size_limit=0 35 | detect_3d/compress_to=1 36 | svg/scale=1.0 37 | editor/scale_with_editor_scale=true 38 | editor/convert_colors_with_editor_theme=false 39 | -------------------------------------------------------------------------------- /ui/picker/categories/icons/lifecycle.svg: -------------------------------------------------------------------------------- 1 | 2 | 10 | 12 | 14 | 18 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /ui/picker/categories/icons/lifecycle.svg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://dtx1jvrk0xo6u" 6 | path="res://.godot/imported/lifecycle.svg-a03e82f944312da96cc3afcd5fe9b410.ctex" 7 | metadata={ 8 | "has_editor_variant": true, 9 | "vram_texture": false 10 | } 11 | 12 | [deps] 13 | 14 | source_file="res://addons/reblocks/ui/picker/categories/icons/lifecycle.svg" 15 | dest_files=["res://.godot/imported/lifecycle.svg-a03e82f944312da96cc3afcd5fe9b410.ctex"] 16 | 17 | [params] 18 | 19 | compress/mode=0 20 | compress/high_quality=false 21 | compress/lossy_quality=0.7 22 | compress/hdr_compression=1 23 | compress/normal_map=0 24 | compress/channel_pack=0 25 | mipmaps/generate=false 26 | mipmaps/limit=-1 27 | roughness/mode=0 28 | roughness/src_normal="" 29 | process/fix_alpha_border=true 30 | process/premult_alpha=false 31 | process/normal_map_invert_y=false 32 | process/hdr_as_srgb=false 33 | process/hdr_clamp_exposure=false 34 | process/size_limit=0 35 | detect_3d/compress_to=1 36 | svg/scale=1.0 37 | editor/scale_with_editor_scale=true 38 | editor/convert_colors_with_editor_theme=false 39 | -------------------------------------------------------------------------------- /ui/picker/categories/icons/log.svg: -------------------------------------------------------------------------------- 1 | 2 | 10 | 12 | 14 | 18 | 22 | 28 | 34 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /ui/picker/categories/icons/log.svg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://deb4kkgrd4ova" 6 | path="res://.godot/imported/log.svg-327c08a400b93a74d2b8236ea0898062.ctex" 7 | metadata={ 8 | "has_editor_variant": true, 9 | "vram_texture": false 10 | } 11 | 12 | [deps] 13 | 14 | source_file="res://addons/reblocks/ui/picker/categories/icons/log.svg" 15 | dest_files=["res://.godot/imported/log.svg-327c08a400b93a74d2b8236ea0898062.ctex"] 16 | 17 | [params] 18 | 19 | compress/mode=0 20 | compress/high_quality=false 21 | compress/lossy_quality=0.7 22 | compress/hdr_compression=1 23 | compress/normal_map=0 24 | compress/channel_pack=0 25 | mipmaps/generate=false 26 | mipmaps/limit=-1 27 | roughness/mode=0 28 | roughness/src_normal="" 29 | process/fix_alpha_border=true 30 | process/premult_alpha=false 31 | process/normal_map_invert_y=false 32 | process/hdr_as_srgb=false 33 | process/hdr_clamp_exposure=false 34 | process/size_limit=0 35 | detect_3d/compress_to=1 36 | svg/scale=1.0 37 | editor/scale_with_editor_scale=true 38 | editor/convert_colors_with_editor_theme=false 39 | -------------------------------------------------------------------------------- /ui/picker/categories/icons/logic.svg: -------------------------------------------------------------------------------- 1 | 2 | 10 | 12 | 14 | 18 | 22 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /ui/picker/categories/icons/logic.svg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://xs78uxfonid0" 6 | path="res://.godot/imported/logic.svg-944177754b8f54bab7f488e8345ce91f.ctex" 7 | metadata={ 8 | "has_editor_variant": true, 9 | "vram_texture": false 10 | } 11 | 12 | [deps] 13 | 14 | source_file="res://addons/reblocks/ui/picker/categories/icons/logic.svg" 15 | dest_files=["res://.godot/imported/logic.svg-944177754b8f54bab7f488e8345ce91f.ctex"] 16 | 17 | [params] 18 | 19 | compress/mode=0 20 | compress/high_quality=false 21 | compress/lossy_quality=0.7 22 | compress/hdr_compression=1 23 | compress/normal_map=0 24 | compress/channel_pack=0 25 | mipmaps/generate=false 26 | mipmaps/limit=-1 27 | roughness/mode=0 28 | roughness/src_normal="" 29 | process/fix_alpha_border=true 30 | process/premult_alpha=false 31 | process/normal_map_invert_y=false 32 | process/hdr_as_srgb=false 33 | process/hdr_clamp_exposure=false 34 | process/size_limit=0 35 | detect_3d/compress_to=1 36 | svg/scale=1.0 37 | editor/scale_with_editor_scale=true 38 | editor/convert_colors_with_editor_theme=false 39 | -------------------------------------------------------------------------------- /ui/picker/categories/icons/loops.svg: -------------------------------------------------------------------------------- 1 | 2 | 10 | 12 | 14 | 18 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /ui/picker/categories/icons/loops.svg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://xfxkkou3p0re" 6 | path="res://.godot/imported/loops.svg-316da2da589f07c3d0f5428710593245.ctex" 7 | metadata={ 8 | "has_editor_variant": true, 9 | "vram_texture": false 10 | } 11 | 12 | [deps] 13 | 14 | source_file="res://addons/reblocks/ui/picker/categories/icons/loops.svg" 15 | dest_files=["res://.godot/imported/loops.svg-316da2da589f07c3d0f5428710593245.ctex"] 16 | 17 | [params] 18 | 19 | compress/mode=0 20 | compress/high_quality=false 21 | compress/lossy_quality=0.7 22 | compress/hdr_compression=1 23 | compress/normal_map=0 24 | compress/channel_pack=0 25 | mipmaps/generate=false 26 | mipmaps/limit=-1 27 | roughness/mode=0 28 | roughness/src_normal="" 29 | process/fix_alpha_border=true 30 | process/premult_alpha=false 31 | process/normal_map_invert_y=false 32 | process/hdr_as_srgb=false 33 | process/hdr_clamp_exposure=false 34 | process/size_limit=0 35 | detect_3d/compress_to=1 36 | svg/scale=1.0 37 | editor/scale_with_editor_scale=true 38 | editor/convert_colors_with_editor_theme=false 39 | -------------------------------------------------------------------------------- /ui/picker/categories/icons/math.svg: -------------------------------------------------------------------------------- 1 | 2 | 10 | 12 | 14 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /ui/picker/categories/icons/math.svg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://cjwntrfvngo35" 6 | path="res://.godot/imported/math.svg-c778437f6fc860eedd4f084b9d29355a.ctex" 7 | metadata={ 8 | "has_editor_variant": true, 9 | "vram_texture": false 10 | } 11 | 12 | [deps] 13 | 14 | source_file="res://addons/reblocks/ui/picker/categories/icons/math.svg" 15 | dest_files=["res://.godot/imported/math.svg-c778437f6fc860eedd4f084b9d29355a.ctex"] 16 | 17 | [params] 18 | 19 | compress/mode=0 20 | compress/high_quality=false 21 | compress/lossy_quality=0.7 22 | compress/hdr_compression=1 23 | compress/normal_map=0 24 | compress/channel_pack=0 25 | mipmaps/generate=false 26 | mipmaps/limit=-1 27 | roughness/mode=0 28 | roughness/src_normal="" 29 | process/fix_alpha_border=true 30 | process/premult_alpha=false 31 | process/normal_map_invert_y=false 32 | process/hdr_as_srgb=false 33 | process/hdr_clamp_exposure=false 34 | process/size_limit=0 35 | detect_3d/compress_to=1 36 | svg/scale=1.0 37 | editor/scale_with_editor_scale=true 38 | editor/convert_colors_with_editor_theme=false 39 | -------------------------------------------------------------------------------- /ui/picker/categories/icons/physics.svg: -------------------------------------------------------------------------------- 1 | 2 | 10 | 12 | 14 | 21 | 28 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /ui/picker/categories/icons/physics.svg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://8isr3pc5m4mi" 6 | path="res://.godot/imported/physics.svg-09ffe308a70b6e14c8f03dc392898be8.ctex" 7 | metadata={ 8 | "has_editor_variant": true, 9 | "vram_texture": false 10 | } 11 | 12 | [deps] 13 | 14 | source_file="res://addons/reblocks/ui/picker/categories/icons/physics.svg" 15 | dest_files=["res://.godot/imported/physics.svg-09ffe308a70b6e14c8f03dc392898be8.ctex"] 16 | 17 | [params] 18 | 19 | compress/mode=0 20 | compress/high_quality=false 21 | compress/lossy_quality=0.7 22 | compress/hdr_compression=1 23 | compress/normal_map=0 24 | compress/channel_pack=0 25 | mipmaps/generate=false 26 | mipmaps/limit=-1 27 | roughness/mode=0 28 | roughness/src_normal="" 29 | process/fix_alpha_border=true 30 | process/premult_alpha=false 31 | process/normal_map_invert_y=false 32 | process/hdr_as_srgb=false 33 | process/hdr_clamp_exposure=false 34 | process/size_limit=0 35 | detect_3d/compress_to=1 36 | svg/scale=1.0 37 | editor/scale_with_editor_scale=true 38 | editor/convert_colors_with_editor_theme=false 39 | -------------------------------------------------------------------------------- /ui/picker/categories/icons/sounds.svg: -------------------------------------------------------------------------------- 1 | 2 | 10 | 12 | 14 | 18 | 22 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /ui/picker/categories/icons/sounds.svg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://81pkn6w7wkba" 6 | path="res://.godot/imported/sounds.svg-355a120001ae628f9afecc29c867f10a.ctex" 7 | metadata={ 8 | "has_editor_variant": true, 9 | "vram_texture": false 10 | } 11 | 12 | [deps] 13 | 14 | source_file="res://addons/reblocks/ui/picker/categories/icons/sounds.svg" 15 | dest_files=["res://.godot/imported/sounds.svg-355a120001ae628f9afecc29c867f10a.ctex"] 16 | 17 | [params] 18 | 19 | compress/mode=0 20 | compress/high_quality=false 21 | compress/lossy_quality=0.7 22 | compress/hdr_compression=1 23 | compress/normal_map=0 24 | compress/channel_pack=0 25 | mipmaps/generate=false 26 | mipmaps/limit=-1 27 | roughness/mode=0 28 | roughness/src_normal="" 29 | process/fix_alpha_border=true 30 | process/premult_alpha=false 31 | process/normal_map_invert_y=false 32 | process/hdr_as_srgb=false 33 | process/hdr_clamp_exposure=false 34 | process/size_limit=0 35 | detect_3d/compress_to=1 36 | svg/scale=1.0 37 | editor/scale_with_editor_scale=true 38 | editor/convert_colors_with_editor_theme=false 39 | -------------------------------------------------------------------------------- /ui/picker/categories/icons/transform.svg: -------------------------------------------------------------------------------- 1 | 2 | 10 | 12 | 14 | 21 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /ui/picker/categories/icons/transform.svg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://rkbwr5ea2npu" 6 | path="res://.godot/imported/transform.svg-baaec2023e58f087ed2c55b9e83048bf.ctex" 7 | metadata={ 8 | "has_editor_variant": true, 9 | "vram_texture": false 10 | } 11 | 12 | [deps] 13 | 14 | source_file="res://addons/reblocks/ui/picker/categories/icons/transform.svg" 15 | dest_files=["res://.godot/imported/transform.svg-baaec2023e58f087ed2c55b9e83048bf.ctex"] 16 | 17 | [params] 18 | 19 | compress/mode=0 20 | compress/high_quality=false 21 | compress/lossy_quality=0.7 22 | compress/hdr_compression=1 23 | compress/normal_map=0 24 | compress/channel_pack=0 25 | mipmaps/generate=false 26 | mipmaps/limit=-1 27 | roughness/mode=0 28 | roughness/src_normal="" 29 | process/fix_alpha_border=true 30 | process/premult_alpha=false 31 | process/normal_map_invert_y=false 32 | process/hdr_as_srgb=false 33 | process/hdr_clamp_exposure=false 34 | process/size_limit=0 35 | detect_3d/compress_to=1 36 | svg/scale=1.0 37 | editor/scale_with_editor_scale=true 38 | editor/convert_colors_with_editor_theme=false 39 | -------------------------------------------------------------------------------- /ui/picker/categories/icons/ui.svg: -------------------------------------------------------------------------------- 1 | 2 | 10 | 12 | 14 | 21 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /ui/picker/categories/icons/ui.svg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://cpdpycplq4kmp" 6 | path="res://.godot/imported/ui.svg-166cb4713f750fb9cec115a1d0a692ca.ctex" 7 | metadata={ 8 | "has_editor_variant": true, 9 | "vram_texture": false 10 | } 11 | 12 | [deps] 13 | 14 | source_file="res://addons/reblocks/ui/picker/categories/icons/ui.svg" 15 | dest_files=["res://.godot/imported/ui.svg-166cb4713f750fb9cec115a1d0a692ca.ctex"] 16 | 17 | [params] 18 | 19 | compress/mode=0 20 | compress/high_quality=false 21 | compress/lossy_quality=0.7 22 | compress/hdr_compression=1 23 | compress/normal_map=0 24 | compress/channel_pack=0 25 | mipmaps/generate=false 26 | mipmaps/limit=-1 27 | roughness/mode=0 28 | roughness/src_normal="" 29 | process/fix_alpha_border=true 30 | process/premult_alpha=false 31 | process/normal_map_invert_y=false 32 | process/hdr_as_srgb=false 33 | process/hdr_clamp_exposure=false 34 | process/size_limit=0 35 | detect_3d/compress_to=1 36 | svg/scale=1.0 37 | editor/scale_with_editor_scale=true 38 | editor/convert_colors_with_editor_theme=false 39 | -------------------------------------------------------------------------------- /ui/picker/categories/icons/variables.svg: -------------------------------------------------------------------------------- 1 | 2 | 10 | 12 | 14 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /ui/picker/categories/icons/variables.svg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://c0nt5beum2fx" 6 | path="res://.godot/imported/variables.svg-3dba899b1f7db7e9d53b46e5901f191a.ctex" 7 | metadata={ 8 | "has_editor_variant": true, 9 | "vram_texture": false 10 | } 11 | 12 | [deps] 13 | 14 | source_file="res://addons/reblocks/ui/picker/categories/icons/variables.svg" 15 | dest_files=["res://.godot/imported/variables.svg-3dba899b1f7db7e9d53b46e5901f191a.ctex"] 16 | 17 | [params] 18 | 19 | compress/mode=0 20 | compress/high_quality=false 21 | compress/lossy_quality=0.7 22 | compress/hdr_compression=1 23 | compress/normal_map=0 24 | compress/channel_pack=0 25 | mipmaps/generate=false 26 | mipmaps/limit=-1 27 | roughness/mode=0 28 | roughness/src_normal="" 29 | process/fix_alpha_border=true 30 | process/premult_alpha=false 31 | process/normal_map_invert_y=false 32 | process/hdr_as_srgb=false 33 | process/hdr_clamp_exposure=false 34 | process/size_limit=0 35 | detect_3d/compress_to=1 36 | svg/scale=1.0 37 | editor/scale_with_editor_scale=true 38 | editor/convert_colors_with_editor_theme=false 39 | -------------------------------------------------------------------------------- /ui/picker/categories/variable_category/create_variable_button.gd: -------------------------------------------------------------------------------- 1 | @tool 2 | extends MarginContainer 3 | 4 | signal create_variable(var_name: String, var_type: String) 5 | 6 | @onready var _create_variable_dialog := %CreateVariableDialog 7 | @onready var _create_button := %CreateButton 8 | @onready var _create_variable_icon = _create_button.get_theme_icon("Add", "EditorIcons") 9 | 10 | 11 | func _ready() -> void: 12 | _create_button.icon = _create_variable_icon 13 | 14 | 15 | func _on_create_button_pressed(): 16 | _create_variable_dialog.popup() 17 | 18 | 19 | func _on_create_variable_dialog_create_variable(var_name, var_type): 20 | create_variable.emit(var_name, var_type) 21 | -------------------------------------------------------------------------------- /ui/picker/categories/variable_category/create_variable_button.gd.uid: -------------------------------------------------------------------------------- 1 | uid://dkhckmafib5pb 2 | -------------------------------------------------------------------------------- /ui/picker/categories/variable_category/create_variable_button.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=3 format=3 uid="uid://t0eoc4ekvjr1"] 2 | 3 | [ext_resource type="Script" path="res://addons/reblocks/ui/picker/categories/variable_category/create_variable_button.gd" id="1_cw6c3"] 4 | [ext_resource type="PackedScene" uid="uid://dbrm7wwkao0c0" path="res://addons/reblocks/ui/picker/categories/variable_category/create_variable_dialog.tscn" id="2_udpg5"] 5 | 6 | [node name="CreateVariableButton" type="MarginContainer"] 7 | size_flags_horizontal = 0 8 | theme_override_constants/margin_bottom = 12 9 | script = ExtResource("1_cw6c3") 10 | 11 | [node name="CreateButton" type="Button" parent="."] 12 | unique_name_in_owner = true 13 | layout_mode = 2 14 | theme_type_variation = &"InspectorActionButton" 15 | text = "Create New Variable" 16 | 17 | [node name="CreateVariableDialog" parent="." instance=ExtResource("2_udpg5")] 18 | unique_name_in_owner = true 19 | visible = false 20 | 21 | [connection signal="pressed" from="CreateButton" to="." method="_on_create_button_pressed"] 22 | [connection signal="create_variable" from="CreateVariableDialog" to="." method="_on_create_variable_dialog_create_variable"] 23 | -------------------------------------------------------------------------------- /ui/picker/categories/variable_category/create_variable_dialog.gd: -------------------------------------------------------------------------------- 1 | @tool 2 | extends ConfirmationDialog 3 | 4 | const BlockCodePlugin = preload("res://addons/reblocks/block_code_plugin.gd") 5 | 6 | signal create_variable(var_name: String, var_type: String) 7 | 8 | @onready var _context := BlockEditorContext.get_default() 9 | 10 | @onready var _variable_input := %VariableInput 11 | @onready var _type_option := %TypeOption 12 | @onready var _messages := %Messages 13 | 14 | const available_types = ["STRING", "BOOL", "INT", "FLOAT", "VECTOR2", "COLOR"] 15 | 16 | 17 | func _ready(): 18 | _type_option.clear() 19 | _type_option.focus_next = get_cancel_button().get_path() 20 | get_cancel_button().focus_previous = _type_option.get_path() 21 | get_ok_button().focus_next = _variable_input.get_path() 22 | _variable_input.focus_previous = get_ok_button().get_path() 23 | 24 | for type in available_types: 25 | _type_option.add_item(type) 26 | 27 | _clear() 28 | 29 | 30 | func _clear(): 31 | # Workaround for POT generation extracting empty string. 32 | _variable_input.text = str("") 33 | get_ok_button().disabled = check_errors(_variable_input.text) 34 | _type_option.select(0) 35 | 36 | 37 | func _on_variable_input_text_changed(new_text): 38 | get_ok_button().disabled = check_errors(new_text) 39 | 40 | 41 | func check_errors(new_var_name: String) -> bool: 42 | if new_var_name.contains(" "): 43 | var caret_column = _variable_input.caret_column 44 | new_var_name = new_var_name.replace(" ", "_") 45 | _variable_input.text = new_var_name 46 | _variable_input.caret_column = caret_column 47 | 48 | _messages.clear() 49 | 50 | var errors: Array = [] 51 | 52 | if new_var_name == "": 53 | errors.append("Variable requires a name") 54 | elif new_var_name == "_": 55 | errors.append("Variable name cannot be a single underscore") 56 | elif RegEx.create_from_string("^[0-9]").search(new_var_name) != null: 57 | errors.append("Variable name cannot start with numbers") 58 | 59 | if new_var_name.begins_with("__"): 60 | errors.append("Variable name cannot start with two underscores") 61 | 62 | if RegEx.create_from_string("[^_a-zA-Z0-9-]+").search(new_var_name) != null: 63 | errors.append("Variable name cannot contain special characters") 64 | 65 | var duplicate_variable_name := false 66 | if _context.block_script: 67 | for variable in _context.block_script.variables: 68 | if variable.var_name == new_var_name: 69 | duplicate_variable_name = true 70 | break 71 | 72 | if duplicate_variable_name: 73 | errors.append("Variable already exists") 74 | 75 | if errors.is_empty(): 76 | _messages.push_context() 77 | _messages.push_color(Color("73F27F")) 78 | _messages.push_list(0, RichTextLabel.LIST_DOTS, false) 79 | 80 | _messages.add_text("Will create new variable") 81 | 82 | _messages.pop_context() 83 | 84 | return false 85 | else: 86 | _messages.push_context() 87 | _messages.push_color(Color("FF786B")) 88 | _messages.push_list(0, RichTextLabel.LIST_DOTS, false) 89 | 90 | for error in errors: 91 | _messages.add_text(error) 92 | _messages.newline() 93 | 94 | _messages.pop_context() 95 | 96 | return true 97 | 98 | 99 | func _on_confirmed(): 100 | if check_errors(_variable_input.text): 101 | return 102 | 103 | create_variable.emit(_variable_input.text, _type_option.get_item_text(_type_option.selected)) 104 | hide() 105 | _clear() 106 | 107 | 108 | func _on_canceled(): 109 | _clear() 110 | 111 | 112 | func _on_about_to_popup() -> void: 113 | _variable_input.grab_focus() 114 | 115 | 116 | func _on_focus_entered() -> void: 117 | _variable_input.grab_focus() 118 | 119 | 120 | func _on_variable_input_text_submitted(new_text: String) -> void: 121 | _on_confirmed() 122 | -------------------------------------------------------------------------------- /ui/picker/categories/variable_category/create_variable_dialog.gd.uid: -------------------------------------------------------------------------------- 1 | uid://drrvypmfse801 2 | -------------------------------------------------------------------------------- /ui/picker/categories/variable_category/create_variable_dialog.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=2 format=3 uid="uid://dbrm7wwkao0c0"] 2 | 3 | [ext_resource type="Script" path="res://addons/reblocks/ui/picker/categories/variable_category/create_variable_dialog.gd" id="1_b52me"] 4 | 5 | [node name="CreateVariableDialog" type="ConfirmationDialog"] 6 | title = "Create New Variable" 7 | initial_position = 1 8 | size = Vector2i(300, 183) 9 | visible = true 10 | ok_button_text = "Create" 11 | dialog_hide_on_ok = false 12 | script = ExtResource("1_b52me") 13 | 14 | [node name="VBoxContainer" type="VBoxContainer" parent="."] 15 | offset_left = 8.0 16 | offset_top = 8.0 17 | offset_right = 292.0 18 | offset_bottom = 134.0 19 | 20 | [node name="GridContainer" type="GridContainer" parent="VBoxContainer"] 21 | layout_mode = 2 22 | columns = 2 23 | 24 | [node name="Label" type="Label" parent="VBoxContainer/GridContainer"] 25 | layout_mode = 2 26 | text = "Name " 27 | 28 | [node name="VariableInput" type="LineEdit" parent="VBoxContainer/GridContainer"] 29 | unique_name_in_owner = true 30 | auto_translate_mode = 2 31 | layout_mode = 2 32 | focus_neighbor_bottom = NodePath("../TypeOption") 33 | focus_next = NodePath("../TypeOption") 34 | 35 | [node name="Label2" type="Label" parent="VBoxContainer/GridContainer"] 36 | layout_mode = 2 37 | text = "Type " 38 | 39 | [node name="TypeOption" type="OptionButton" parent="VBoxContainer/GridContainer"] 40 | unique_name_in_owner = true 41 | auto_translate_mode = 2 42 | layout_mode = 2 43 | size_flags_horizontal = 3 44 | focus_neighbor_top = NodePath("../VariableInput") 45 | focus_previous = NodePath("../VariableInput") 46 | selected = 0 47 | item_count = 6 48 | popup/item_0/text = "STRING" 49 | popup/item_0/id = 0 50 | popup/item_1/text = "BOOL" 51 | popup/item_1/id = 1 52 | popup/item_2/text = "INT" 53 | popup/item_2/id = 2 54 | popup/item_3/text = "FLOAT" 55 | popup/item_3/id = 3 56 | popup/item_4/text = "VECTOR2" 57 | popup/item_4/id = 4 58 | popup/item_5/text = "COLOR" 59 | popup/item_5/id = 5 60 | 61 | [node name="ErrorsContainer" type="MarginContainer" parent="VBoxContainer"] 62 | layout_mode = 2 63 | size_flags_vertical = 3 64 | theme_override_constants/margin_top = 8 65 | 66 | [node name="Messages" type="RichTextLabel" parent="VBoxContainer/ErrorsContainer"] 67 | unique_name_in_owner = true 68 | custom_minimum_size = Vector2(0, 48) 69 | layout_mode = 2 70 | theme_override_constants/line_separation = 4 71 | fit_content = true 72 | 73 | [connection signal="about_to_popup" from="." to="." method="_on_about_to_popup"] 74 | [connection signal="canceled" from="." to="." method="_on_canceled"] 75 | [connection signal="confirmed" from="." to="." method="_on_confirmed"] 76 | [connection signal="focus_entered" from="." to="." method="_on_focus_entered"] 77 | [connection signal="text_changed" from="VBoxContainer/GridContainer/VariableInput" to="." method="_on_variable_input_text_changed"] 78 | [connection signal="text_submitted" from="VBoxContainer/GridContainer/VariableInput" to="." method="_on_variable_input_text_submitted"] 79 | -------------------------------------------------------------------------------- /ui/picker/categories/variable_category/variable_category_display.gd: -------------------------------------------------------------------------------- 1 | @tool 2 | extends "res://addons/reblocks/ui/picker/categories/block_category_display.gd" 3 | 4 | const Types = preload("res://addons/reblocks/types/types.gd") 5 | const VariableDefinition = preload("res://addons/reblocks/code_generation/variable_definition.gd") 6 | 7 | @onready var h_separator := %HSeparator 8 | 9 | signal variable_created(variable: VariableDefinition) 10 | 11 | 12 | func _ready(): 13 | super() 14 | 15 | 16 | func _update_blocks(): 17 | super() 18 | 19 | if h_separator: 20 | h_separator.visible = not block_definitions.is_empty() 21 | 22 | 23 | func _on_create_variable(var_name, var_type): 24 | variable_created.emit(VariableDefinition.new(var_name, Types.STRING_TO_VARIANT_TYPE[var_type])) 25 | -------------------------------------------------------------------------------- /ui/picker/categories/variable_category/variable_category_display.gd.uid: -------------------------------------------------------------------------------- 1 | uid://b31vdisxgqpxb 2 | -------------------------------------------------------------------------------- /ui/picker/categories/variable_category/variable_category_display.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=5 format=3 uid="uid://byne4g2yvdf3"] 2 | 3 | [ext_resource type="PackedScene" uid="uid://duhpwtfo3k0sk" path="res://addons/reblocks/ui/picker/categories/block_category_display.tscn" id="1_vermd"] 4 | [ext_resource type="Script" path="res://addons/reblocks/ui/picker/categories/variable_category/variable_category_display.gd" id="2_ggvi7"] 5 | [ext_resource type="PackedScene" uid="uid://t0eoc4ekvjr1" path="res://addons/reblocks/ui/picker/categories/variable_category/create_variable_button.tscn" id="3_gjvnq"] 6 | 7 | [sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_0m6vh"] 8 | 9 | [node name="VariableCategoryDisplay" instance=ExtResource("1_vermd")] 10 | script = ExtResource("2_ggvi7") 11 | 12 | [node name="BlocksContainer" parent="VBoxContainer" index="1"] 13 | visible = false 14 | 15 | [node name="HSeparator" type="HSeparator" parent="VBoxContainer" index="2"] 16 | unique_name_in_owner = true 17 | visible = false 18 | layout_mode = 2 19 | theme_override_constants/separation = 30 20 | theme_override_styles/separator = SubResource("StyleBoxEmpty_0m6vh") 21 | 22 | [node name="CreateVariableButton" parent="VBoxContainer" index="3" instance=ExtResource("3_gjvnq")] 23 | layout_mode = 2 24 | 25 | [connection signal="create_variable" from="VBoxContainer/CreateVariableButton" to="." method="_on_create_variable"] 26 | -------------------------------------------------------------------------------- /ui/picker/picker.gd.uid: -------------------------------------------------------------------------------- 1 | uid://b8fhdn4gigy8y 2 | -------------------------------------------------------------------------------- /ui/picker/picker.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=2 format=3 uid="uid://dlabt3bgmpna2"] 2 | 3 | [ext_resource type="Script" path="res://addons/reblocks/ui/picker/picker.gd" id="1_tkt44"] 4 | 5 | [node name="Picker" type="MarginContainer"] 6 | offset_right = 251.0 7 | offset_bottom = 253.0 8 | script = ExtResource("1_tkt44") 9 | 10 | [node name="Panel" type="Panel" parent="."] 11 | layout_mode = 2 12 | 13 | [node name="WidgetContainer" type="HBoxContainer" parent="."] 14 | unique_name_in_owner = true 15 | layout_mode = 2 16 | size_flags_vertical = 3 17 | theme_override_constants/separation = 0 18 | 19 | [node name="CategoryMarginContainer" type="MarginContainer" parent="WidgetContainer"] 20 | layout_mode = 2 21 | size_flags_horizontal = 0 22 | theme_override_constants/margin_left = 4 23 | theme_override_constants/margin_top = 4 24 | theme_override_constants/margin_right = 4 25 | theme_override_constants/margin_bottom = 4 26 | 27 | [node name="CategoryScroll" type="ScrollContainer" parent="WidgetContainer/CategoryMarginContainer"] 28 | layout_mode = 2 29 | horizontal_scroll_mode = 0 30 | 31 | [node name="CategoryList" type="VBoxContainer" parent="WidgetContainer/CategoryMarginContainer/CategoryScroll"] 32 | unique_name_in_owner = true 33 | layout_mode = 2 34 | theme_override_constants/separation = 10 35 | 36 | [node name="BlockMarginContainer" type="MarginContainer" parent="WidgetContainer"] 37 | layout_mode = 2 38 | size_flags_horizontal = 3 39 | 40 | [node name="BlockScroll" type="ScrollContainer" parent="WidgetContainer/BlockMarginContainer"] 41 | unique_name_in_owner = true 42 | custom_minimum_size = Vector2(250, 0) 43 | layout_mode = 2 44 | size_flags_horizontal = 3 45 | horizontal_scroll_mode = 3 46 | 47 | [node name="BlockList" type="VBoxContainer" parent="WidgetContainer/BlockMarginContainer/BlockScroll"] 48 | unique_name_in_owner = true 49 | layout_mode = 2 50 | theme_override_constants/separation = 0 51 | -------------------------------------------------------------------------------- /ui/script_window/script_window.gd: -------------------------------------------------------------------------------- 1 | @tool 2 | extends Window 3 | 4 | @onready var script_label: CodeEdit = $"PanelContainer/VBox/Code" 5 | 6 | var script_content: String = "" 7 | 8 | 9 | ## Attempts to match the syntax highlighting for some open script in the 10 | ## editor, which is more likely to be appropriate for the editor theme 11 | ## than our hardcoded default 12 | func _apply_editor_syntax_highlighter() -> void: 13 | var script_editor: ScriptEditor = EditorInterface.get_script_editor() 14 | for x in script_editor.get_open_script_editors(): 15 | var control: Control = x.get_base_editor() 16 | if control is TextEdit: 17 | script_label.syntax_highlighter = control.syntax_highlighter 18 | break 19 | 20 | 21 | ## Undoes the effect of the CodeEdit being read-only 22 | func _remove_font_color_alpha_clamp() -> void: 23 | var font_readonly_color = script_label.get_theme_color("font_readonly_color") 24 | font_readonly_color.a = 1 25 | script_label.add_theme_color_override("font_readonly_color", font_readonly_color) 26 | 27 | 28 | func update_script(script: String) -> void: 29 | _apply_editor_syntax_highlighter() 30 | _remove_font_color_alpha_clamp() 31 | script_content = script 32 | script_label.text = script_content.replace("\t", " ") 33 | 34 | 35 | func _on_copy_code_pressed() -> void: 36 | DisplayServer.clipboard_set(script_content) 37 | -------------------------------------------------------------------------------- /ui/script_window/script_window.gd.uid: -------------------------------------------------------------------------------- 1 | uid://drgxnv88f3jyj 2 | -------------------------------------------------------------------------------- /ui/script_window/script_window.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=4 format=3 uid="uid://c5qmyjwv7gaxl"] 2 | 3 | [ext_resource type="Script" path="res://addons/reblocks/ui/script_window/script_window.gd" id="1_iw5ag"] 4 | 5 | [sub_resource type="SystemFont" id="SystemFont_r6ct2"] 6 | font_names = PackedStringArray("DejaVu Sans Mono") 7 | subpixel_positioning = 0 8 | 9 | [sub_resource type="SyntaxHighlighter" id="SyntaxHighlighter_0wnrb"] 10 | 11 | [node name="ScriptWindow" type="Window"] 12 | title = "Block Code Generated GDScript" 13 | initial_position = 1 14 | size = Vector2i(750, 750) 15 | transient = true 16 | script = ExtResource("1_iw5ag") 17 | 18 | [node name="PanelContainer" type="PanelContainer" parent="."] 19 | anchors_preset = 15 20 | anchor_right = 1.0 21 | anchor_bottom = 1.0 22 | grow_horizontal = 2 23 | grow_vertical = 2 24 | 25 | [node name="Panel" type="Panel" parent="PanelContainer"] 26 | layout_mode = 2 27 | 28 | [node name="VBox" type="VBoxContainer" parent="PanelContainer"] 29 | layout_mode = 2 30 | 31 | [node name="Code" type="CodeEdit" parent="PanelContainer/VBox"] 32 | unique_name_in_owner = true 33 | layout_mode = 2 34 | size_flags_vertical = 3 35 | theme_override_colors/font_readonly_color = Color(0.875, 0.875, 0.875, 1) 36 | theme_override_fonts/font = SubResource("SystemFont_r6ct2") 37 | editable = false 38 | syntax_highlighter = SubResource("SyntaxHighlighter_0wnrb") 39 | highlight_all_occurrences = true 40 | highlight_current_line = true 41 | 42 | [node name="HBoxContainer" type="HBoxContainer" parent="PanelContainer/VBox"] 43 | layout_mode = 2 44 | 45 | [node name="MarginContainer" type="MarginContainer" parent="PanelContainer/VBox/HBoxContainer"] 46 | layout_mode = 2 47 | size_flags_horizontal = 3 48 | theme_override_constants/margin_left = 3 49 | theme_override_constants/margin_right = 3 50 | theme_override_constants/margin_bottom = 3 51 | 52 | [node name="CopyCode" type="Button" parent="PanelContainer/VBox/HBoxContainer/MarginContainer"] 53 | layout_mode = 2 54 | size_flags_horizontal = 4 55 | text = "Copy" 56 | 57 | [connection signal="pressed" from="PanelContainer/VBox/HBoxContainer/MarginContainer/CopyCode" to="." method="_on_copy_code_pressed"] 58 | -------------------------------------------------------------------------------- /ui/script_window/split_script_window.gd: -------------------------------------------------------------------------------- 1 | @tool 2 | extends HBoxContainer 3 | 4 | signal script_window_opened 5 | 6 | @onready var script_label: CodeEdit = $"PanelContainer/CodeContainer/Code" 7 | @onready var window_button: Button = %WindowButton 8 | @onready var code_container: VBoxContainer = $"PanelContainer/CodeContainer" 9 | 10 | var script_content: String = "" 11 | var window_mode: bool = false 12 | 13 | 14 | ## Attempts to match the syntax highlighting for some open script in the 15 | ## editor, which is more likely to be appropriate for the editor theme 16 | ## than our hardcoded default 17 | func _apply_editor_syntax_highlighter() -> void: 18 | var script_editor: ScriptEditor = EditorInterface.get_script_editor() 19 | for x in script_editor.get_open_script_editors(): 20 | var control: Control = x.get_base_editor() 21 | if control is TextEdit: 22 | script_label.syntax_highlighter = control.syntax_highlighter 23 | break 24 | 25 | 26 | ## Undoes the effect of the CodeEdit being read-only 27 | func _remove_font_color_alpha_clamp() -> void: 28 | var font_readonly_color = script_label.get_theme_color("font_readonly_color") 29 | font_readonly_color.a = 1 30 | script_label.add_theme_color_override("font_readonly_color", font_readonly_color) 31 | 32 | 33 | func update_script(script: String) -> void: 34 | _apply_editor_syntax_highlighter() 35 | _remove_font_color_alpha_clamp() 36 | script_content = script 37 | script_label.text = script_content.replace("\t", " ") 38 | 39 | 40 | func _on_copy_code_pressed() -> void: 41 | DisplayServer.clipboard_set(script_content) 42 | 43 | 44 | func _on_window_button_pressed() -> void: 45 | script_window_opened.emit() 46 | -------------------------------------------------------------------------------- /ui/script_window/split_script_window.gd.uid: -------------------------------------------------------------------------------- 1 | uid://c1esa7mkimtjv 2 | -------------------------------------------------------------------------------- /ui/script_window/split_script_window.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=4 format=3 uid="uid://c2tvodrmli2ar"] 2 | 3 | [ext_resource type="Script" path="res://addons/reblocks/ui/script_window/split_script_window.gd" id="1_pcqlh"] 4 | 5 | [sub_resource type="SystemFont" id="SystemFont_r6ct2"] 6 | font_names = PackedStringArray("DejaVu Sans Mono") 7 | subpixel_positioning = 0 8 | 9 | [sub_resource type="CodeHighlighter" id="CodeHighlighter_3qk2k"] 10 | 11 | [node name="SplitScriptWindow" type="HBoxContainer"] 12 | custom_minimum_size = Vector2(400, 0) 13 | anchors_preset = 6 14 | anchor_left = 1.0 15 | anchor_top = 0.5 16 | anchor_right = 1.0 17 | anchor_bottom = 0.5 18 | offset_left = -484.0 19 | offset_top = -323.0 20 | offset_bottom = 323.0 21 | grow_horizontal = 0 22 | grow_vertical = 2 23 | size_flags_horizontal = 8 24 | size_flags_vertical = 3 25 | script = ExtResource("1_pcqlh") 26 | 27 | [node name="PanelContainer" type="PanelContainer" parent="."] 28 | layout_mode = 2 29 | size_flags_horizontal = 3 30 | 31 | [node name="Panel" type="Panel" parent="PanelContainer"] 32 | layout_mode = 2 33 | 34 | [node name="CodeContainer" type="VBoxContainer" parent="PanelContainer"] 35 | unique_name_in_owner = true 36 | layout_mode = 2 37 | 38 | [node name="Code" type="CodeEdit" parent="PanelContainer/CodeContainer"] 39 | unique_name_in_owner = true 40 | layout_mode = 2 41 | size_flags_vertical = 3 42 | theme_override_colors/font_readonly_color = Color(0.875, 0.875, 0.875, 1) 43 | theme_override_fonts/font = SubResource("SystemFont_r6ct2") 44 | text = " " 45 | editable = false 46 | syntax_highlighter = SubResource("CodeHighlighter_3qk2k") 47 | highlight_all_occurrences = true 48 | highlight_current_line = true 49 | draw_tabs = true 50 | 51 | [node name="HBoxContainer" type="HBoxContainer" parent="PanelContainer/CodeContainer"] 52 | layout_mode = 2 53 | 54 | [node name="MarginContainer" type="MarginContainer" parent="PanelContainer/CodeContainer/HBoxContainer"] 55 | layout_mode = 2 56 | size_flags_horizontal = 3 57 | theme_override_constants/margin_left = 3 58 | theme_override_constants/margin_right = 3 59 | theme_override_constants/margin_bottom = 3 60 | 61 | [node name="HBoxContainer" type="HBoxContainer" parent="PanelContainer/CodeContainer/HBoxContainer/MarginContainer"] 62 | layout_mode = 2 63 | 64 | [node name="CopyCode" type="Button" parent="PanelContainer/CodeContainer/HBoxContainer/MarginContainer/HBoxContainer"] 65 | layout_mode = 2 66 | size_flags_horizontal = 6 67 | text = "Copy" 68 | 69 | [node name="WindowButton" type="Button" parent="PanelContainer/CodeContainer/HBoxContainer/MarginContainer/HBoxContainer"] 70 | unique_name_in_owner = true 71 | layout_mode = 2 72 | size_flags_horizontal = 6 73 | text = "Open Window" 74 | 75 | [connection signal="pressed" from="PanelContainer/CodeContainer/HBoxContainer/MarginContainer/HBoxContainer/CopyCode" to="." method="_on_copy_code_pressed"] 76 | [connection signal="pressed" from="PanelContainer/CodeContainer/HBoxContainer/MarginContainer/HBoxContainer/WindowButton" to="." method="_on_window_button_pressed"] 77 | -------------------------------------------------------------------------------- /ui/title_bar/title_bar.gd: -------------------------------------------------------------------------------- 1 | @tool 2 | extends MarginContainer 3 | 4 | const BlockCodePlugin = preload("res://addons/reblocks/block_code_plugin.gd") 5 | 6 | signal node_name_changed(node_name: String) 7 | 8 | @onready var _context := BlockEditorContext.get_default() 9 | 10 | @onready var _block_code_icon = load("res://addons/reblocks/block_code_node/block_code_node.svg") as Texture2D 11 | @onready var _editor_inspector: EditorInspector = EditorInterface.get_inspector() 12 | @onready var _node_option_button: OptionButton = %NodeOptionButton 13 | 14 | 15 | func _ready(): 16 | _context.changed.connect(_on_context_changed) 17 | _node_option_button.connect("item_selected", _on_node_option_button_item_selected) 18 | 19 | 20 | func _on_context_changed(): 21 | # TODO: We should listen for property changes in all BlockCode nodes and 22 | # their parents. As a workaround for the UI displaying stale data, 23 | # we'll crudely update the list of BlockCode nodes whenever the 24 | # selection changes. 25 | 26 | _update_node_option_button_items() 27 | 28 | var select_index = _get_block_script_index(_context.block_script) 29 | if _node_option_button.selected != select_index: 30 | _node_option_button.select(select_index) 31 | 32 | 33 | func _update_node_option_button_items(): 34 | _node_option_button.clear() 35 | 36 | var scene_root = EditorInterface.get_edited_scene_root() 37 | 38 | if not scene_root: 39 | return 40 | 41 | for block_code in BlockCodePlugin.list_block_code_nodes_for_node(scene_root, true): 42 | if not BlockCodePlugin.is_block_code_editable(block_code): 43 | continue 44 | 45 | var node_item_index = _node_option_button.item_count 46 | var node_label = "{name} ({type})".format({"name": scene_root.get_path_to(block_code).get_concatenated_names(), "type": block_code.block_script.script_inherits}) 47 | _node_option_button.add_item(node_label) 48 | _node_option_button.set_item_icon(node_item_index, _block_code_icon) 49 | _node_option_button.set_item_metadata(node_item_index, block_code) 50 | 51 | _node_option_button.disabled = _node_option_button.item_count == 0 52 | 53 | 54 | func _get_block_script_index(block_script: BlockScriptSerialization) -> int: 55 | for index in range(_node_option_button.item_count): 56 | var block_code_node = _node_option_button.get_item_metadata(index) 57 | if block_code_node.block_script == block_script: 58 | return index 59 | return -1 60 | 61 | 62 | func _on_node_option_button_item_selected(index): 63 | var block_code_node = _node_option_button.get_item_metadata(index) as BlockCode 64 | _context.block_code_node = block_code_node 65 | -------------------------------------------------------------------------------- /ui/title_bar/title_bar.gd.uid: -------------------------------------------------------------------------------- 1 | uid://dv1v5haqk3u58 2 | -------------------------------------------------------------------------------- /ui/title_bar/title_bar.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=2 format=3 uid="uid://bm1183pm05p6a"] 2 | 3 | [ext_resource type="Script" path="res://addons/reblocks/ui/title_bar/title_bar.gd" id="1_hpvmt"] 4 | 5 | [node name="TitleBar" type="MarginContainer"] 6 | custom_minimum_size = Vector2(0, 40) 7 | offset_right = 1000.0 8 | offset_bottom = 40.0 9 | script = ExtResource("1_hpvmt") 10 | 11 | [node name="Panel" type="Panel" parent="."] 12 | layout_mode = 2 13 | 14 | [node name="HBoxContainer" type="HBoxContainer" parent="."] 15 | layout_mode = 2 16 | 17 | [node name="NodeOptionButton" type="OptionButton" parent="HBoxContainer"] 18 | unique_name_in_owner = true 19 | layout_mode = 2 20 | size_flags_horizontal = 3 21 | -------------------------------------------------------------------------------- /ui/tooltip/tooltip.gd: -------------------------------------------------------------------------------- 1 | @tool 2 | class_name Tooltip 3 | extends RichTextLabel 4 | ## Rich-text control for block tooltips that matches the built-in inspector's tooltips' font styles 5 | 6 | const Util = preload("res://addons/reblocks/ui/util.gd") 7 | 8 | 9 | func override_font(font_name: StringName, editor_font_name: StringName) -> Font: 10 | var font = get_theme_font(editor_font_name, &"EditorFonts") 11 | add_theme_font_override(font_name, font) 12 | return font 13 | 14 | 15 | func override_fonts(): 16 | # Set fonts to match documentation tooltips in inspector 17 | override_font(&"normal_font", &"doc") 18 | override_font(&"mono_font", &"doc_source") 19 | override_font(&"bold_font", &"doc_bold") 20 | var italics = override_font(&"italics_font", &"doc_italic") 21 | 22 | # No doc_ style for bold italic; fake it by emboldening the italic style 23 | var bold_italics = FontVariation.new() 24 | bold_italics.set_base_font(italics) 25 | bold_italics.set_variation_embolden(1.2) 26 | add_theme_font_override(&"bold_italics_font", bold_italics) 27 | 28 | 29 | func _ready(): 30 | if not self.is_part_of_edited_scene(): 31 | override_fonts() 32 | -------------------------------------------------------------------------------- /ui/tooltip/tooltip.gd.uid: -------------------------------------------------------------------------------- 1 | uid://cmjwydpocd766 2 | -------------------------------------------------------------------------------- /ui/tooltip/tooltip.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=2 format=3 uid="uid://bmxco03vqyq2t"] 2 | 3 | [ext_resource type="Script" path="res://addons/reblocks/ui/tooltip/tooltip.gd" id="1_4ko6a"] 4 | 5 | [node name="Tooltip" type="RichTextLabel"] 6 | custom_minimum_size = Vector2(360, 48) 7 | anchors_preset = 15 8 | anchor_right = 1.0 9 | anchor_bottom = 1.0 10 | grow_horizontal = 2 11 | grow_vertical = 2 12 | bbcode_enabled = true 13 | fit_content = true 14 | script = ExtResource("1_4ko6a") 15 | -------------------------------------------------------------------------------- /ui/util.gd: -------------------------------------------------------------------------------- 1 | extends Object 2 | 3 | 4 | ## Get the path from [param reference] to [param node] within a scene. 5 | ## 6 | ## Returns the path from [param reference] to [param node] without referencing 7 | ## parent nodes. If [param node] is [param reference] or a child of it in the 8 | ## scene tree, a relative path is returned. If [param node] is an ancestor of 9 | ## [param reference] in the scene tree, an absolute path using [param 10 | ## path_root] is returned. 11 | ## [br] 12 | ## Both [param node] and [param reference] must be ancestors of [param 13 | ## path_root]. If [param path_root] is [constant null] 14 | ## [method EditorInterface.get_edited_scene_root().get_parent] is used. 15 | static func node_scene_path(node: Node, reference: Node, path_root: Node = null) -> NodePath: 16 | if path_root == null: 17 | path_root = EditorInterface.get_edited_scene_root().get_parent() 18 | 19 | if not path_root.is_ancestor_of(node): 20 | push_error("Node %s is not an ancestor of %s" % [path_root, node]) 21 | return NodePath() 22 | if not path_root.is_ancestor_of(reference): 23 | push_error("Node %s is not an ancestor of %s" % [path_root, reference]) 24 | return NodePath() 25 | 26 | if node.unique_name_in_owner: 27 | # With unique_name_in_owner, just use the % prefixed name. 28 | return NodePath("%%%s" % node.name) 29 | else: 30 | # The node is reference or a child of it. Use a relative path. 31 | return reference.get_path_to(node) 32 | -------------------------------------------------------------------------------- /ui/util.gd.uid: -------------------------------------------------------------------------------- 1 | uid://bdhv40hm0im1l 2 | --------------------------------------------------------------------------------