Skip to content

Commit

Permalink
Merge pull request #117 from endlessm/T35541-block-code-in-bottom-panel
Browse files Browse the repository at this point in the history
T35541 block code in bottom panel
  • Loading branch information
wnbaum authored Jul 9, 2024
2 parents 58e3e0d + ed99a84 commit d82ce7d
Show file tree
Hide file tree
Showing 7 changed files with 359 additions and 57 deletions.
88 changes: 74 additions & 14 deletions addons/block_code/block_code_plugin.gd
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,13 @@ class_name BlockCodePlugin
extends EditorPlugin

const MainPanel := preload("res://addons/block_code/ui/main_panel.tscn")
static var main_panel
static var main_panel: MainPanel
static var block_code_button: Button

var editor_inspector: EditorInspector
var editor_selection: EditorSelection

var selected_block_code_node: BlockCode

var old_feature_profile: String = ""

Expand Down Expand Up @@ -48,14 +52,11 @@ func _enter_tree():
Types.init_cast_graph()

editor_inspector = EditorInterface.get_inspector()
editor_selection = EditorInterface.get_selection()

main_panel = MainPanel.instantiate()
main_panel.undo_redo = get_undo_redo()

# Add the main panel to the editor's main viewport.
EditorInterface.get_editor_main_screen().add_child(main_panel)
# Hide the main panel. Very much required.
_make_visible(false)
block_code_button = add_control_to_bottom_panel(main_panel, _get_plugin_name())

# Remove unwanted class nodes from create node
old_feature_profile = EditorInterface.get_current_feature_profile()
Expand All @@ -75,8 +76,13 @@ func _enter_tree():


func _exit_tree():
if block_code_button:
remove_control_from_bottom_panel(main_panel)
block_code_button = null

if main_panel:
main_panel.queue_free()
main_panel = null

var editor_paths: EditorPaths = EditorInterface.get_editor_paths()
if editor_paths:
Expand All @@ -91,26 +97,80 @@ func _exit_tree():
func _ready():
connect("scene_changed", _on_scene_changed)
editor_inspector.connect("edited_object_changed", _on_editor_inspector_edited_object_changed)
editor_inspector.connect("property_edited", _on_editor_inspector_property_edited)
_on_scene_changed(EditorInterface.get_edited_scene_root())
_on_editor_inspector_edited_object_changed()


func _on_scene_changed(scene_root: Node):
BlockCodePlugin.main_panel.switch_scene(scene_root)
main_panel.switch_scene(scene_root)
_on_editor_inspector_edited_object_changed()


func _on_editor_inspector_edited_object_changed():
var block_code: BlockCode = editor_inspector.get_edited_object() as BlockCode
BlockCodePlugin.main_panel.switch_script(block_code)
var edited_object = editor_inspector.get_edited_object()
#var edited_node = edited_object as Node
var selected_nodes = editor_selection.get_selected_nodes()

if edited_object is BlockCode and selected_nodes.has(edited_object):
# If a BlockCode node is being edited, and it was explicitly selected
# (as opposed to edited in the Inspector alone), select its parent node
# as well. This provides a clearer indication of what is being edited.
# Changing the selection will cause edited_object_changed to fire again,
# so we will return early to avoid duplicate work.
var parent_node = edited_object.get_parent()
if parent_node:
EditorInterface.get_selection().add_node.call_deferred(parent_node)
make_bottom_panel_item_visible(main_panel)
return

func _has_main_screen():
return true
if edited_object and edited_object.get_class() == "MultiNodeEdit":
# If multiple nodes are shown in the inspector, we will find the first
# BlockCode node in the list of selected nodes and use that. This
# occurs when the user selects multiple items in the Scene panel, or
# when we select the parent of a BlockCode node.
edited_object = selected_nodes.filter(func(node): return node is BlockCode).pop_front()

# We will edit either the selected node (if it is a BlockCode node) or
# the first BlockCode child of that node. Keep track of the block code node
# being edited so we know to monitor for changes from EditorInspector.
selected_block_code_node = list_block_code_for_node(edited_object as Node).pop_front()
if not is_block_code_editable(selected_block_code_node):
selected_block_code_node = null

func _make_visible(visible):
if main_panel:
main_panel.visible = visible
main_panel.switch_block_code_node(selected_block_code_node)


static func is_block_code_editable(block_code: BlockCode) -> bool:
if not block_code:
return false

# A BlockCode node can be edited if it belongs to the edited scene, or it
# is an editable instance.

