Skip to content

Commit

Permalink
Create Template Generator (#145)
Browse files Browse the repository at this point in the history
* Register CommandRecord.

Add CommandRecord in Blockflow constants.
Create CommandRecord "singleton" in plugin script initialization.
Add CommandRecord in plugin script.

* Add CommandRecord script.

This commit should have been added before previous one... but didn't for some reason.

CommandRecord is a 'singleton' class in charge of registering and managing know commands.

* Update CommandRecord to restore commands.

Update command record to restore commands from project settings.
Update plugin script to force update CommandRecord on project settings change.

* Prevent default commands being removed on project setting reload

* Update CommandRecord.

Remove `as_template` argument. Command record should not save resources implicitly in filesystem.

* Update CommandList to make usage of CommandRecord.

* Create TemplateGenerator.

Template generator helps creating templates from commands, visually.

* Register TemplateGenerator.

Add TemplateGenerator as child of BlockflowMainEditor to be able to use it.
  • Loading branch information
AnidemDex authored May 5, 2024
1 parent 955bdb7 commit 7cec64f
Show file tree
Hide file tree
Showing 3 changed files with 194 additions and 2 deletions.
6 changes: 6 additions & 0 deletions editor/command_list.gd
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const FALLBACK_ICON = preload("res://addons/blockflow/icons/false.svg")
const Settings = preload("res://addons/blockflow/blockflow.gd")
const CommandClass = preload("res://addons/blockflow/commands/command.gd")
const EditorConst = preload("res://addons/blockflow/editor/constants.gd")
const CommandRecord = preload("res://addons/blockflow/core/command_record.gd")

class Category extends VBoxContainer:
const InspectorTools = preload("res://addons/blockflow/editor/inspector/inspector_tools.gd")
Expand Down Expand Up @@ -165,6 +166,11 @@ func _notification(what: int) -> void:
NOTIFICATION_ENTER_TREE, NOTIFICATION_THEME_CHANGED:
# TODO: Add a background stylebox
return

NOTIFICATION_READY:
var command_record:CommandRecord = CommandRecord.get_record()
command_record.command_list_changed.connect(build_command_list)
build_command_list()

func _init() -> void:
size_flags_vertical = Control.SIZE_EXPAND_FILL
Expand Down
19 changes: 17 additions & 2 deletions editor/editor.gd
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ class StateLayout:
const Blockflow = preload("res://addons/blockflow/blockflow.gd")
const CollectionDisplayer = preload("res://addons/blockflow/editor/displayer.gd")
const CommandList = preload("res://addons/blockflow/editor/command_list.gd")
const TemplateGenerator = preload("res://addons/blockflow/editor/template_generator.gd")

const Constants = preload("res://addons/blockflow/editor/constants.gd")

Expand All @@ -27,7 +28,8 @@ enum _ItemPopup {
DUPLICATE,
REMOVE,
COPY,
PASTE
PASTE,
CREATE_TEMPLATE,
}

enum _DropSection {
Expand Down Expand Up @@ -60,6 +62,7 @@ var editor_undoredo:EditorUndoRedoManager
var collection_displayer:CollectionDisplayer
var command_list:CommandList
var title_label:Label
var template_generator:TemplateGenerator

var edit_callback:Callable
var toast_callback:Callable
Expand Down Expand Up @@ -464,6 +467,9 @@ func _item_popup_id_pressed(id:int) -> void:

_ItemPopup.PASTE:
add_command(command_clipboard.get_duplicated(), command_idx + 1, command.get_command_owner())

_ItemPopup.CREATE_TEMPLATE:
template_generator.create_from(command)


func _get_file_dialog() -> ConfirmationDialog:
Expand Down Expand Up @@ -502,6 +508,7 @@ func _collection_displayer_item_mouse_selected(_position:Vector2, button_index:i
can_move_up = c_pos != 0
can_move_down = c_pos < c_max_size - 1
_item_popup.clear()

_item_popup.add_item("Move up", _ItemPopup.MOVE_UP)
_item_popup.set_item_shortcut(_item_popup.get_item_index(_ItemPopup.MOVE_UP), Constants.SHORTCUT_MOVE_UP)
_item_popup.set_item_disabled(0, !can_move_up)
Expand All @@ -513,6 +520,7 @@ func _collection_displayer_item_mouse_selected(_position:Vector2, button_index:i
_item_popup.set_item_shortcut(_item_popup.get_item_index(_ItemPopup.DUPLICATE), Constants.SHORTCUT_DUPLICATE)
_item_popup.add_item("Remove", _ItemPopup.REMOVE)
_item_popup.set_item_shortcut(_item_popup.get_item_index(_ItemPopup.REMOVE), Constants.SHORTCUT_DELETE)

_item_popup.add_separator()

_item_popup.add_item("Copy", _ItemPopup.COPY)
Expand All @@ -524,6 +532,10 @@ func _collection_displayer_item_mouse_selected(_position:Vector2, button_index:i
_item_popup.set_item_disabled(_item_popup.get_item_index(_ItemPopup.PASTE), command_clipboard == null)
_item_popup.set_item_shortcut(_item_popup.get_item_index(_ItemPopup.PASTE), Constants.SHORTCUT_PASTE)

_item_popup.add_separator()

_item_popup.add_item("Create Template...", _ItemPopup.CREATE_TEMPLATE)

_item_popup.reset_size()
_item_popup.position = DisplayServer.mouse_get_position()
_item_popup.popup()
Expand Down Expand Up @@ -892,6 +904,9 @@ func _init() -> void:
_help_panel_load_btn.pressed.connect(_request_open)
hb.add_child(_help_panel_load_btn)

template_generator = TemplateGenerator.new()
add_child(template_generator)

if Engine.is_editor_hint():
# https://github.com/godotengine/godot/issues/73525#issuecomment-1606067249
_editor_file_dialog = (EditorFileDialog as Variant).new()
Expand All @@ -901,5 +916,5 @@ func _init() -> void:
_file_dialog = FileDialog.new()
_file_dialog.file_selected.connect(_editor_file_dialog_file_selected)
add_child(_file_dialog)


Engine.set_meta("Blockflow_main_editor", self)
171 changes: 171 additions & 0 deletions editor/template_generator.gd
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
@tool
extends ConfirmationDialog

## TemplateGenerator node
## Creates a template resource according a passed command, saves it
## under templates folder and registers it in CommandRecord.

const PREVIEW_DESCRIPTION = "Saving command '{command_name}' with the following structure:"
const PATH_DESCRIPTION = "Template will be saved under path:"
const NOTE_DESCRIPTION = "Note: This template will be added to CommandRecord after save."

const CommandRecord = preload("res://addons/blockflow/core/command_record.gd")

var preview_desc_label:Label
var path_line_edit:LineEdit
var warning_label:Button

var _editor_file_dialog
var _file_dialog

var current_command
var template
var template_path


func create_from(command:Resource) -> void:
_clean()
current_command = command
preview_desc_label.text = PREVIEW_DESCRIPTION.format({"command_name":command.command_name})
popup_centered_ratio(0.4)

func _confirm() -> void:
_create_template()
_save_template()
_register_template()

func _create_template() -> void:
if not current_command:
push_error("Failed to create a template: No command given")
return

template = current_command.get_duplicated()
template_path = path_line_edit.text

func _save_template() -> void:
if not template:
push_error("Failed saving template: No template was created")
return

template.resource_path = template_path
var error := ResourceSaver.save(template, template_path)

if error != OK:
push_error("Failed saving template: %s"%error_string(error))

func _register_template() -> void:
var record:CommandRecord = CommandRecord.get_record()
record.register(template, false)

func _clean() -> void:
path_line_edit.text_changed.emit("")
path_line_edit.text = ""
get_ok_button().disabled = true

func _open_button_clicked() -> void:
var __file_dialog := _get_file_dialog()
__file_dialog.current_dir = ""
__file_dialog.file_mode = EditorFileDialog.FILE_MODE_SAVE_FILE
__file_dialog.filters = ["*.tres, *.res ; Resource file"]
__file_dialog.title = "Save Template"
__file_dialog.popup_centered_ratio(0.5)

func _editor_file_dialog_file_selected(path:String) -> void:
path_line_edit.text_changed.emit(path)
path_line_edit.text = path

func _path_line_edit_text_changed(new_string:String) -> void:
if not new_string.is_absolute_path():
warning_label.text = "Not valid path."
get_ok_button().disabled = true
return

if ResourceLoader.exists(new_string):
warning_label.text = "A resource exists at the given path."
else:
warning_label.text = ""

get_ok_button().disabled = false

func _get_file_dialog() -> ConfirmationDialog:
if Engine.is_editor_hint():
return _editor_file_dialog
return _file_dialog

func _notification(what: int) -> void:
match what:
NOTIFICATION_VISIBILITY_CHANGED:
_clean()

if not visible:
current_command = null

func _init() -> void:
unresizable = true
popup_window = true
get_ok_button().pressed.connect(_confirm)

var p_bg := PanelContainer.new()
p_bg.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
add_child(p_bg, false, Node.INTERNAL_MODE_BACK)

var main_vb := VBoxContainer.new()
p_bg.add_child(main_vb, false, Node.INTERNAL_MODE_BACK)

var preview_vb := VBoxContainer.new()
main_vb.add_child(preview_vb, false, Node.INTERNAL_MODE_BACK)

preview_desc_label = Label.new()
preview_desc_label.text = PREVIEW_DESCRIPTION
preview_vb.add_child(preview_desc_label, false, Node.INTERNAL_MODE_BACK)

var collection_displayer := Tree.new()
collection_displayer.custom_minimum_size = Vector2i(256, 128)
preview_vb.add_child(collection_displayer, false, Node.INTERNAL_MODE_BACK)

var separator := HSeparator.new()
main_vb.add_child(separator, false, Node.INTERNAL_MODE_BACK)

var path_vb := VBoxContainer.new()
path_vb.size_flags_vertical = Control.SIZE_EXPAND_FILL
main_vb.add_child(path_vb, false, Node.INTERNAL_MODE_BACK)

var path_desc := Label.new()
path_desc.text = PATH_DESCRIPTION
path_vb.add_child(path_desc, false, Node.INTERNAL_MODE_BACK)

var hb := HBoxContainer.new()
hb.size_flags_horizontal = Control.SIZE_EXPAND_FILL
path_vb.add_child(hb, false, Node.INTERNAL_MODE_BACK)

path_line_edit = LineEdit.new()
path_line_edit.placeholder_text = "res://"
path_line_edit.size_flags_horizontal = Control.SIZE_EXPAND_FILL
path_line_edit.text_changed.connect(_path_line_edit_text_changed)
hb.add_child(path_line_edit, false, Node.INTERNAL_MODE_BACK)

var open_btn := Button.new()
open_btn.text = "Select..."
open_btn.pressed.connect(_open_button_clicked)
hb.add_child(open_btn, false, Node.INTERNAL_MODE_BACK)

warning_label = Button.new()
warning_label.text = ""
warning_label.disabled = true
warning_label.focus_mode = Control.FOCUS_NONE
path_vb.add_child(warning_label, false, Node.INTERNAL_MODE_BACK)

var note_label := Label.new()
note_label.text = NOTE_DESCRIPTION
note_label.size_flags_vertical = Control.SIZE_SHRINK_END
main_vb.add_child(note_label, false, Node.INTERNAL_MODE_BACK)

if Engine.is_editor_hint():
# https://github.com/godotengine/godot/issues/73525#issuecomment-1606067249
_editor_file_dialog = (EditorFileDialog as Variant).new()
_editor_file_dialog.file_selected.connect(_editor_file_dialog_file_selected)
add_child(_editor_file_dialog)
else:
_file_dialog = FileDialog.new()
_file_dialog.file_selected.connect(_editor_file_dialog_file_selected)
add_child(_file_dialog)

0 comments on commit 7cec64f

Please sign in to comment.