var scene_node = EditorInterface.get_edited_scene_root()

return block_code == scene_node or block_code.owner == scene_node or scene_node.is_editable_instance(block_code.owner)


static func node_has_block_code(node: Node, recursive: bool = false) -> bool:
return list_block_code_for_node(node, recursive).size() > 0


static func list_block_code_for_node(node: Node, recursive: bool = false) -> Array[BlockCode]:
var result: Array[BlockCode] = []

if node is BlockCode:
result.append(node)
elif node:
result.append_array(node.find_children("*", "BlockCode", recursive))

return result


func _on_editor_inspector_property_edited(property: String):
if selected_block_code_node:
_on_editor_inspector_edited_object_changed()


func _get_plugin_name():
Expand Down
22 changes: 11 additions & 11 deletions addons/block_code/examples/pong_game/pong_game.tscn
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
[ext_resource type="PackedScene" uid="uid://c7l70grmkauij" path="res://addons/block_code/examples/pong_game/ball.tscn" id="9_xrqll"]
[ext_resource type="PackedScene" uid="uid://fhoapg3anjsu" path="res://addons/block_code/examples/pong_game/goal_area.tscn" id="12_nqmxu"]

[sub_resource type="Resource" id="Resource_k50df"]
[sub_resource type="Resource" id="Resource_k6jw1"]
script = ExtResource("5_wr38c")
block_class = &"StatementBlock"
serialized_props = [["block_name", "statement_block"], ["label", "StatementBlock"], ["color", Color(0.835294, 0.262745, 0.133333, 1)], ["block_type", 2], ["position", Vector2(0, 0)], ["scope", ""], ["block_format", "Move with player 1 buttons, speed {speed: VECTOR2}"], ["statement", "var dir = Vector2()
Expand All @@ -26,29 +26,29 @@ move_and_slide()"], ["defaults", {}], ["param_input_strings", {
"speed": "0,1000"
}]]

[sub_resource type="Resource" id="Resource_bjhgb"]
[sub_resource type="Resource" id="Resource_e61h1"]
script = ExtResource("4_qtggh")
serialized_block = SubResource("Resource_k50df")
serialized_block = SubResource("Resource_k6jw1")
path_child_pairs = []

[sub_resource type="Resource" id="Resource_fwk6m"]
[sub_resource type="Resource" id="Resource_pm7ay"]
script = ExtResource("5_wr38c")
block_class = &"EntryBlock"
serialized_props = [["block_name", "process_block"], ["label", "EntryBlock"], ["color", Color(0.92549, 0.231373, 0.34902, 1)], ["block_type", 1], ["position", Vector2(167, 112)], ["scope", ""], ["block_format", "On Process"], ["statement", "func _process(delta):"], ["defaults", {}], ["param_input_strings", {}], ["signal_name", ""]]
serialized_props = [["block_name", "process_block"], ["label", "EntryBlock"], ["color", Color(0.92549, 0.231373, 0.34902, 1)], ["block_type", 1], ["position", Vector2(174, 102)], ["scope", ""], ["block_format", "On Process"], ["statement", "func _process(delta):"], ["defaults", {}], ["param_input_strings", {}], ["signal_name", ""]]

[sub_resource type="Resource" id="Resource_8ar27"]
[sub_resource type="Resource" id="Resource_uln40"]
script = ExtResource("4_qtggh")
serialized_block = SubResource("Resource_fwk6m")
path_child_pairs = [[NodePath("VBoxContainer/SnapPoint"), SubResource("Resource_bjhgb")]]
serialized_block = SubResource("Resource_pm7ay")
path_child_pairs = [[NodePath("VBoxContainer/SnapPoint"), SubResource("Resource_e61h1")]]

[sub_resource type="Resource" id="Resource_ue2t3"]
[sub_resource type="Resource" id="Resource_4j61k"]
script = ExtResource("6_ppdc3")
array = Array[ExtResource("4_qtggh")]([SubResource("Resource_8ar27")])
array = Array[ExtResource("4_qtggh")]([SubResource("Resource_uln40")])

[sub_resource type="Resource" id="Resource_qmak3"]
script = ExtResource("7_uuuue")
script_inherits = "SimpleCharacter"
block_trees = SubResource("Resource_ue2t3")
block_trees = SubResource("Resource_4j61k")
generated_script = "extends SimpleCharacter
var VAR_DICT := {}
Expand Down
76 changes: 66 additions & 10 deletions addons/block_code/ui/block_canvas/block_canvas.gd
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,33 @@ const BLOCK_AUTO_PLACE_MARGIN: Vector2 = Vector2(16, 8)

@onready var _window: Control = %Window
@onready var _window_scroll: ScrollContainer = %WindowScroll
@onready var _choose_block_code_label: Label = %ChooseBlockCodeLabel
@onready var _create_block_code_label: Label = %CreateBlockCodeLabel
@onready var _empty_box: BoxContainer = %EmptyBox

@onready var _selected_node_box: BoxContainer = %SelectedNodeBox
@onready var _selected_node_label: Label = %SelectedNodeBox/Label
@onready var _selected_node_label_format: String = _selected_node_label.text

@onready var _selected_node_with_block_code_box: BoxContainer = %SelectedNodeWithBlockCodeBox
@onready var _selected_node_with_block_code_label: Label = %SelectedNodeWithBlockCodeBox/Label
@onready var _selected_node_with_block_code_label_format: String = _selected_node_with_block_code_label.text

@onready var _add_block_code_button: Button = %AddBlockCodeButton
@onready var _open_scene_button: Button = %OpenSceneButton
@onready var _replace_block_code_button: Button = %ReplaceBlockCodeButton

@onready var _open_scene_icon = _open_scene_button.get_theme_icon("Load", "EditorIcons")

var _block_scenes_by_class = {}

signal reconnect_block(block: Block)
signal add_block_code
signal open_scene
signal replace_block_code


func _ready():
if not _open_scene_button.icon:
_open_scene_button.icon = _open_scene_icon
_populate_block_scenes_by_class()


Expand Down Expand Up @@ -59,16 +77,36 @@ func set_child(n: Node):
func bsd_selected(bsd: BlockScriptData):
clear_canvas()

_choose_block_code_label.visible = false
_create_block_code_label.visible = false
var edited_node = EditorInterface.get_inspector().get_edited_object() as Node

_empty_box.visible = false
_selected_node_box.visible = false
_selected_node_with_block_code_box.visible = false
_add_block_code_button.disabled = true
_open_scene_button.disabled = true
_replace_block_code_button.disabled = true

if bsd != null:
_load_bsd(bsd)
elif edited_node == null:
_empty_box.visible = true
elif BlockCodePlugin.node_has_block_code(edited_node):
# If the selected node has a block code node, but BlockCodePlugin didn't
# provide it to bsd_selected, we assume the block code itself is not
# editable. In that case, provide options to either edit the node's
# scene file, or override the BlockCode node. This is mostly to avoid
# creating a situation where a node has multiple BlockCode nodes.
_selected_node_with_block_code_box.visible = true
_selected_node_with_block_code_label.text = _selected_node_with_block_code_label_format.format({"node": edited_node.name})
_open_scene_button.disabled = false if edited_node.scene_file_path else true
_replace_block_code_button.disabled = false
else:
_selected_node_box.visible = true
_selected_node_label.text = _selected_node_label_format.format({"node": edited_node.name})
_add_block_code_button.disabled = false

if not bsd and scene_has_bsd_nodes():
_choose_block_code_label.visible = true
return
elif not bsd and not scene_has_bsd_nodes():
_create_block_code_label.visible = true
return

func _load_bsd(bsd: BlockScriptData):
for tree in bsd.block_trees.array:
load_tree(_window, tree)

Expand Down Expand Up @@ -151,3 +189,21 @@ func set_scope(scope: String):
func release_scope():
for block in _window.get_children():
block.modulate = Color.WHITE


func _on_add_block_code_button_pressed():
_add_block_code_button.disabled = true

add_block_code.emit()


func _on_open_scene_button_pressed():
_open_scene_button.disabled = true

open_scene.emit()


func _on_replace_block_code_button_pressed():
_replace_block_code_button.disabled = true

replace_block_code.emit()
82 changes: 77 additions & 5 deletions addons/block_code/ui/block_canvas/block_canvas.tscn
Original file line number Diff line number Diff line change
@@ -1,6 +1,19 @@
[gd_scene load_steps=2 format=3 uid="uid://c6vumewgnfquy"]
[gd_scene load_steps=5 format=3 uid="uid://c6vumewgnfquy"]

[ext_resource type="Script" path="res://addons/block_code/ui/block_canvas/block_canvas.gd" id="1_tk8h2"]
[ext_resource type="Texture2D" uid="uid://cmusxj1ppspnp" path="res://addons/block_code/block_code_node/block_code_node.svg" id="2_710vn"]

[sub_resource type="Image" id="Image_2jxnn"]
data = {
"data": PackedByteArray(255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 231, 255, 94, 94, 54, 255, 94, 94, 57, 255, 93, 93, 233, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 231, 255, 94, 94, 54, 255, 94, 94, 57, 255, 93, 93, 233, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 93, 93, 233, 255, 93, 93, 232, 255, 93, 93, 41, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 93, 93, 233, 255, 93, 93, 232, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 44, 255, 255, 255, 0, 255, 97, 97, 42, 255, 97, 97, 42, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 44, 255, 255, 255, 0, 255, 97, 97, 42, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 235, 255, 94, 94, 234, 255, 95, 95, 43, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 235, 255, 94, 94, 234, 255, 95, 95, 43, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 235, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 233, 255, 95, 95, 59, 255, 96, 96, 61, 255, 93, 93, 235, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 233, 255, 95, 95, 59, 255, 96, 96, 61, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0),
"format": "RGBA8",
"height": 16,
"mipmaps": false,
"width": 16
}

[sub_resource type="ImageTexture" id="ImageTexture_jgo72"]
image = SubResource("Image_2jxnn")

[node name="BlockCanvas" type="MarginContainer"]
anchors_preset = 15
Expand All @@ -25,16 +38,75 @@ layout_mode = 2
size_flags_horizontal = 3
mouse_filter = 1

[node name="ChooseBlockCodeLabel" type="Label" parent="."]
[node name="EmptyBox" type="VBoxContainer" parent="."]
unique_name_in_owner = true
visible = false
layout_mode = 2
text = "Choose a BlockCode node in the inspector."
size_flags_vertical = 4

[node name="Label" type="Label" parent="EmptyBox"]
layout_mode = 2
text = "Select a node to create and edit block code."
horizontal_alignment = 1

[node name="CreateBlockCodeLabel" type="Label" parent="."]
[node name="SelectedNodeBox" type="VBoxContainer" parent="."]
unique_name_in_owner = true
visible = false
layout_mode = 2
text = "First, add a BlockCode node to the scene."
size_flags_vertical = 4

[node name="Label" type="Label" parent="SelectedNodeBox"]
custom_minimum_size = Vector2(200, 0)
layout_mode = 2
text = "Use block coding to create custom behavior and game mechanics for \"{node}\"."
horizontal_alignment = 1
autowrap_mode = 2

[node name="ButtonsBox" type="HBoxContainer" parent="SelectedNodeBox"]
layout_mode = 2
size_flags_horizontal = 4

[node name="AddBlockCodeButton" type="Button" parent="SelectedNodeBox/ButtonsBox"]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 4
theme_type_variation = &"InspectorActionButton"
text = "Add Block Code"
icon = ExtResource("2_710vn")

[node name="SelectedNodeWithBlockCodeBox" type="VBoxContainer" parent="."]
unique_name_in_owner = true
visible = false
layout_mode = 2
size_flags_vertical = 4

[node name="Label" type="Label" parent="SelectedNodeWithBlockCodeBox"]
custom_minimum_size = Vector2(200, 0)
layout_mode = 2
text = "\"{node}\" uses block coding."
horizontal_alignment = 1
autowrap_mode = 2

[node name="ButtonsBox" type="HBoxContainer" parent="SelectedNodeWithBlockCodeBox"]
layout_mode = 2
size_flags_horizontal = 4

[node name="OpenSceneButton" type="Button" parent="SelectedNodeWithBlockCodeBox/ButtonsBox"]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 4
theme_type_variation = &"InspectorActionButton"
text = "Open in Editor"
icon = SubResource("ImageTexture_jgo72")

[node name="ReplaceBlockCodeButton" type="Button" parent="SelectedNodeWithBlockCodeBox/ButtonsBox"]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 4
theme_type_variation = &"InspectorActionButton"
text = "Override Block Code"
icon = ExtResource("2_710vn")

[connection signal="pressed" from="SelectedNodeBox/ButtonsBox/AddBlockCodeButton" to="." method="_on_add_block_code_button_pressed"]
[connection signal="pressed" from="SelectedNodeWithBlockCodeBox/ButtonsBox/OpenSceneButton" to="." method="_on_open_scene_button_pressed"]
[connection signal="pressed" from="SelectedNodeWithBlockCodeBox/ButtonsBox/ReplaceBlockCodeButton" to="." method="_on_replace_block_code_button_pressed"]
Loading

0 comments on commit d82ce7d

Please sign in to comment.