init
This commit is contained in:
commit
b99855351d
434 changed files with 50357 additions and 0 deletions
57
addons/inkgd/editor/panel/common/ink_progress_dialog.gd
Normal file
57
addons/inkgd/editor/panel/common/ink_progress_dialog.gd
Normal file
|
@ -0,0 +1,57 @@
|
|||
@tool
|
||||
# ############################################################################ #
|
||||
# Copyright © 2019-2022 Frédéric Maquin <fred@ephread.com>
|
||||
# Licensed under the MIT License.
|
||||
# See LICENSE in the project root for license information.
|
||||
# ############################################################################ #
|
||||
|
||||
extends Popup
|
||||
|
||||
# A custom dialog showing a progress bar.
|
||||
|
||||
# Hiding this type to prevent registration of "private" nodes.
|
||||
# See https://github.com/godotengine/godot-proposals/issues/1047
|
||||
# class_name InkProgressDialog
|
||||
|
||||
# ############################################################################ #
|
||||
# Nodes
|
||||
# ############################################################################ #
|
||||
|
||||
@onready var _margin_container = $MarginContainer
|
||||
@onready var _vbox_container = $MarginContainer/VBoxContainer
|
||||
@onready var _title_label = $MarginContainer/VBoxContainer/TitleLabel
|
||||
@onready var _progress_bar = $MarginContainer/VBoxContainer/ProgressBar
|
||||
@onready var _current_step_label = $MarginContainer/VBoxContainer/CurrentStepLabel
|
||||
|
||||
# ############################################################################ #
|
||||
# Properties
|
||||
# ############################################################################ #
|
||||
|
||||
## The title of the progress.
|
||||
var progress_title: String: get = get_progress_title, set = set_progress_title
|
||||
func set_progress_title(text: String):
|
||||
_title_label.text = text
|
||||
func get_progress_title() -> String:
|
||||
return _title_label.text
|
||||
|
||||
## The name of the current step.
|
||||
var current_step_name: String: get = get_current_step_name, set = set_current_step_name
|
||||
func set_current_step_name(text: String):
|
||||
_current_step_label.text = text
|
||||
func get_current_step_name() -> String:
|
||||
return _current_step_label.text
|
||||
|
||||
## The current progress.
|
||||
var progress: float:
|
||||
get:
|
||||
return _progress_bar.value
|
||||
set(value):
|
||||
_progress_bar.value = value
|
||||
|
||||
|
||||
func update_layout(scale: float) -> void:
|
||||
_margin_container.add_theme_constant_override("offset_right", 10 * scale)
|
||||
_margin_container.add_theme_constant_override("offset_top", 10 * scale)
|
||||
_margin_container.add_theme_constant_override("offset_left", 10 * scale)
|
||||
_margin_container.add_theme_constant_override("offset_bottom", 10 * scale)
|
||||
_vbox_container.add_theme_constant_override("separation", 5 * scale)
|
63
addons/inkgd/editor/panel/common/ink_progress_dialog.tscn
Normal file
63
addons/inkgd/editor/panel/common/ink_progress_dialog.tscn
Normal file
|
@ -0,0 +1,63 @@
|
|||
[gd_scene load_steps=2 format=2]
|
||||
|
||||
[ext_resource path="res://addons/inkgd/editor/panel/common/ink_progress_dialog.gd" type="Script" id=1]
|
||||
|
||||
[node name="InkProgressDialog" type="Popup"]
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -250.0
|
||||
offset_top = -42.5
|
||||
offset_right = 250.0
|
||||
offset_bottom = 42.5
|
||||
custom_minimum_size = Vector2( 500, 85 )
|
||||
script = ExtResource( 1 )
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="MarginContainer" type="MarginContainer" parent="."]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
theme_override_constants/margin_right = 10
|
||||
theme_override_constants/margin_top = 10
|
||||
theme_override_constants/margin_left = 10
|
||||
theme_override_constants/margin_bottom = 10
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="MarginContainer"]
|
||||
offset_left = 10.0
|
||||
offset_top = 10.0
|
||||
offset_right = 490.0
|
||||
offset_bottom = 75.0
|
||||
theme_override_constants/separation = 5
|
||||
alignment = 1
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="TitleLabel" type="Label" parent="MarginContainer/VBoxContainer"]
|
||||
offset_top = 1.0
|
||||
offset_right = 480.0
|
||||
offset_bottom = 15.0
|
||||
text = "Compiling..."
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="ProgressBar" type="ProgressBar" parent="MarginContainer/VBoxContainer"]
|
||||
offset_top = 25.0
|
||||
offset_right = 480.0
|
||||
offset_bottom = 39.0
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="CurrentStepLabel" type="Label" parent="MarginContainer/VBoxContainer"]
|
||||
offset_top = 49.0
|
||||
offset_right = 480.0
|
||||
offset_bottom = 63.0
|
||||
text = "the_intercept.ink"
|
103
addons/inkgd/editor/panel/common/ink_rich_dialog.gd
Normal file
103
addons/inkgd/editor/panel/common/ink_rich_dialog.gd
Normal file
|
@ -0,0 +1,103 @@
|
|||
@tool
|
||||
# ############################################################################ #
|
||||
# Copyright © 2019-2022 Frédéric Maquin <fred@ephread.com>
|
||||
# Licensed under the MIT License.
|
||||
# See LICENSE in the project root for license information.
|
||||
# ############################################################################ #
|
||||
|
||||
extends Window
|
||||
|
||||
# A custom dialog showing a message and, optionally, a command output.
|
||||
|
||||
# Hiding this type to prevent registration of "private" nodes.
|
||||
# See https://github.com/godotengine/godot-proposals/issues/1047
|
||||
# class_name InkRichDialog
|
||||
|
||||
# ############################################################################ #
|
||||
# Nodes
|
||||
# ############################################################################ #
|
||||
|
||||
@onready var _margin_container = $MarginContainer
|
||||
@onready var _vbox_container = $MarginContainer/VBoxContainer
|
||||
@onready var _message_label = $MarginContainer/VBoxContainer/MessageLabel
|
||||
@onready var _accept_button = $MarginContainer/VBoxContainer/AcceptButton
|
||||
@onready var _output_panel = $MarginContainer/VBoxContainer/OutputPanel
|
||||
@onready var _output_label = find_child("OutputLabel")
|
||||
|
||||
# ############################################################################ #
|
||||
# Properties
|
||||
# ############################################################################ #
|
||||
|
||||
## The message displayed in the dialog.
|
||||
var message_text: String: get = get_message_text, set = set_message_text
|
||||
func set_message_text(text: String):
|
||||
_message_label.text = text
|
||||
func get_message_text() -> String:
|
||||
return _message_label.text
|
||||
|
||||
## An output, often the result of a command, than can optionally be displayed
|
||||
## in the dialog.
|
||||
##
|
||||
## Setting this property to null hides the corresponding panel in the dialog.
|
||||
var output_text: String: get = get_output_text, set = set_output_text
|
||||
func set_output_text(text: String):
|
||||
_output_label.text = text
|
||||
_output_label.visible = !(text == null || text.length() == 0)
|
||||
func get_output_text() -> String:
|
||||
return _output_label.text
|
||||
|
||||
# ############################################################################ #
|
||||
# Overriden Methods
|
||||
# ############################################################################ #
|
||||
|
||||
func _ready():
|
||||
_accept_button.connect("pressed", Callable(self, "_accept_button_pressed"))
|
||||
|
||||
var font = _get_source_font()
|
||||
if font != null:
|
||||
_output_panel.add_theme_font_override("font", font)
|
||||
|
||||
# ############################################################################ #
|
||||
# Methods
|
||||
# ############################################################################ #
|
||||
|
||||
func update_layout(scale: float) -> void:
|
||||
_margin_container.add_theme_constant_override("offset_right", 10 * scale)
|
||||
_margin_container.add_theme_constant_override("offset_top", 10 * scale)
|
||||
_margin_container.add_theme_constant_override("offset_left", 10 * scale)
|
||||
_margin_container.add_theme_constant_override("offset_bottom", 10 * scale)
|
||||
_vbox_container.add_theme_constant_override("separation", 10 * scale)
|
||||
|
||||
|
||||
# ############################################################################ #
|
||||
# Signal Receivers
|
||||
# ############################################################################ #
|
||||
|
||||
func _accept_button_pressed():
|
||||
self.get_parent().remove_child(self)
|
||||
self.queue_free()
|
||||
|
||||
# ############################################################################ #
|
||||
# Private helpers
|
||||
# ############################################################################ #
|
||||
|
||||
## Gets the monospaced font used by the editor.
|
||||
func _get_source_font():
|
||||
var base_theme = _retrieve_base_theme()
|
||||
if base_theme:
|
||||
return base_theme.get_font("output_source", "EditorFonts")
|
||||
else:
|
||||
return null
|
||||
|
||||
## Gets the theme currently used by the editor.
|
||||
func _retrieve_base_theme():
|
||||
var parent = self
|
||||
|
||||
while(parent != null && parent.theme == null):
|
||||
var older_parent = parent.get_parent()
|
||||
if older_parent is Control:
|
||||
parent = older_parent
|
||||
else:
|
||||
break
|
||||
|
||||
return parent.theme
|
89
addons/inkgd/editor/panel/common/ink_rich_dialog.tscn
Normal file
89
addons/inkgd/editor/panel/common/ink_rich_dialog.tscn
Normal file
|
@ -0,0 +1,89 @@
|
|||
[gd_scene load_steps=2 format=2]
|
||||
|
||||
[ext_resource path="res://addons/inkgd/editor/panel/common/ink_rich_dialog.gd" type="Script" id=1]
|
||||
|
||||
[node name="Window" type="Window"]
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -250.0
|
||||
offset_top = -150.0
|
||||
offset_right = 250.0
|
||||
offset_bottom = 150.0
|
||||
custom_minimum_size = Vector2( 500, 300 )
|
||||
window_title = "Error"
|
||||
resizable = true
|
||||
script = ExtResource( 1 )
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="MarginContainer" type="MarginContainer" parent="."]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 3
|
||||
theme_override_constants/margin_right = 10
|
||||
theme_override_constants/margin_top = 10
|
||||
theme_override_constants/margin_left = 10
|
||||
theme_override_constants/margin_bottom = 10
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="MarginContainer"]
|
||||
offset_left = 10.0
|
||||
offset_top = 10.0
|
||||
offset_right = 490.0
|
||||
offset_bottom = 290.0
|
||||
theme_override_constants/separation = 10
|
||||
|
||||
[node name="MessageLabel" type="Label" parent="MarginContainer/VBoxContainer"]
|
||||
offset_right = 480.0
|
||||
offset_bottom = 31.0
|
||||
text = "Something went wrong while testing inklecate's setup. Please see the output below."
|
||||
autowrap = true
|
||||
|
||||
[node name="OutputPanel" type="Panel" parent="MarginContainer/VBoxContainer"]
|
||||
offset_top = 41.0
|
||||
offset_right = 480.0
|
||||
offset_bottom = 250.0
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 3
|
||||
|
||||
[node name="OutputScrollContainer" type="ScrollContainer" parent="MarginContainer/VBoxContainer/OutputPanel"]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="OutputMarginContainer" type="MarginContainer" parent="MarginContainer/VBoxContainer/OutputPanel/OutputScrollContainer"]
|
||||
offset_right = 480.0
|
||||
offset_bottom = 136.0
|
||||
size_flags_horizontal = 3
|
||||
theme_override_constants/margin_right = 10
|
||||
theme_override_constants/margin_top = 10
|
||||
theme_override_constants/margin_left = 10
|
||||
theme_override_constants/margin_bottom = 10
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="OutputLabel" type="Label" parent="MarginContainer/VBoxContainer/OutputPanel/OutputScrollContainer/OutputMarginContainer"]
|
||||
offset_left = 10.0
|
||||
offset_top = 10.0
|
||||
offset_right = 470.0
|
||||
offset_bottom = 126.0
|
||||
size_flags_vertical = 0
|
||||
text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
|
||||
autowrap = true
|
||||
|
||||
[node name="AcceptButton" type="Button" parent="MarginContainer/VBoxContainer"]
|
||||
offset_left = 224.0
|
||||
offset_top = 260.0
|
||||
offset_right = 255.0
|
||||
offset_bottom = 280.0
|
||||
size_flags_horizontal = 4
|
||||
text = "OK"
|
|
@ -0,0 +1,306 @@
|
|||
@tool
|
||||
# ############################################################################ #
|
||||
# Copyright © 2019-2022 Frédéric Maquin <fred@ephread.com>
|
||||
# Licensed under the MIT License.
|
||||
# See LICENSE in the project root for license information.
|
||||
# ############################################################################ #
|
||||
|
||||
extends Control
|
||||
|
||||
# Hiding this type to prevent registration of "private" nodes.
|
||||
# See https://github.com/godotengine/godot-proposals/issues/1047
|
||||
# class_name InkConfigurationPanel
|
||||
|
||||
# ############################################################################ #
|
||||
# Imports
|
||||
# ############################################################################ #
|
||||
|
||||
var InkExecutionConfiguration = load("res://addons/inkgd/editor/common/executors/structures/ink_execution_configuration.gd")
|
||||
var InkConfigurationTester = load("res://addons/inkgd/editor/common/executors/ink_configuration_tester.gd")
|
||||
|
||||
var InkCSharpValidator = preload("res://addons/inkgd/editor/common/ink_csharp_validator.gd")
|
||||
|
||||
var InkRichDialog = load("res://addons/inkgd/editor/panel/common/ink_rich_dialog.tscn")
|
||||
|
||||
|
||||
# ############################################################################ #
|
||||
# Enums
|
||||
# ############################################################################ #
|
||||
|
||||
## Represents which configuration setting triggered the file dialog.
|
||||
enum FileDialogSelection {
|
||||
UNKNOWN,
|
||||
MONO_EXECUTABLE,
|
||||
INKLECATE_EXECUTABLE
|
||||
}
|
||||
|
||||
|
||||
# ############################################################################ #
|
||||
# Constants
|
||||
# ############################################################################ #
|
||||
|
||||
const BOM = "\ufeff"
|
||||
|
||||
|
||||
# ############################################################################ #
|
||||
# Properties
|
||||
# ############################################################################ #
|
||||
|
||||
var editor_interface: InkEditorInterface = null
|
||||
var configuration: InkConfiguration = null
|
||||
|
||||
|
||||
# ############################################################################ #
|
||||
# Private Properties
|
||||
# ############################################################################ #
|
||||
|
||||
var _file_dialog = EditorFileDialog.new()
|
||||
|
||||
## Configuration item for which the FileDialog is currently shown.
|
||||
##
|
||||
## Unknown by default.
|
||||
var _file_dialog_selection = FileDialogSelection.UNKNOWN
|
||||
|
||||
|
||||
# ############################################################################ #
|
||||
# Nodes
|
||||
# ############################################################################ #
|
||||
|
||||
@onready var _test_button = find_child("TestButton")
|
||||
|
||||
@onready var _use_mono_label = find_child("UseMonoLabel")
|
||||
@onready var _use_mono_checkbox = find_child("UseMonoCheckBox")
|
||||
|
||||
@onready var _mono_label = find_child("MonoLabel")
|
||||
@onready var _mono_container = find_child("MonoH")
|
||||
@onready var _mono_line_edit = find_child("MonoLineEdit")
|
||||
@onready var _mono_dialog_button = find_child("MonoDialogButton")
|
||||
|
||||
@onready var _executable_line_edit = find_child("ExecutableLineEdit")
|
||||
@onready var _executable_dialog_button = find_child("ExecutableDialogButton")
|
||||
|
||||
@onready var _recompilation_mode_button = find_child("RecompilationModeOptionButton")
|
||||
|
||||
@onready var _mono_support_container = find_child("MonoSupportV")
|
||||
@onready var _mono_support_documentation_button = find_child("DocumentationButton")
|
||||
@onready var _mono_support_presence_label = _mono_support_container.find_child("PresenceLabel")
|
||||
@onready var _mono_support_refresh_button = _mono_support_container.find_child("RefreshButton")
|
||||
|
||||
|
||||
# ############################################################################ #
|
||||
# Overrides
|
||||
# ############################################################################ #
|
||||
|
||||
func _ready():
|
||||
# FIXME: This needs investigating.
|
||||
# Sanity check. It seems the editor instantiates tools script on their
|
||||
# own, probably to add them to its tree. In that case, they won't have
|
||||
# their dependencies injected, so we're not doing anything.
|
||||
if editor_interface == null || configuration == null:
|
||||
print("[inkgd] [INFO] Ink Configuration Tab: dependencies not met, ignoring.")
|
||||
return
|
||||
|
||||
_set_button_icons()
|
||||
_apply_configuration()
|
||||
_connect_signals()
|
||||
_check_runtime_presence()
|
||||
|
||||
_mono_support_container.visible = _can_run_mono()
|
||||
|
||||
add_child(_file_dialog)
|
||||
|
||||
|
||||
# ############################################################################ #
|
||||
# Signal Receivers
|
||||
# ############################################################################ #
|
||||
|
||||
func _configuration_entered(_new_text: String):
|
||||
_configuration_focus_exited()
|
||||
|
||||
|
||||
func _configuration_focus_exited():
|
||||
configuration.mono_path = _mono_line_edit.text
|
||||
configuration.inklecate_path = _executable_line_edit.text
|
||||
|
||||
configuration.persist()
|
||||
|
||||
|
||||
func _use_mono_toggled(_toggled: bool):
|
||||
configuration.use_mono = !configuration.use_mono
|
||||
configuration.persist()
|
||||
|
||||
_update_mono_availability(false)
|
||||
|
||||
|
||||
func _mono_button_pressed():
|
||||
_reset_file_dialog()
|
||||
|
||||
_file_dialog_selection = FileDialogSelection.MONO_EXECUTABLE
|
||||
_file_dialog.current_path = configuration.mono_path
|
||||
_file_dialog.current_dir = configuration.mono_path.get_base_dir()
|
||||
_file_dialog.current_file = configuration.mono_path.get_file()
|
||||
_file_dialog.file_mode = FileDialog.FILE_MODE_OPEN_FILE
|
||||
_file_dialog.access = FileDialog.ACCESS_FILESYSTEM
|
||||
_file_dialog.popup_centered(Vector2(1280, 800) * editor_interface.scale)
|
||||
|
||||
|
||||
func _executable_button_pressed():
|
||||
_reset_file_dialog()
|
||||
|
||||
_file_dialog_selection = FileDialogSelection.INKLECATE_EXECUTABLE
|
||||
_file_dialog.current_file = configuration.inklecate_path
|
||||
_file_dialog.current_dir = configuration.inklecate_path.get_base_dir()
|
||||
_file_dialog.current_file = configuration.inklecate_path.get_file()
|
||||
_file_dialog.file_mode = FileDialog.FILE_MODE_OPEN_FILE
|
||||
_file_dialog.access = FileDialog.ACCESS_FILESYSTEM
|
||||
_file_dialog.popup_centered(Vector2(1280, 800) * editor_interface.scale)
|
||||
|
||||
|
||||
func _recompilation_mode_button_selected(index):
|
||||
configuration.compilation_mode = index
|
||||
configuration.persist()
|
||||
|
||||
|
||||
func _test_button_pressed():
|
||||
var test_configuration = InkExecutionConfiguration.new(configuration, false, true)
|
||||
var tester = InkConfigurationTester.new(test_configuration)
|
||||
|
||||
var result = tester.test_availability()
|
||||
|
||||
# NOTE: At the moment, inklecate doesn't support a subcommand that would just
|
||||
# exit with 0 so `_contains_inklecate_output_prefix` will always be executed.
|
||||
if result.success:
|
||||
var dialog = AcceptDialog.new()
|
||||
add_child(dialog)
|
||||
|
||||
dialog.title = "Success"
|
||||
dialog.dialog_text = "The configuration seems to be valid!"
|
||||
|
||||
dialog.popup_centered()
|
||||
else:
|
||||
var dialog = InkRichDialog.instantiate()
|
||||
add_child(dialog)
|
||||
|
||||
|
||||
dialog.title = "Error"
|
||||
dialog.message_text = "Something went wrong while testing inklecate's setup. Please see the output below."
|
||||
dialog.output_text = result.output
|
||||
dialog.update_layout(editor_interface.scale)
|
||||
|
||||
dialog.popup_centered(Vector2(700, 400) * editor_interface.scale)
|
||||
|
||||
|
||||
func _on_file_selected(path: String):
|
||||
match _file_dialog_selection:
|
||||
FileDialogSelection.MONO_EXECUTABLE:
|
||||
configuration.mono_path = ProjectSettings.globalize_path(path)
|
||||
_update_save_and_cleanup(configuration.mono_path, _mono_line_edit)
|
||||
|
||||
FileDialogSelection.INKLECATE_EXECUTABLE:
|
||||
configuration.inklecate_path = ProjectSettings.globalize_path(path)
|
||||
_update_save_and_cleanup(configuration.inklecate_path, _executable_line_edit)
|
||||
|
||||
_:
|
||||
printerr("[inkgd] [ERROR] Unknown FileDialogSelection, failed to save FileDialog file.")
|
||||
|
||||
_file_dialog_selection = FileDialogSelection.UNKNOWN
|
||||
|
||||
|
||||
func _check_runtime_presence():
|
||||
var ink_engine_runtime = InkCSharpValidator.new().get_runtime_path()
|
||||
var is_present = !ink_engine_runtime.is_empty()
|
||||
|
||||
if is_present:
|
||||
_mono_support_presence_label.add_theme_color_override("font_color", Color.GREEN)
|
||||
_mono_support_presence_label.text = "PRESENT"
|
||||
else:
|
||||
_mono_support_presence_label.add_theme_color_override("font_color", Color.RED)
|
||||
_mono_support_presence_label.text = "MISSING"
|
||||
|
||||
|
||||
func _mono_support_documentation_pressed():
|
||||
OS.shell_open("https://inkgd.readthedocs.io/en/latest/advanced/migrating_to_godot_mono.html")
|
||||
|
||||
|
||||
# ############################################################################ #
|
||||
# Private helpers
|
||||
# ############################################################################ #
|
||||
|
||||
func _reset_file_dialog():
|
||||
_file_dialog.current_file = ""
|
||||
_file_dialog.clear_filters()
|
||||
|
||||
|
||||
func _update_save_and_cleanup(value, line_edit):
|
||||
line_edit.text = value
|
||||
line_edit.queue_redraw()
|
||||
|
||||
configuration.persist()
|
||||
|
||||
|
||||
func _apply_configuration():
|
||||
var compilation_mode = configuration.compilation_mode
|
||||
var item_count = _recompilation_mode_button.get_item_count()
|
||||
|
||||
if compilation_mode >= 0 && compilation_mode < item_count:
|
||||
_recompilation_mode_button.select(configuration.compilation_mode)
|
||||
else:
|
||||
_recompilation_mode_button.select(0)
|
||||
|
||||
_mono_line_edit.text = configuration.mono_path
|
||||
_executable_line_edit.text = configuration.inklecate_path
|
||||
|
||||
_update_mono_availability(true)
|
||||
|
||||
|
||||
func _update_mono_availability(updates_checkbox: bool = false):
|
||||
var is_running_on_windows: bool = editor_interface.is_running_on_windows
|
||||
var is_control_visible: bool = !is_running_on_windows && configuration.use_mono
|
||||
|
||||
_use_mono_label.visible = !is_running_on_windows
|
||||
_use_mono_checkbox.visible = !is_running_on_windows
|
||||
|
||||
_mono_label.visible = is_control_visible
|
||||
_mono_container.visible = is_control_visible
|
||||
|
||||
if updates_checkbox:
|
||||
_use_mono_checkbox.set_pressed(configuration.use_mono)
|
||||
|
||||
|
||||
func _set_button_icons():
|
||||
var folder_icon = get_theme_icon("Folder", "EditorIcons")
|
||||
var reload_icon = get_theme_icon("Reload", "EditorIcons")
|
||||
var instance_icon = get_theme_icon("Instance", "EditorIcons")
|
||||
|
||||
_mono_dialog_button.icon = folder_icon
|
||||
_executable_dialog_button.icon = folder_icon
|
||||
|
||||
_mono_support_documentation_button.icon = instance_icon
|
||||
_mono_support_refresh_button.icon = reload_icon
|
||||
|
||||
|
||||
func _connect_signals():
|
||||
editor_interface.editor_filesystem.connect("filesystem_changed", Callable(self, "_check_runtime_presence"))
|
||||
|
||||
_test_button.connect("pressed", Callable(self, "_test_button_pressed"))
|
||||
_use_mono_checkbox.connect("toggled", Callable(self, "_use_mono_toggled"))
|
||||
|
||||
_mono_line_edit.connect("text_submitted", Callable(self, "_configuration_entered"))
|
||||
_executable_line_edit.connect("text_submitted", Callable(self, "_configuration_entered"))
|
||||
|
||||
_mono_line_edit.connect("focus_exited", Callable(self, "_configuration_focus_exited"))
|
||||
_executable_line_edit.connect("focus_exited", Callable(self, "_configuration_focus_exited"))
|
||||
|
||||
_mono_dialog_button.connect("pressed", Callable(self, "_mono_button_pressed"))
|
||||
_executable_dialog_button.connect("pressed", Callable(self, "_executable_button_pressed"))
|
||||
|
||||
_recompilation_mode_button.connect("item_selected", Callable(self, "_recompilation_mode_button_selected"))
|
||||
|
||||
_mono_support_documentation_button.connect("pressed", Callable(self, "_mono_support_documentation_pressed"))
|
||||
_mono_support_refresh_button.connect("pressed", Callable(self, "_check_runtime_presence"))
|
||||
|
||||
_file_dialog.connect("file_selected", Callable(self, "_on_file_selected"))
|
||||
|
||||
|
||||
func _can_run_mono():
|
||||
return type_exists("_GodotSharp")
|
|
@ -0,0 +1,258 @@
|
|||
[gd_scene load_steps=6 format=3 uid="uid://cbuep470x6krw"]
|
||||
|
||||
[ext_resource type="Script" path="res://addons/inkgd/editor/panel/configuration/ink_configuration_panel.gd" id="1"]
|
||||
|
||||
[sub_resource type="Image" id="Image_h71nq"]
|
||||
data = {
|
||||
"data": PackedByteArray(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
|
||||
"format": "LumAlpha8",
|
||||
"height": 16,
|
||||
"mipmaps": false,
|
||||
"width": 16
|
||||
}
|
||||
|
||||
[sub_resource type="ImageTexture" id="7"]
|
||||
image = SubResource("Image_h71nq")
|
||||
|
||||
[sub_resource type="Image" id="Image_e0kbj"]
|
||||
data = {
|
||||
"data": PackedByteArray(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
|
||||
"format": "LumAlpha8",
|
||||
"height": 16,
|
||||
"mipmaps": false,
|
||||
"width": 16
|
||||
}
|
||||
|
||||
[sub_resource type="ImageTexture" id="5"]
|
||||
image = SubResource("Image_e0kbj")
|
||||
|
||||
[node name="Configuration" type="Control"]
|
||||
layout_mode = 3
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
script = ExtResource("1")
|
||||
|
||||
[node name="ScrollContainer" type="ScrollContainer" parent="."]
|
||||
layout_mode = 0
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
pivot_offset = Vector2(1346, -25)
|
||||
|
||||
[node name="V" type="VBoxContainer" parent="ScrollContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
theme_override_constants/separation = 25
|
||||
|
||||
[node name="InklecateV" type="VBoxContainer" parent="ScrollContainer/V"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="H" type="HBoxContainer" parent="ScrollContainer/V/InklecateV"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Label" type="Label" parent="ScrollContainer/V/InklecateV/H"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
text = "Inklecate"
|
||||
|
||||
[node name="TestButton" type="Button" parent="ScrollContainer/V/InklecateV/H"]
|
||||
layout_mode = 2
|
||||
mouse_filter = 1
|
||||
text = "Test configuration"
|
||||
|
||||
[node name="M" type="MarginContainer" parent="ScrollContainer/V/InklecateV"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Panel" type="Panel" parent="ScrollContainer/V/InklecateV/M"]
|
||||
self_modulate = Color(1, 1, 1, 0.686275)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="M" type="MarginContainer" parent="ScrollContainer/V/InklecateV/M"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 3
|
||||
theme_override_constants/margin_left = 5
|
||||
theme_override_constants/margin_top = 5
|
||||
theme_override_constants/margin_right = 5
|
||||
theme_override_constants/margin_bottom = 5
|
||||
|
||||
[node name="V" type="VBoxContainer" parent="ScrollContainer/V/InklecateV/M/M"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="G" type="GridContainer" parent="ScrollContainer/V/InklecateV/M/M/V"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
columns = 2
|
||||
|
||||
[node name="UseMonoLabel" type="Label" parent="ScrollContainer/V/InklecateV/M/M/V/G"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 1
|
||||
tooltip_text = "When toggled, run inklecate through Mono.
|
||||
|
||||
Only enable this setting is you want to use an older version of inklecate or you have a custom setup.
|
||||
Modern versions of inklecate come bundled with a mono runtime on all platforms."
|
||||
mouse_filter = 1
|
||||
text = "Use Mono / .NET Core"
|
||||
|
||||
[node name="UseMonoCheckBox" type="CheckBox" parent="ScrollContainer/V/InklecateV/M/M/V/G"]
|
||||
layout_mode = 2
|
||||
text = "Yes"
|
||||
|
||||
[node name="MonoLabel" type="Label" parent="ScrollContainer/V/InklecateV/M/M/V/G"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 1
|
||||
tooltip_text = "The path to Mono."
|
||||
mouse_filter = 1
|
||||
text = "Mono / .NET Core Executable"
|
||||
|
||||
[node name="MonoH" type="HBoxContainer" parent="ScrollContainer/V/InklecateV/M/M/V/G"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="MonoLineEdit" type="LineEdit" parent="ScrollContainer/V/InklecateV/M/M/V/G/MonoH"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
text = "/Library/Frameworks/Mono.framework/Versions/Current/Commands/mono"
|
||||
|
||||
[node name="MonoDialogButton" type="Button" parent="ScrollContainer/V/InklecateV/M/M/V/G/MonoH"]
|
||||
layout_mode = 2
|
||||
icon = SubResource("7")
|
||||
|
||||
[node name="ExecutableLabel" type="Label" parent="ScrollContainer/V/InklecateV/M/M/V/G"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 1
|
||||
tooltip_text = "The path to inklecate."
|
||||
mouse_filter = 1
|
||||
text = "Executable"
|
||||
|
||||
[node name="ExecutableH" type="HBoxContainer" parent="ScrollContainer/V/InklecateV/M/M/V/G"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="ExecutableLineEdit" type="LineEdit" parent="ScrollContainer/V/InklecateV/M/M/V/G/ExecutableH"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
text = "/opt/homebrew/bin/inklecate"
|
||||
|
||||
[node name="ExecutableDialogButton" type="Button" parent="ScrollContainer/V/InklecateV/M/M/V/G/ExecutableH"]
|
||||
layout_mode = 2
|
||||
icon = SubResource("7")
|
||||
|
||||
[node name="Recompilation Mode" type="Label" parent="ScrollContainer/V/InklecateV/M/M/V/G"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 1
|
||||
tooltip_text = "Define if/when your stories should be recompiled.
|
||||
|
||||
– Manual: no automatic compilation.
|
||||
– During Build: every time the project is built/ran, the stories will be recompiled.
|
||||
– On change: as soon as an Ink resource is reimported by Godot, trigger a recompilation. A folder to watch can be defined in the \"Story\" tab."
|
||||
mouse_filter = 1
|
||||
text = "Recompilation Mode"
|
||||
|
||||
[node name="RecompilationModeOptionButton" type="OptionButton" parent="ScrollContainer/V/InklecateV/M/M/V/G"]
|
||||
layout_mode = 2
|
||||
item_count = 3
|
||||
selected = 0
|
||||
popup/item_0/text = "Manual"
|
||||
popup/item_0/id = 0
|
||||
popup/item_1/text = "During Build"
|
||||
popup/item_1/id = 1
|
||||
popup/item_2/text = "On change (experimental)"
|
||||
popup/item_2/id = 2
|
||||
|
||||
[node name="InkDirectoryLabel" type="Label" parent="ScrollContainer/V/InklecateV/M/M/V/G"]
|
||||
visible = false
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 1
|
||||
tooltip_text = "The path to Mono."
|
||||
mouse_filter = 1
|
||||
text = "Mono"
|
||||
|
||||
[node name="InkDirectoryH" type="HBoxContainer" parent="ScrollContainer/V/InklecateV/M/M/V/G"]
|
||||
visible = false
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="InkDirectoryLineEdit" type="LineEdit" parent="ScrollContainer/V/InklecateV/M/M/V/G/InkDirectoryH"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="InkDIrectoryDialogButton" type="Button" parent="ScrollContainer/V/InklecateV/M/M/V/G/InkDirectoryH"]
|
||||
layout_mode = 2
|
||||
icon = SubResource("5")
|
||||
|
||||
[node name="MonoSupportV" type="VBoxContainer" parent="ScrollContainer/V"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="H" type="HBoxContainer" parent="ScrollContainer/V/MonoSupportV"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Label" type="Label" parent="ScrollContainer/V/MonoSupportV/H"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
text = "Mono Support"
|
||||
|
||||
[node name="DocumentationButton" type="Button" parent="ScrollContainer/V/MonoSupportV/H"]
|
||||
layout_mode = 2
|
||||
mouse_filter = 1
|
||||
theme_override_constants/h_separation = 8
|
||||
text = "Documentation"
|
||||
|
||||
[node name="M" type="MarginContainer" parent="ScrollContainer/V/MonoSupportV"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Panel" type="Panel" parent="ScrollContainer/V/MonoSupportV/M"]
|
||||
self_modulate = Color(1, 1, 1, 0.686275)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="M" type="MarginContainer" parent="ScrollContainer/V/MonoSupportV/M"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 3
|
||||
theme_override_constants/margin_left = 5
|
||||
theme_override_constants/margin_top = 5
|
||||
theme_override_constants/margin_right = 5
|
||||
theme_override_constants/margin_bottom = 5
|
||||
|
||||
[node name="V" type="VBoxContainer" parent="ScrollContainer/V/MonoSupportV/M/M"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="G" type="GridContainer" parent="ScrollContainer/V/MonoSupportV/M/M/V"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
columns = 2
|
||||
|
||||
[node name="DLLLabel" type="Label" parent="ScrollContainer/V/MonoSupportV/M/M/V/G"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 1
|
||||
tooltip_text = "Whether the ink runtime DLL (ink-engine-runtime.dll) can be found in the project or not."
|
||||
mouse_filter = 1
|
||||
text = "ink DLL"
|
||||
|
||||
[node name="DLLH" type="HBoxContainer" parent="ScrollContainer/V/MonoSupportV/M/M/V/G"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="PresenceLabel" type="Label" parent="ScrollContainer/V/MonoSupportV/M/M/V/G/DLLH"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 1
|
||||
mouse_filter = 1
|
||||
theme_override_colors/font_color = Color(1, 0, 0, 1)
|
||||
text = "MISSING"
|
||||
|
||||
[node name="RefreshButton" type="Button" parent="ScrollContainer/V/MonoSupportV/M/M/V/G/DLLH"]
|
||||
layout_mode = 2
|
||||
theme_override_constants/h_separation = 8
|
||||
text = "Scan"
|
||||
icon = SubResource("7")
|
106
addons/inkgd/editor/panel/ink_bottom_panel.gd
Normal file
106
addons/inkgd/editor/panel/ink_bottom_panel.gd
Normal file
|
@ -0,0 +1,106 @@
|
|||
@tool
|
||||
# warning-ignore-all:return_value_discarded
|
||||
|
||||
# ############################################################################ #
|
||||
# Copyright © 2019-2022 Frédéric Maquin <fred@ephread.com>
|
||||
# Licensed under the MIT License.
|
||||
# See LICENSE in the project root for license information.
|
||||
# ############################################################################ #
|
||||
|
||||
extends Control
|
||||
|
||||
# Hiding this type to prevent registration of "private" nodes.
|
||||
# See https://github.com/godotengine/godot-proposals/issues/1047
|
||||
# class_name InkBottomPanel
|
||||
|
||||
# ############################################################################ #
|
||||
# Imports
|
||||
# ############################################################################ #
|
||||
|
||||
var InkStoryPanelScene = load("res://addons/inkgd/editor/panel/stories/ink_story_panel.tscn")
|
||||
var InkPreviewPanelScene = load("res://addons/inkgd/editor/panel/preview/ink_preview_panel.tscn")
|
||||
var InkConfigurationPanelScene = load("res://addons/inkgd/editor/panel/configuration/ink_configuration_panel.tscn")
|
||||
|
||||
# ############################################################################ #
|
||||
# Properties
|
||||
# ############################################################################ #
|
||||
|
||||
var editor_interface: InkEditorInterface = null
|
||||
var configuration: InkConfiguration = null
|
||||
|
||||
# ############################################################################ #
|
||||
# Private Properties
|
||||
# ############################################################################ #
|
||||
|
||||
var _progress_texture: AnimatedTexture
|
||||
|
||||
# ############################################################################ #
|
||||
# Hierarchy Nodes
|
||||
# ############################################################################ #
|
||||
|
||||
@onready var _tab_container: TabContainer = $TabContainer
|
||||
@onready var _beta_button: LinkButton = $MarginContainer/LinkButton
|
||||
|
||||
@onready var _story_panel = InkStoryPanelScene.instantiate()
|
||||
@onready var _preview_panel = InkPreviewPanelScene.instantiate()
|
||||
@onready var _configuration_panel = InkConfigurationPanelScene.instantiate()
|
||||
|
||||
# ############################################################################ #
|
||||
# Overrides
|
||||
# ############################################################################ #
|
||||
|
||||
func _ready():
|
||||
# FIXME: This needs investigating.
|
||||
# Sanity check. It seems the editor instantiates tools script on their
|
||||
# own, probably to add them to its tree. In that case, they won't have
|
||||
# their dependencies injected, so we're not doing anything.
|
||||
if editor_interface == null || configuration == null:
|
||||
print("[inkgd] [INFO] Ink Bottom Panel: dependencies not met, ignoring.")
|
||||
return
|
||||
|
||||
_progress_texture = _create_progress_texture()
|
||||
|
||||
_story_panel.editor_interface = editor_interface
|
||||
_story_panel.configuration = configuration
|
||||
_story_panel.progress_texture = _progress_texture
|
||||
|
||||
_preview_panel.editor_interface = editor_interface
|
||||
_preview_panel.configuration = configuration
|
||||
_preview_panel.progress_texture = _progress_texture
|
||||
|
||||
_configuration_panel.editor_interface = editor_interface
|
||||
_configuration_panel.configuration = configuration
|
||||
|
||||
_tab_container.add_child(_story_panel)
|
||||
_tab_container.add_child(_preview_panel)
|
||||
_tab_container.add_child(_configuration_panel)
|
||||
|
||||
_beta_button.connect("pressed", Callable(self, "_open_github_issues"))
|
||||
|
||||
_set_minimum_panel_size()
|
||||
|
||||
|
||||
# ############################################################################ #
|
||||
# Signals Receivers
|
||||
# ############################################################################ #
|
||||
|
||||
func _open_github_issues():
|
||||
OS.shell_open("https://github.com/ephread/inkgd/issues/new?assignees=&labels=&template=bug_report.md")
|
||||
|
||||
# ############################################################################ #
|
||||
# Private helpers
|
||||
# ############################################################################ #
|
||||
|
||||
func _create_progress_texture() -> AnimatedTexture:
|
||||
var animated_texture = AnimatedTexture.new()
|
||||
animated_texture.frames = 8
|
||||
|
||||
for index in range(8):
|
||||
var texture = get_theme_icon(str("Progress", (index + 1)), "EditorIcons")
|
||||
animated_texture.set_frame_texture(index, texture)
|
||||
|
||||
return animated_texture
|
||||
|
||||
func _set_minimum_panel_size():
|
||||
# Adapting the minimum size of the panel to the scale of the editor.
|
||||
custom_minimum_size = Vector2(900, 245) * editor_interface.scale
|
51
addons/inkgd/editor/panel/ink_bottom_panel.tscn
Normal file
51
addons/inkgd/editor/panel/ink_bottom_panel.tscn
Normal file
|
@ -0,0 +1,51 @@
|
|||
[gd_scene load_steps=2 format=2]
|
||||
|
||||
[ext_resource path="res://addons/inkgd/editor/panel/ink_bottom_panel.gd" type="Script" id=1]
|
||||
|
||||
[node name="Control" type="Control"]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
script = ExtResource( 1 )
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="TabContainer" type="TabContainer" parent="."]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
custom_minimum_size = Vector2( 0, 428.75 )
|
||||
size_flags_vertical = 3
|
||||
tab_alignment = 0
|
||||
drag_to_rearrange_enabled = true
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="MarginContainer" type="MarginContainer" parent="."]
|
||||
anchor_right = 1.0
|
||||
offset_bottom = 24.0
|
||||
clip_contents = true
|
||||
mouse_filter = 2
|
||||
size_flags_horizontal = 0
|
||||
size_flags_vertical = 0
|
||||
theme_override_constants/margin_right = 5
|
||||
theme_override_constants/margin_top = 5
|
||||
theme_override_constants/margin_left = 5
|
||||
theme_override_constants/margin_bottom = 5
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="LinkButton" type="LinkButton" parent="MarginContainer"]
|
||||
self_modulate = Color( 1, 1, 1, 0.647059 )
|
||||
offset_left = 1887.0
|
||||
offset_top = 5.0
|
||||
offset_right = 1915.0
|
||||
offset_bottom = 19.0
|
||||
tooltip_text = "Open a new issue on Github to report a problem!"
|
||||
size_flags_horizontal = 8
|
||||
text = "beta"
|
||||
underline = 1
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
366
addons/inkgd/editor/panel/preview/ink_preview_panel.gd
Normal file
366
addons/inkgd/editor/panel/preview/ink_preview_panel.gd
Normal file
|
@ -0,0 +1,366 @@
|
|||
@tool
|
||||
# ############################################################################ #
|
||||
# Copyright © 2018-2022 Paul Joannon
|
||||
# Copyright © 2019-2022 Frédéric Maquin <fred@ephread.com>
|
||||
# Licensed under the MIT License.
|
||||
# See LICENSE in the project root for license information.
|
||||
# ############################################################################ #
|
||||
|
||||
extends Control
|
||||
|
||||
# Hiding this type to prevent registration of "private" nodes.
|
||||
# See https://github.com/godotengine/godot-proposals/issues/1047
|
||||
# class_name InkPreviewPanel
|
||||
|
||||
# ############################################################################ #
|
||||
# Imports
|
||||
# ############################################################################ #
|
||||
|
||||
var InkPlayerFactory := preload("res://addons/inkgd/ink_player_factory.gd") as GDScript
|
||||
|
||||
# ############################################################################ #
|
||||
# Enums
|
||||
# ############################################################################ #
|
||||
|
||||
enum StoryOrigin {
|
||||
CONFIGURATION,
|
||||
FILE
|
||||
}
|
||||
|
||||
# ############################################################################ #
|
||||
# Constants
|
||||
# ############################################################################ #
|
||||
|
||||
const NAME = "name"
|
||||
const STORY_ORIGIN = "story_origin"
|
||||
const FILE_PATH = "file_path"
|
||||
|
||||
# ############################################################################ #
|
||||
# Public Properties
|
||||
# ############################################################################ #
|
||||
|
||||
var editor_interface: InkEditorInterface
|
||||
var configuration: InkConfiguration
|
||||
var progress_texture: AnimatedTexture
|
||||
|
||||
# ############################################################################ #
|
||||
# Private Properties
|
||||
# ############################################################################ #
|
||||
|
||||
var _scrollbar_max_value = -1
|
||||
var _current_story_index = -1
|
||||
|
||||
var _custom_stories: Array = []
|
||||
var _available_stories: Array = []
|
||||
|
||||
var _file_dialog = EditorFileDialog.new()
|
||||
|
||||
var _ink_player = InkPlayerFactory.create()
|
||||
|
||||
# ############################################################################ #
|
||||
# On Ready | Private Properties
|
||||
# ############################################################################ #
|
||||
|
||||
@onready var _play_icon = get_theme_icon("Play", "EditorIcons")
|
||||
|
||||
# ############################################################################ #
|
||||
# On Ready | Private Nodes
|
||||
# ############################################################################
|
||||
|
||||
@onready var _command_strip = find_child("CommandStripHBoxContainer")
|
||||
|
||||
@onready var _pick_story_button = _command_strip.get_node("PickStoryOptionButton")
|
||||
@onready var _load_story_button = _command_strip.get_node("LoadStoryButton")
|
||||
@onready var _start_button = _command_strip.get_node("StartButton")
|
||||
@onready var _stop_button = _command_strip.get_node("StopButton")
|
||||
@onready var _clear_button = _command_strip.get_node("ClearButton")
|
||||
|
||||
@onready var _scroll_container = find_child("ScrollContainer")
|
||||
@onready var _story_container = _scroll_container.get_node("MarginContainer/StoryVBoxContainer")
|
||||
|
||||
@onready var _choice_area_container = find_child("ChoicesAreaVBoxContainer")
|
||||
@onready var _choices_container = _choice_area_container.get_node("ChoicesVBoxContainer")
|
||||
|
||||
# ############################################################################ #
|
||||
# Overrides
|
||||
# ############################################################################ #
|
||||
|
||||
func _ready():
|
||||
# FIXME: This needs investigating.
|
||||
# Sanity check. It seems the editor instantiates tools script on their
|
||||
# own, probably to add them to its tree. In that case, they won't have
|
||||
# their dependencies injected, so we're not doing anything.
|
||||
if editor_interface == null || configuration == null || progress_texture == null:
|
||||
print("[inkgd] [INFO] Ink Preview Tab: dependencies not met, ignoring.")
|
||||
return
|
||||
|
||||
add_child(_ink_player)
|
||||
|
||||
_connect_signals()
|
||||
_apply_configuration()
|
||||
_update_story_picker()
|
||||
|
||||
var load_icon = get_theme_icon("Load", "EditorIcons")
|
||||
var stop_icon = get_theme_icon("Stop", "EditorIcons")
|
||||
var clear_icon = get_theme_icon("Clear", "EditorIcons")
|
||||
|
||||
_start_button.icon = _play_icon
|
||||
_load_story_button.icon = load_icon
|
||||
_stop_button.icon = stop_icon
|
||||
_clear_button.icon = clear_icon
|
||||
|
||||
_stop_button.visible = false
|
||||
|
||||
_choice_area_container.custom_minimum_size = Vector2(200, 0) * editor_interface.scale
|
||||
_choice_area_container.visible = false
|
||||
|
||||
_file_dialog.connect("file_selected", Callable(self, "_on_file_selected"))
|
||||
add_child(_file_dialog)
|
||||
|
||||
# ############################################################################ #
|
||||
# Signal Receivers
|
||||
# ############################################################################ #
|
||||
|
||||
func _start_button_pressed():
|
||||
var file_path = _get_current_story_file_path()
|
||||
if file_path == null:
|
||||
return
|
||||
|
||||
print("[inkgd] [INFO] Previewing %s" % file_path)
|
||||
_clear_content()
|
||||
|
||||
_ink_player.destroy()
|
||||
_ink_player.ink_file = load(file_path)
|
||||
|
||||
_start_button.icon = progress_texture
|
||||
_disable_command_strip(true)
|
||||
|
||||
_ink_player.create_story()
|
||||
|
||||
|
||||
func _stop_button_pressed():
|
||||
_start_button.visible = true
|
||||
_stop_button.visible = false
|
||||
_choice_area_container.visible = false
|
||||
|
||||
_ink_player.destroy()
|
||||
|
||||
_clear_choices()
|
||||
_clear_content()
|
||||
|
||||
|
||||
func _story_loaded(successfully: bool):
|
||||
_disable_command_strip(false)
|
||||
_start_button.icon = _play_icon
|
||||
|
||||
if !successfully:
|
||||
return
|
||||
|
||||
_start_button.visible = false
|
||||
_stop_button.visible = true
|
||||
|
||||
_ink_player.allow_external_function_fallbacks = true
|
||||
_continue_story()
|
||||
|
||||
func _pick_story_button_selected(index):
|
||||
if _current_story_index != index:
|
||||
_stop_button_pressed()
|
||||
|
||||
_current_story_index = index
|
||||
|
||||
|
||||
func _load_story_button_pressed():
|
||||
_file_dialog.file_mode = FileDialog.FILE_MODE_OPEN_FILE
|
||||
_file_dialog.access = FileDialog.ACCESS_RESOURCES
|
||||
_file_dialog.add_filter("*.json;Compiled Ink story")
|
||||
_file_dialog.popup_centered(Vector2(1280, 800) * editor_interface.scale)
|
||||
|
||||
|
||||
func _choice_button_pressed(index):
|
||||
_clear_choices()
|
||||
|
||||
_ink_player.choose_choice_index(index)
|
||||
_continue_story()
|
||||
|
||||
|
||||
func _on_file_selected(path: String):
|
||||
if _custom_stories.has(path):
|
||||
return
|
||||
|
||||
for story_configuration in self.configuration.stories:
|
||||
var target_file_path = self.configuration.get_target_file_path(story_configuration)
|
||||
if target_file_path == path:
|
||||
return
|
||||
|
||||
_custom_stories.append(path)
|
||||
_apply_configuration()
|
||||
_update_story_picker(path)
|
||||
|
||||
|
||||
func _scrollbar_changed():
|
||||
var max_value = _scroll_container.get_v_scroll_bar().max_value
|
||||
|
||||
if _scrollbar_max_value == max_value && _scrollbar_max_value != -1:
|
||||
return
|
||||
|
||||
_scrollbar_max_value = max_value
|
||||
_scroll_container.scroll_vertical = max_value
|
||||
|
||||
|
||||
func _configuration_changed():
|
||||
# Cleaning everything on configuration change may end up being frustrating.
|
||||
# But for now, it's going to make everybody's life easier.
|
||||
_stop_button_pressed()
|
||||
_apply_configuration()
|
||||
_update_story_picker()
|
||||
|
||||
|
||||
# ############################################################################ #
|
||||
# Private Methods
|
||||
# ############################################################################ #
|
||||
|
||||
func _apply_configuration():
|
||||
_available_stories.clear()
|
||||
|
||||
_current_story_index = -1
|
||||
_pick_story_button.selected = _current_story_index
|
||||
|
||||
var i = 0
|
||||
for story_configuration in self.configuration.stories:
|
||||
var target_file_path = self.configuration.get_target_file_path(story_configuration)
|
||||
if target_file_path != null && !target_file_path.is_empty():
|
||||
_available_stories.append({
|
||||
NAME: "Story %d - %s" % [i + 1, target_file_path.get_file()],
|
||||
FILE_PATH: target_file_path,
|
||||
STORY_ORIGIN: StoryOrigin.CONFIGURATION
|
||||
})
|
||||
i += 1
|
||||
|
||||
var j = 0
|
||||
for custom_story_path in _custom_stories:
|
||||
if custom_story_path != null && !custom_story_path.is_empty():
|
||||
_available_stories.append({
|
||||
NAME: custom_story_path.get_file(),
|
||||
FILE_PATH: ProjectSettings.localize_path(custom_story_path),
|
||||
STORY_ORIGIN: StoryOrigin.FILE
|
||||
})
|
||||
j += 1
|
||||
|
||||
|
||||
func _update_story_picker(selected_path = null):
|
||||
_pick_story_button.clear()
|
||||
|
||||
var i = 0
|
||||
for story in _available_stories:
|
||||
_pick_story_button.add_item(story[NAME], i)
|
||||
if selected_path != null && story[FILE_PATH] == selected_path:
|
||||
_current_story_index = i
|
||||
_pick_story_button.selected = _current_story_index
|
||||
i += 1
|
||||
|
||||
if _available_stories.size() > 0:
|
||||
if _current_story_index == -1:
|
||||
_current_story_index = 0
|
||||
_pick_story_button.selected = _current_story_index
|
||||
|
||||
_pick_story_button.visible = true
|
||||
else:
|
||||
_current_story_index = -1
|
||||
_pick_story_button.selected = _current_story_index
|
||||
|
||||
_pick_story_button.visible = false
|
||||
|
||||
|
||||
func _continue_story():
|
||||
while _ink_player.can_continue:
|
||||
var text = _ink_player.continue_story()
|
||||
|
||||
if text.right(text.length() - 1) == "\n":
|
||||
text.erase(text.length() - 1, 1)
|
||||
|
||||
var text_label = Label.new()
|
||||
text_label.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
|
||||
text_label.text = text
|
||||
|
||||
_story_container.add_child(text_label)
|
||||
|
||||
var tags = _ink_player.current_tags
|
||||
if !tags.is_empty():
|
||||
var tag_label = Label.new()
|
||||
tag_label.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
|
||||
tag_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||
tag_label.text = "# " + ", ".join(PackedStringArray(tags))
|
||||
tag_label.add_theme_color_override("font_color", Color(1, 1, 1, 0.4))
|
||||
|
||||
_story_container.add_child(tag_label)
|
||||
|
||||
var separator = HSeparator.new()
|
||||
_story_container.add_child(separator)
|
||||
|
||||
if _ink_player.current_choices.size() > 0:
|
||||
var i = 0
|
||||
for choice in _ink_player.current_choices:
|
||||
var button = Button.new()
|
||||
button.text = choice.text
|
||||
button.connect("pressed", Callable(self, "_choice_button_pressed").bind(i))
|
||||
|
||||
_choices_container.add_child(button)
|
||||
i += 1
|
||||
|
||||
_choice_area_container.visible = true
|
||||
else:
|
||||
var label = Label.new()
|
||||
label.text = "End of the story."
|
||||
label.horizontal_alignment = HORIZONTAL_ALIGNMENT_RIGHT
|
||||
|
||||
_story_container.add_child(label)
|
||||
|
||||
_choice_area_container.visible = false
|
||||
|
||||
|
||||
func _get_current_story_file_path():
|
||||
if _current_story_index >= 0 && _current_story_index < _available_stories.size():
|
||||
return _available_stories[_current_story_index][FILE_PATH]
|
||||
else:
|
||||
return null
|
||||
|
||||
|
||||
func _clear_content():
|
||||
for child in _story_container.get_children():
|
||||
_story_container.remove_child(child)
|
||||
child.queue_free()
|
||||
|
||||
|
||||
func _clear_choices():
|
||||
for child in _choices_container.get_children():
|
||||
_choices_container.remove_child(child)
|
||||
child.queue_free()
|
||||
|
||||
func _disable_command_strip(disabled: bool):
|
||||
_pick_story_button.disabled = disabled
|
||||
_load_story_button.disabled = disabled
|
||||
_start_button.disabled = disabled
|
||||
_stop_button.disabled = disabled
|
||||
_clear_button.disabled = disabled
|
||||
|
||||
func _connect_signals():
|
||||
if configuration != null:
|
||||
var is_signal_connected := configuration.is_connected(
|
||||
"story_configuration_changed",
|
||||
Callable(self, "_configuration_changed")
|
||||
)
|
||||
|
||||
if !is_signal_connected:
|
||||
configuration.connect(
|
||||
"story_configuration_changed",
|
||||
Callable(self, "_configuration_changed")
|
||||
)
|
||||
|
||||
_ink_player.connect("loaded", Callable(self, "_story_loaded"))
|
||||
_pick_story_button.connect("item_selected", Callable(self, "_pick_story_button_selected"))
|
||||
_load_story_button.connect("pressed", Callable(self, "_load_story_button_pressed"))
|
||||
_start_button.connect("pressed", Callable(self, "_start_button_pressed"))
|
||||
_stop_button.connect("pressed", Callable(self, "_stop_button_pressed"))
|
||||
_clear_button.connect("pressed", Callable(self, "_clear_content"))
|
||||
|
||||
_scroll_container.get_v_scroll_bar().connect("changed", Callable(self, "_scrollbar_changed"))
|
119
addons/inkgd/editor/panel/preview/ink_preview_panel.tscn
Normal file
119
addons/inkgd/editor/panel/preview/ink_preview_panel.tscn
Normal file
|
@ -0,0 +1,119 @@
|
|||
[gd_scene load_steps=4 format=3 uid="uid://0do8xgmkscjn"]
|
||||
|
||||
[ext_resource type="Script" path="res://addons/inkgd/editor/panel/preview/ink_preview_panel.gd" id="2"]
|
||||
|
||||
[sub_resource type="Image" id="Image_nl482"]
|
||||
data = {
|
||||
"data": PackedByteArray(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
|
||||
"format": "LumAlpha8",
|
||||
"height": 16,
|
||||
"mipmaps": false,
|
||||
"width": 16
|
||||
}
|
||||
|
||||
[sub_resource type="ImageTexture" id="2"]
|
||||
image = SubResource("Image_nl482")
|
||||
|
||||
[node name="Preview" type="Control"]
|
||||
layout_mode = 3
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
script = ExtResource("2")
|
||||
|
||||
[node name="MarginContainer" type="MarginContainer" parent="."]
|
||||
layout_mode = 0
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 3
|
||||
|
||||
[node name="HSplitContainer" type="HSplitContainer" parent="MarginContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 3
|
||||
|
||||
[node name="StoryVBoxContainer" type="VBoxContainer" parent="MarginContainer/HSplitContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 3
|
||||
theme_override_constants/separation = 5
|
||||
|
||||
[node name="CommandStripHBoxContainer" type="HBoxContainer" parent="MarginContainer/HSplitContainer/StoryVBoxContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
theme_override_constants/separation = 10
|
||||
|
||||
[node name="LoadStoryButton" type="Button" parent="MarginContainer/HSplitContainer/StoryVBoxContainer/CommandStripHBoxContainer"]
|
||||
layout_mode = 2
|
||||
theme_override_constants/h_separation = 8
|
||||
text = "Load new…"
|
||||
icon = SubResource("2")
|
||||
|
||||
[node name="PickStoryOptionButton" type="OptionButton" parent="MarginContainer/HSplitContainer/StoryVBoxContainer/CommandStripHBoxContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 0
|
||||
|
||||
[node name="Control" type="Control" parent="MarginContainer/HSplitContainer/StoryVBoxContainer/CommandStripHBoxContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="StartButton" type="Button" parent="MarginContainer/HSplitContainer/StoryVBoxContainer/CommandStripHBoxContainer"]
|
||||
layout_mode = 2
|
||||
theme_override_constants/h_separation = 8
|
||||
text = "Start"
|
||||
icon = SubResource("2")
|
||||
|
||||
[node name="StopButton" type="Button" parent="MarginContainer/HSplitContainer/StoryVBoxContainer/CommandStripHBoxContainer"]
|
||||
visible = false
|
||||
layout_mode = 2
|
||||
theme_override_constants/h_separation = 10
|
||||
text = "Stop"
|
||||
icon = SubResource("2")
|
||||
|
||||
[node name="ClearButton" type="Button" parent="MarginContainer/HSplitContainer/StoryVBoxContainer/CommandStripHBoxContainer"]
|
||||
layout_mode = 2
|
||||
theme_override_constants/h_separation = 8
|
||||
text = "Clear"
|
||||
icon = SubResource("2")
|
||||
|
||||
[node name="MarginContainer" type="MarginContainer" parent="MarginContainer/HSplitContainer/StoryVBoxContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 3
|
||||
|
||||
[node name="Panel" type="Panel" parent="MarginContainer/HSplitContainer/StoryVBoxContainer/MarginContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 3
|
||||
|
||||
[node name="ScrollContainer" type="ScrollContainer" parent="MarginContainer/HSplitContainer/StoryVBoxContainer/MarginContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 3
|
||||
|
||||
[node name="MarginContainer" type="MarginContainer" parent="MarginContainer/HSplitContainer/StoryVBoxContainer/MarginContainer/ScrollContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
theme_override_constants/margin_left = 10
|
||||
theme_override_constants/margin_top = 10
|
||||
theme_override_constants/margin_right = 10
|
||||
theme_override_constants/margin_bottom = 10
|
||||
|
||||
[node name="StoryVBoxContainer" type="VBoxContainer" parent="MarginContainer/HSplitContainer/StoryVBoxContainer/MarginContainer/ScrollContainer/MarginContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="ChoicesAreaVBoxContainer" type="VBoxContainer" parent="MarginContainer/HSplitContainer"]
|
||||
custom_minimum_size = Vector2(300, 0)
|
||||
layout_mode = 2
|
||||
theme_override_constants/separation = 5
|
||||
|
||||
[node name="Button" type="Button" parent="MarginContainer/HSplitContainer/ChoicesAreaVBoxContainer"]
|
||||
layout_mode = 2
|
||||
mouse_filter = 2
|
||||
text = "Choices"
|
||||
flat = true
|
||||
|
||||
[node name="ChoicesVBoxContainer" type="VBoxContainer" parent="MarginContainer/HSplitContainer/ChoicesAreaVBoxContainer"]
|
||||
layout_mode = 2
|
13
addons/inkgd/editor/panel/stories/empty_state_container.tscn
Normal file
13
addons/inkgd/editor/panel/stories/empty_state_container.tscn
Normal file
|
@ -0,0 +1,13 @@
|
|||
[gd_scene format=2]
|
||||
|
||||
[node name="EmptyStateContainer" type="CenterContainer"]
|
||||
offset_right = 1902.0
|
||||
offset_bottom = 100.0
|
||||
custom_minimum_size = Vector2( 0, 100 )
|
||||
|
||||
[node name="Label" type="Label" parent="."]
|
||||
offset_left = 879.0
|
||||
offset_top = 43.0
|
||||
offset_right = 1022.0
|
||||
offset_bottom = 57.0
|
||||
text = "No stories to compile."
|
153
addons/inkgd/editor/panel/stories/ink_story_configuration.gd
Normal file
153
addons/inkgd/editor/panel/stories/ink_story_configuration.gd
Normal file
|
@ -0,0 +1,153 @@
|
|||
@tool
|
||||
# ############################################################################ #
|
||||
# Copyright © 2019-2022 Frédéric Maquin <fred@ephread.com>
|
||||
# Licensed under the MIT License.
|
||||
# See LICENSE in the project root for license information.
|
||||
# ############################################################################ #
|
||||
|
||||
extends VBoxContainer
|
||||
|
||||
# Hiding this type to prevent registration of "private" nodes.
|
||||
# See https://github.com/godotengine/godot-proposals/issues/1047
|
||||
# class_name InkStoryConfiguration
|
||||
|
||||
# ############################################################################ #
|
||||
# Signals
|
||||
# ############################################################################ #
|
||||
|
||||
signal configuration_changed(story_configuration)
|
||||
|
||||
signal remove_button_pressed(story_configuration)
|
||||
|
||||
signal build_button_pressed(story_configuration)
|
||||
|
||||
signal source_file_button_pressed(story_configuration)
|
||||
|
||||
signal target_file_button_pressed(story_configuration)
|
||||
|
||||
signal watched_folder_button_pressed(story_configuration)
|
||||
|
||||
# ############################################################################ #
|
||||
# Properties
|
||||
# ############################################################################ #
|
||||
|
||||
var editor_interface: InkEditorInterface = null
|
||||
|
||||
# ############################################################################ #
|
||||
# Nodes
|
||||
# ############################################################################ #
|
||||
|
||||
@onready var story_label = find_child("StoryLabel")
|
||||
|
||||
@onready var remove_button = find_child("RemoveButton")
|
||||
@onready var build_button = find_child("BuildButton")
|
||||
|
||||
@onready var source_file_line_edit = find_child("SourceFileLineEdit")
|
||||
@onready var source_file_dialog_button = find_child("SourceFileDialogButton")
|
||||
|
||||
@onready var target_file_line_edit = find_child("TargetFileLineEdit")
|
||||
@onready var target_file_dialog_button = find_child("TargetFileDialogButton")
|
||||
|
||||
@onready var watched_folder_label = find_child("WatchedFolderLabel")
|
||||
@onready var watched_folder_container = find_child("WatchedFolderHBoxContainer")
|
||||
@onready var watched_folder_line_edit = find_child("WatchedFolderLineEdit")
|
||||
@onready var watched_folder_dialog_button = find_child("WatchedFolderDialogButton")
|
||||
|
||||
@onready var background_color_rect = find_child("BackgroundColorRect")
|
||||
|
||||
# ############################################################################ #
|
||||
# Overrides
|
||||
# ############################################################################ #
|
||||
|
||||
func _ready():
|
||||
# FIXME: This needs investigating.
|
||||
# Sanity check. It seems the editor instantiates tools script on their
|
||||
# own, probably to add them to its tree. In that case, they won't have
|
||||
# their dependencies injected, so we're not doing anything.
|
||||
if editor_interface == null:
|
||||
return
|
||||
|
||||
_apply_custom_header_color()
|
||||
_set_button_icons()
|
||||
_connect_signals()
|
||||
|
||||
show_watched_folder(false)
|
||||
|
||||
# ############################################################################ #
|
||||
# Signals
|
||||
# ############################################################################ #
|
||||
|
||||
func _configuration_entered(_new_text: String):
|
||||
_configuration_focus_exited()
|
||||
|
||||
|
||||
func _configuration_focus_exited():
|
||||
emit_signal("configuration_changed", self)
|
||||
|
||||
|
||||
func _remove_button_pressed():
|
||||
emit_signal("remove_button_pressed", self)
|
||||
|
||||
|
||||
func _build_button_pressed():
|
||||
emit_signal("build_button_pressed", self)
|
||||
|
||||
|
||||
func _source_file_button_pressed():
|
||||
emit_signal("source_file_button_pressed", self)
|
||||
|
||||
|
||||
func _target_file_button_pressed():
|
||||
emit_signal("target_file_button_pressed", self)
|
||||
|
||||
|
||||
func _watched_folder_button_pressed():
|
||||
emit_signal("watched_folder_button_pressed", self)
|
||||
|
||||
# ############################################################################ #
|
||||
# Public Methods
|
||||
# ############################################################################ #
|
||||
|
||||
@warning_ignore("shadowed_variable")
|
||||
func show_watched_folder(show: bool):
|
||||
watched_folder_label.visible = show
|
||||
watched_folder_container.visible = show
|
||||
|
||||
func disable_all_buttons(disable: bool):
|
||||
remove_button.disabled = disable
|
||||
build_button.disabled = disable
|
||||
|
||||
|
||||
# ############################################################################ #
|
||||
# Private Methods
|
||||
# ############################################################################ #
|
||||
|
||||
func _apply_custom_header_color():
|
||||
var header_color = editor_interface.get_custom_header_color()
|
||||
if header_color != Color.TRANSPARENT:
|
||||
background_color_rect.color = header_color
|
||||
|
||||
|
||||
func _set_button_icons():
|
||||
var folder_icon = get_theme_icon("Folder", "EditorIcons")
|
||||
source_file_dialog_button.icon = folder_icon
|
||||
target_file_dialog_button.icon = folder_icon
|
||||
watched_folder_dialog_button.icon = folder_icon
|
||||
|
||||
var trash_icon = get_theme_icon("Remove", "EditorIcons")
|
||||
remove_button.icon = trash_icon
|
||||
|
||||
|
||||
func _connect_signals():
|
||||
source_file_line_edit.connect("text_submitted", Callable(self, "_configuration_entered"))
|
||||
source_file_line_edit.connect("focus_exited", Callable(self, "_configuration_focus_exited"))
|
||||
|
||||
target_file_line_edit.connect("text_submitted", Callable(self, "_configuration_entered"))
|
||||
target_file_line_edit.connect("focus_exited", Callable(self, "_configuration_focus_exited"))
|
||||
|
||||
source_file_dialog_button.connect("pressed", Callable(self, "_source_file_button_pressed"))
|
||||
target_file_dialog_button.connect("pressed", Callable(self, "_target_file_button_pressed"))
|
||||
watched_folder_dialog_button.connect("pressed", Callable(self, "_watched_folder_button_pressed"))
|
||||
|
||||
remove_button.connect("pressed", Callable(self, "_remove_button_pressed"))
|
||||
build_button.connect("pressed", Callable(self, "_build_button_pressed"))
|
189
addons/inkgd/editor/panel/stories/ink_story_configuration.tscn
Normal file
189
addons/inkgd/editor/panel/stories/ink_story_configuration.tscn
Normal file
|
@ -0,0 +1,189 @@
|
|||
[gd_scene load_steps=4 format=2]
|
||||
|
||||
[ext_resource path="res://addons/inkgd/editor/panel/stories/ink_story_configuration.gd" type="Script" id=1]
|
||||
|
||||
[sub_resource type="Image" id=3]
|
||||
data = {
|
||||
"data": PackedByteArray( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ),
|
||||
"format": "LumAlpha8",
|
||||
"height": 16,
|
||||
"mipmaps": false,
|
||||
"width": 16
|
||||
}
|
||||
|
||||
[sub_resource type="ImageTexture" id=2]
|
||||
flags = 4
|
||||
flags = 4
|
||||
image = SubResource( 3 )
|
||||
size = Vector2( 16, 16 )
|
||||
|
||||
[node name="StoryConfiguration" type="VBoxContainer"]
|
||||
offset_right = 1902.0
|
||||
offset_bottom = 87.0
|
||||
theme_override_constants/separation = 5
|
||||
script = ExtResource( 1 )
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="HeaderMarginContainer" type="MarginContainer" parent="."]
|
||||
offset_right = 1902.0
|
||||
offset_bottom = 32.0
|
||||
theme_override_constants/margin_right = 0
|
||||
theme_override_constants/margin_top = 0
|
||||
theme_override_constants/margin_left = 0
|
||||
theme_override_constants/margin_bottom = 0
|
||||
|
||||
[node name="BackgroundColorRect" type="ColorRect" parent="HeaderMarginContainer"]
|
||||
offset_right = 1902.0
|
||||
offset_bottom = 32.0
|
||||
color = Color( 0.268314, 0.291712, 0.340784, 1 )
|
||||
|
||||
[node name="MarginContainer" type="MarginContainer" parent="HeaderMarginContainer"]
|
||||
offset_right = 1902.0
|
||||
offset_bottom = 32.0
|
||||
theme_override_constants/margin_right = 5
|
||||
theme_override_constants/margin_top = 5
|
||||
theme_override_constants/margin_left = 25
|
||||
theme_override_constants/margin_bottom = 5
|
||||
|
||||
[node name="HBoxContainer" type="HBoxContainer" parent="HeaderMarginContainer/MarginContainer"]
|
||||
offset_left = 25.0
|
||||
offset_top = 5.0
|
||||
offset_right = 1897.0
|
||||
offset_bottom = 27.0
|
||||
|
||||
[node name="StoryLabel" type="Label" parent="HeaderMarginContainer/MarginContainer/HBoxContainer"]
|
||||
offset_top = 4.0
|
||||
offset_right = 1711.0
|
||||
offset_bottom = 18.0
|
||||
size_flags_horizontal = 3
|
||||
text = "0"
|
||||
|
||||
[node name="RemoveButton" type="Button" parent="HeaderMarginContainer/MarginContainer/HBoxContainer"]
|
||||
offset_left = 1715.0
|
||||
offset_right = 1803.0
|
||||
offset_bottom = 22.0
|
||||
mouse_filter = 1
|
||||
theme_override_constants/h_separation = 8
|
||||
text = "Remove"
|
||||
icon = SubResource( 2 )
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false,
|
||||
"_editor_description_": "Compile the story manually, based on the configuration below."
|
||||
}
|
||||
|
||||
[node name="BuildButton" type="Button" parent="HeaderMarginContainer/MarginContainer/HBoxContainer"]
|
||||
offset_left = 1807.0
|
||||
offset_right = 1872.0
|
||||
offset_bottom = 22.0
|
||||
mouse_filter = 1
|
||||
theme_override_constants/h_separation = 8
|
||||
text = "Compile"
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false,
|
||||
"_editor_description_": "Compile the story manually, based on the configuration below."
|
||||
}
|
||||
|
||||
[node name="ConfigurationMarginContainer" type="MarginContainer" parent="."]
|
||||
offset_top = 37.0
|
||||
offset_right = 1902.0
|
||||
offset_bottom = 117.0
|
||||
theme_override_constants/margin_right = 0
|
||||
theme_override_constants/margin_top = 0
|
||||
theme_override_constants/margin_left = 5
|
||||
theme_override_constants/margin_bottom = 0
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="GridContainer" type="GridContainer" parent="ConfigurationMarginContainer"]
|
||||
offset_left = 5.0
|
||||
offset_right = 1902.0
|
||||
offset_bottom = 80.0
|
||||
size_flags_horizontal = 3
|
||||
columns = 2
|
||||
|
||||
[node name="SourceFileLabel" type="Label" parent="ConfigurationMarginContainer/GridContainer"]
|
||||
offset_right = 946.0
|
||||
offset_bottom = 24.0
|
||||
tooltip_text = "The input path, a.k.a the original ink story."
|
||||
mouse_filter = 1
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 1
|
||||
text = "Source File (*.ink)"
|
||||
|
||||
[node name="SourceFileHBoxContainer" type="HBoxContainer" parent="ConfigurationMarginContainer/GridContainer"]
|
||||
offset_left = 950.0
|
||||
offset_right = 1896.0
|
||||
offset_bottom = 24.0
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="SourceFileLineEdit" type="LineEdit" parent="ConfigurationMarginContainer/GridContainer/SourceFileHBoxContainer"]
|
||||
offset_right = 914.0
|
||||
offset_bottom = 24.0
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="SourceFileDialogButton" type="Button" parent="ConfigurationMarginContainer/GridContainer/SourceFileHBoxContainer"]
|
||||
offset_left = 918.0
|
||||
offset_right = 946.0
|
||||
offset_bottom = 24.0
|
||||
icon = SubResource( 2 )
|
||||
|
||||
[node name="TargetFileLabel" type="Label" parent="ConfigurationMarginContainer/GridContainer"]
|
||||
offset_top = 28.0
|
||||
offset_right = 946.0
|
||||
offset_bottom = 52.0
|
||||
tooltip_text = "The output path, a.k.a the JSON file compiled from the original ink story."
|
||||
mouse_filter = 1
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 1
|
||||
text = "Target File (*.json)"
|
||||
|
||||
[node name="TargetFileHBoxContainer" type="HBoxContainer" parent="ConfigurationMarginContainer/GridContainer"]
|
||||
offset_left = 950.0
|
||||
offset_top = 28.0
|
||||
offset_right = 1896.0
|
||||
offset_bottom = 52.0
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="TargetFileLineEdit" type="LineEdit" parent="ConfigurationMarginContainer/GridContainer/TargetFileHBoxContainer"]
|
||||
offset_right = 914.0
|
||||
offset_bottom = 24.0
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="TargetFileDialogButton" type="Button" parent="ConfigurationMarginContainer/GridContainer/TargetFileHBoxContainer"]
|
||||
offset_left = 918.0
|
||||
offset_right = 946.0
|
||||
offset_bottom = 24.0
|
||||
icon = SubResource( 2 )
|
||||
|
||||
[node name="WatchedFolderLabel" type="Label" parent="ConfigurationMarginContainer/GridContainer"]
|
||||
offset_top = 56.0
|
||||
offset_right = 946.0
|
||||
offset_bottom = 80.0
|
||||
tooltip_text = "The directory to watch for changes in Ink sources.
|
||||
|
||||
This path is optional, leave it blank to disable automatic recompilation for that story."
|
||||
mouse_filter = 1
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 1
|
||||
text = "Watched Folder"
|
||||
|
||||
[node name="WatchedFolderHBoxContainer" type="HBoxContainer" parent="ConfigurationMarginContainer/GridContainer"]
|
||||
offset_left = 950.0
|
||||
offset_top = 56.0
|
||||
offset_right = 1896.0
|
||||
offset_bottom = 80.0
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="WatchedFolderLineEdit" type="LineEdit" parent="ConfigurationMarginContainer/GridContainer/WatchedFolderHBoxContainer"]
|
||||
offset_right = 914.0
|
||||
offset_bottom = 24.0
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="WatchedFolderDialogButton" type="Button" parent="ConfigurationMarginContainer/GridContainer/WatchedFolderHBoxContainer"]
|
||||
offset_left = 918.0
|
||||
offset_right = 946.0
|
||||
offset_bottom = 24.0
|
||||
icon = SubResource( 2 )
|
524
addons/inkgd/editor/panel/stories/ink_story_panel.gd
Normal file
524
addons/inkgd/editor/panel/stories/ink_story_panel.gd
Normal file
|
@ -0,0 +1,524 @@
|
|||
@tool
|
||||
# ############################################################################ #
|
||||
# Copyright © 2019-2022 Frédéric Maquin <fred@ephread.com>
|
||||
# Licensed under the MIT License.
|
||||
# See LICENSE in the project root for license information.
|
||||
# ############################################################################ #
|
||||
|
||||
extends Control
|
||||
|
||||
# Hiding this type to prevent registration of "private" nodes.
|
||||
# See https://github.com/godotengine/godot-proposals/issues/1047
|
||||
# class_name InkStoryPanel
|
||||
|
||||
# ############################################################################ #
|
||||
# Imports
|
||||
# ############################################################################ #
|
||||
|
||||
var InkConfiguration = load("res://addons/inkgd/editor/common/ink_configuration.gd")
|
||||
|
||||
var InkCompilationConfiguration = load("res://addons/inkgd/editor/common/executors/structures/ink_compilation_configuration.gd")
|
||||
var InkCompiler = load("res://addons/inkgd/editor/common/executors/ink_compiler.gd")
|
||||
|
||||
var InkRichDialog = load("res://addons/inkgd/editor/panel/common/ink_rich_dialog.tscn")
|
||||
var InkProgressDialog = load("res://addons/inkgd/editor/panel/common/ink_progress_dialog.tscn")
|
||||
var InkStoryConfigurationScene = load("res://addons/inkgd/editor/panel/stories/ink_story_configuration.tscn")
|
||||
var EmptyStateContainerScene = load("res://addons/inkgd/editor/panel/stories/empty_state_container.tscn")
|
||||
|
||||
# ############################################################################ #
|
||||
# Signals
|
||||
# ############################################################################ #
|
||||
|
||||
signal _compiled()
|
||||
|
||||
# ############################################################################ #
|
||||
# Enums
|
||||
# ############################################################################ #
|
||||
|
||||
enum FileDialogSelection {
|
||||
UNKNOWN,
|
||||
SOURCE_FILE,
|
||||
TARGET_FILE,
|
||||
WATCHED_FOLDER
|
||||
}
|
||||
|
||||
|
||||
# ############################################################################ #
|
||||
# Properties
|
||||
# ############################################################################ #
|
||||
|
||||
var editor_interface: InkEditorInterface
|
||||
var configuration: InkConfiguration
|
||||
var progress_texture: AnimatedTexture
|
||||
|
||||
|
||||
# ############################################################################ #
|
||||
# Private Properties
|
||||
# ############################################################################ #
|
||||
|
||||
var _scrollbar_max_value = -1
|
||||
|
||||
var _compilers: Dictionary = {}
|
||||
|
||||
var _file_dialog = EditorFileDialog.new()
|
||||
|
||||
## Configuration item for which the FileDialog is currently shown.
|
||||
##
|
||||
## Unknown by default.
|
||||
var _file_dialog_selection = FileDialogSelection.UNKNOWN
|
||||
|
||||
## The story index for which the FileDialog is currenlty shown.
|
||||
##
|
||||
## -1 by default or when the file dialog currently displayed doesn't
|
||||
## concern the stories source/target files.
|
||||
var _file_dialog_selection_story_index = -1
|
||||
|
||||
var _current_story_node = null
|
||||
|
||||
var _progress_dialog = null
|
||||
|
||||
# ############################################################################ #
|
||||
# Nodes
|
||||
# ############################################################################ #
|
||||
|
||||
@onready var _empty_state_container = EmptyStateContainerScene.instantiate()
|
||||
|
||||
@onready var _build_all_button = find_child("BuildAllButton")
|
||||
@onready var _add_new_story_button = find_child("AddNewStoryButton")
|
||||
|
||||
@onready var _story_configuration_container = find_child("StoryConfigurationVBoxContainer")
|
||||
@onready var _scroll_container = find_child("ScrollContainer")
|
||||
|
||||
|
||||
# ############################################################################ #
|
||||
# Overrides
|
||||
# ############################################################################ #
|
||||
|
||||
func _ready():
|
||||
# FIXME: This needs investigating.
|
||||
# Sanity check. It seems the editor instantiates tools script on their
|
||||
# own, probably to add them to its tree. In that case, they won't have
|
||||
# their dependencies injected, so we're not doing anything.
|
||||
if editor_interface == null || configuration == null || progress_texture == null:
|
||||
print("[inkgd] [INFO] Ink Stories Tab: dependencies not met, ignoring.")
|
||||
return
|
||||
|
||||
configuration.connect("compilation_mode_changed", Callable(self, "_compilation_mode_changed"))
|
||||
|
||||
editor_interface.editor_filesystem.connect("resources_reimported", Callable(self, "_resources_reimported"))
|
||||
|
||||
_story_configuration_container.add_child(_empty_state_container)
|
||||
add_child(_file_dialog)
|
||||
|
||||
var add_icon = get_theme_icon("Add", "EditorIcons")
|
||||
_add_new_story_button.icon = add_icon
|
||||
|
||||
_load_story_configurations()
|
||||
_connect_signals()
|
||||
|
||||
_compilation_mode_changed(configuration.compilation_mode)
|
||||
|
||||
|
||||
# ############################################################################ #
|
||||
# Signal Receivers
|
||||
# ############################################################################ #
|
||||
|
||||
func _resources_reimported(resources):
|
||||
call_deferred("_recompile_if_necessary", resources)
|
||||
|
||||
func _compilation_mode_changed(compilation_mode: int):
|
||||
var show_folder = (compilation_mode == InkConfiguration.BuildMode.AFTER_CHANGE)
|
||||
|
||||
for child in _story_configuration_container.get_children():
|
||||
child.show_watched_folder(show_folder)
|
||||
|
||||
func _source_file_button_pressed(node):
|
||||
_reset_file_dialog()
|
||||
|
||||
var index = _get_story_configuration_index(node)
|
||||
|
||||
_file_dialog_selection = FileDialogSelection.SOURCE_FILE
|
||||
_file_dialog_selection_story_index = index
|
||||
|
||||
var story_configuration = _get_story_configuration_at_index(index)
|
||||
var path = story_configuration.source_file_line_edit.text
|
||||
|
||||
_file_dialog.current_path = path
|
||||
_file_dialog.current_dir = path.get_base_dir()
|
||||
_file_dialog.current_file = path.get_file()
|
||||
|
||||
_file_dialog.file_mode = FileDialog.FILE_MODE_OPEN_FILE
|
||||
_file_dialog.access = FileDialog.ACCESS_FILESYSTEM
|
||||
_file_dialog.add_filter("*.ink;Ink source file")
|
||||
_file_dialog.popup_centered(Vector2(1280, 800) * editor_interface.scale)
|
||||
|
||||
|
||||
func _target_file_button_pressed(node):
|
||||
_reset_file_dialog()
|
||||
|
||||
var index = _get_story_configuration_index(node)
|
||||
|
||||
_file_dialog_selection = FileDialogSelection.TARGET_FILE
|
||||
_file_dialog_selection_story_index = index
|
||||
|
||||
var story_configuration = _get_story_configuration_at_index(index)
|
||||
var path = story_configuration.target_file_line_edit.text
|
||||
|
||||
_file_dialog.current_path = path
|
||||
_file_dialog.current_dir = path.get_base_dir()
|
||||
_file_dialog.current_file = path.get_file()
|
||||
|
||||
_file_dialog.file_mode = FileDialog.FILE_MODE_SAVE_FILE
|
||||
_file_dialog.access = FileDialog.ACCESS_FILESYSTEM
|
||||
_file_dialog.add_filter("*.json;Compiled Ink story")
|
||||
_file_dialog.popup_centered(Vector2(1280, 800) * editor_interface.scale)
|
||||
|
||||
func _watched_folder_button_pressed(node):
|
||||
_reset_file_dialog()
|
||||
|
||||
var index = _get_story_configuration_index(node)
|
||||
|
||||
_file_dialog_selection = FileDialogSelection.WATCHED_FOLDER
|
||||
_file_dialog_selection_story_index = index
|
||||
|
||||
var story_configuration = _get_story_configuration_at_index(index)
|
||||
var path = story_configuration.watched_folder_line_edit.text
|
||||
|
||||
_file_dialog.current_path = path
|
||||
_file_dialog.current_dir = path.get_base_dir()
|
||||
_file_dialog.current_file = path.get_file()
|
||||
|
||||
_file_dialog.file_mode = FileDialog.FILE_MODE_OPEN_DIR
|
||||
_file_dialog.access = FileDialog.ACCESS_FILESYSTEM
|
||||
_file_dialog.popup_centered(Vector2(1280, 800) * editor_interface.scale)
|
||||
|
||||
|
||||
func _build_all_button_pressed():
|
||||
_compile_all_stories()
|
||||
|
||||
|
||||
func _add_new_story_button_pressed():
|
||||
_add_new_story_configuration()
|
||||
|
||||
|
||||
func _configuration_changed(_node):
|
||||
_persist_configuration()
|
||||
|
||||
|
||||
func _remove_button_pressed(node):
|
||||
var index = _get_story_configuration_index(node)
|
||||
configuration.remove_story_configuration_at_index(index)
|
||||
|
||||
# TODO: Rebuild from scratch instead.
|
||||
var parent = node.get_parent()
|
||||
if parent != null:
|
||||
parent.remove_child(node)
|
||||
node.queue_free()
|
||||
|
||||
if _story_configuration_container.get_child_count() == 0:
|
||||
_story_configuration_container.add_child(_empty_state_container)
|
||||
else:
|
||||
var i = 0
|
||||
for child in _story_configuration_container.get_children():
|
||||
# Not using "is InkStoryConfiguration", because it requires a type
|
||||
# declaration. Node Types register in the editor and we don't want
|
||||
# that. This is a bit hacky, but until the proposal is accepted,
|
||||
# it prevents cluttering the "Create new node" list.
|
||||
if "story_label" in child:
|
||||
child.story_label.text = "Story %d" % (i + 1)
|
||||
i += 1
|
||||
|
||||
_persist_configuration()
|
||||
|
||||
|
||||
func _build_button_pressed(node):
|
||||
var index = _get_story_configuration_index(node)
|
||||
var story_configuration = configuration.get_story_configuration_at_index(index)
|
||||
|
||||
if story_configuration == null:
|
||||
printerr("[inkgd] [ERROR] No configurations found for Story %d" % (index + 1))
|
||||
return
|
||||
|
||||
_compile_story(story_configuration, node)
|
||||
|
||||
|
||||
func _compile_all_stories():
|
||||
_disable_all_buttons(true)
|
||||
var number_of_stories = configuration.stories.size()
|
||||
var current_story_index = 0
|
||||
|
||||
_progress_dialog = InkProgressDialog.instantiate()
|
||||
add_child(_progress_dialog)
|
||||
|
||||
_progress_dialog.update_layout(editor_interface.scale)
|
||||
_progress_dialog.popup_centered(Vector2(600, 100) * editor_interface.scale)
|
||||
|
||||
for story_configuration in configuration.stories:
|
||||
var source_file_path: String = configuration.get_source_file_path(story_configuration)
|
||||
_progress_dialog.current_step_name = source_file_path.get_file()
|
||||
|
||||
_compile_story(story_configuration)
|
||||
await self._compiled
|
||||
|
||||
@warning_ignore("integer_division")
|
||||
_progress_dialog.progress = float(100 * (current_story_index + 1) / number_of_stories)
|
||||
current_story_index += 1
|
||||
|
||||
remove_child(_progress_dialog)
|
||||
_progress_dialog.queue_free()
|
||||
_progress_dialog = null
|
||||
_disable_all_buttons(false)
|
||||
|
||||
func _compile_story(story_configuration, node = null):
|
||||
var source_file_path = configuration.get_source_file_path(story_configuration)
|
||||
var target_file_path = configuration.get_target_file_path(story_configuration)
|
||||
|
||||
if node != null:
|
||||
_current_story_node = node
|
||||
|
||||
node.build_button.icon = progress_texture
|
||||
_disable_all_buttons(true)
|
||||
|
||||
var compiler_configuration = InkCompilationConfiguration.new(
|
||||
configuration,
|
||||
true,
|
||||
node != null,
|
||||
source_file_path,
|
||||
target_file_path
|
||||
)
|
||||
var compiler = InkCompiler.new(compiler_configuration)
|
||||
|
||||
_compilers[compiler.identifier] = compiler
|
||||
compiler.connect("story_compiled", Callable(self, "_handle_compilation"))
|
||||
compiler.compile_story()
|
||||
|
||||
|
||||
func _handle_compilation(result):
|
||||
if _current_story_node != null:
|
||||
var button = _current_story_node.build_button
|
||||
button.icon = null
|
||||
_disable_all_buttons(false)
|
||||
_current_story_node = null
|
||||
|
||||
if result.user_triggered:
|
||||
if result.success:
|
||||
if result.output && !result.output.is_empty():
|
||||
var dialog = InkRichDialog.instantiate()
|
||||
add_child(dialog)
|
||||
|
||||
dialog.title = "Success!"
|
||||
dialog.message_text = "The story was successfully compiled."
|
||||
dialog.output_text = result.output
|
||||
dialog.update_layout(editor_interface.scale)
|
||||
|
||||
dialog.popup_centered(Vector2(700, 400) * editor_interface.scale)
|
||||
else:
|
||||
var dialog = AcceptDialog.new()
|
||||
add_child(dialog)
|
||||
|
||||
dialog.title = "Success!"
|
||||
dialog.dialog_text = "The story was successfully compiled."
|
||||
|
||||
dialog.popup_centered()
|
||||
|
||||
_reimport_compiled_stories()
|
||||
else:
|
||||
var dialog = InkRichDialog.instantiate()
|
||||
add_child(dialog)
|
||||
|
||||
dialog.title = "Error"
|
||||
dialog.message_text = "The story could not be compiled. See inklecate's output below."
|
||||
dialog.output_text = result.output
|
||||
dialog.update_layout(editor_interface.scale)
|
||||
|
||||
dialog.popup_centered(Vector2(700, 400) * editor_interface.scale)
|
||||
else:
|
||||
_reimport_compiled_stories()
|
||||
|
||||
if _compilers.has(result.identifier):
|
||||
_compilers.erase(result.identifier)
|
||||
|
||||
emit_signal("_compiled")
|
||||
|
||||
|
||||
func _on_file_selected(path: String):
|
||||
var index = _file_dialog_selection_story_index
|
||||
|
||||
match _file_dialog_selection:
|
||||
FileDialogSelection.SOURCE_FILE:
|
||||
var story_configuration = _get_story_configuration_at_index(index)
|
||||
if story_configuration == null:
|
||||
return
|
||||
|
||||
var localized_path = ProjectSettings.localize_path(path)
|
||||
var source_line_edit = story_configuration.source_file_line_edit
|
||||
|
||||
source_line_edit.text = localized_path
|
||||
source_line_edit.queue_redraw()
|
||||
|
||||
if story_configuration.target_file_line_edit.text.is_empty():
|
||||
var target_line_edit = story_configuration.target_file_line_edit
|
||||
target_line_edit.text = localized_path + ".json"
|
||||
target_line_edit.queue_redraw()
|
||||
|
||||
if story_configuration.watched_folder_line_edit.text.is_empty():
|
||||
var watched_folder_line_edit = story_configuration.watched_folder_line_edit
|
||||
watched_folder_line_edit.text = localized_path.get_base_dir()
|
||||
watched_folder_line_edit.queue_redraw()
|
||||
|
||||
_persist_configuration()
|
||||
|
||||
FileDialogSelection.TARGET_FILE:
|
||||
var story_configuration = _get_story_configuration_at_index(index)
|
||||
if story_configuration == null:
|
||||
return
|
||||
|
||||
var localized_path = ProjectSettings.localize_path(path)
|
||||
var line_edit = story_configuration.target_file_line_edit
|
||||
|
||||
line_edit.text = localized_path
|
||||
line_edit.queue_redraw()
|
||||
_persist_configuration()
|
||||
|
||||
FileDialogSelection.WATCHED_FOLDER:
|
||||
var story_configuration = _get_story_configuration_at_index(index)
|
||||
if story_configuration == null:
|
||||
return
|
||||
|
||||
var localized_path = ProjectSettings.localize_path(path)
|
||||
var line_edit = story_configuration.watched_folder_line_edit
|
||||
|
||||
line_edit.text = localized_path
|
||||
line_edit.queue_redraw()
|
||||
_persist_configuration()
|
||||
|
||||
_:
|
||||
printerr("[inkgd] [ERROR] Unknown FileDialogSelection, failed to save FileDialog file.")
|
||||
|
||||
_file_dialog_selection = FileDialogSelection.UNKNOWN
|
||||
|
||||
|
||||
func _scrollbar_changed():
|
||||
var max_value = _scroll_container.get_v_scroll_bar().max_value
|
||||
|
||||
if _scrollbar_max_value == max_value && _scrollbar_max_value != -1:
|
||||
return
|
||||
|
||||
_scrollbar_max_value = max_value
|
||||
_scroll_container.scroll_vertical = max_value
|
||||
|
||||
|
||||
# ############################################################################ #
|
||||
# Private helpers
|
||||
# ############################################################################ #
|
||||
|
||||
func _reset_file_dialog():
|
||||
_file_dialog.current_path = "res://"
|
||||
_file_dialog.current_dir = "res://"
|
||||
_file_dialog.current_file = ""
|
||||
_file_dialog.clear_filters()
|
||||
|
||||
|
||||
func _persist_configuration():
|
||||
configuration.stories.clear()
|
||||
|
||||
if _empty_state_container.get_parent() == null:
|
||||
configuration.stories.clear()
|
||||
for node in _story_configuration_container.get_children():
|
||||
# Not using "is InkStoryConfiguration", because it requires a type
|
||||
# declaration. Node Types register in the editor and we don't want
|
||||
# that. This is a bit hacky, but until the proposal is accepted,
|
||||
# it prevents cluttering the "Create new node" list.
|
||||
if !("story_label" in node):
|
||||
continue
|
||||
|
||||
configuration.append_new_story_configuration(
|
||||
node.source_file_line_edit.text,
|
||||
node.target_file_line_edit.text,
|
||||
node.watched_folder_line_edit.text
|
||||
)
|
||||
|
||||
configuration.persist()
|
||||
|
||||
|
||||
func _load_story_configurations():
|
||||
for story_configuration in configuration.stories:
|
||||
var node = _add_new_story_configuration()
|
||||
|
||||
node.source_file_line_edit.text = configuration.get_source_file_path(story_configuration)
|
||||
node.target_file_line_edit.text = configuration.get_target_file_path(story_configuration)
|
||||
node.watched_folder_line_edit.text = configuration.get_watched_folder_path(story_configuration)
|
||||
|
||||
|
||||
func _add_new_story_configuration():
|
||||
var story_configuration = InkStoryConfigurationScene.instantiate()
|
||||
|
||||
story_configuration.editor_interface = editor_interface
|
||||
|
||||
story_configuration.connect("configuration_changed", Callable(self, "_configuration_changed"))
|
||||
story_configuration.connect("remove_button_pressed", Callable(self, "_remove_button_pressed"))
|
||||
story_configuration.connect("build_button_pressed", Callable(self, "_build_button_pressed"))
|
||||
story_configuration.connect("source_file_button_pressed", Callable(self, "_source_file_button_pressed"))
|
||||
story_configuration.connect("target_file_button_pressed", Callable(self, "_target_file_button_pressed"))
|
||||
story_configuration.connect("watched_folder_button_pressed", Callable(self, "_watched_folder_button_pressed"))
|
||||
|
||||
if _empty_state_container.get_parent() != null:
|
||||
_story_configuration_container.remove_child(_empty_state_container)
|
||||
|
||||
_story_configuration_container.add_child(story_configuration)
|
||||
|
||||
var count = _story_configuration_container.get_child_count()
|
||||
story_configuration.story_label.text = "Story %d" % count
|
||||
|
||||
var show_folder = (configuration.compilation_mode == InkConfiguration.BuildMode.AFTER_CHANGE)
|
||||
story_configuration.show_watched_folder(show_folder)
|
||||
|
||||
return story_configuration
|
||||
|
||||
|
||||
func _reimport_compiled_stories():
|
||||
editor_interface.scan_file_system()
|
||||
|
||||
|
||||
func _get_story_configuration_index(node) -> int:
|
||||
return _story_configuration_container.get_children().find(node)
|
||||
|
||||
|
||||
func _get_story_configuration_at_index(index: int):
|
||||
if index >= 0 && _story_configuration_container.get_child_count():
|
||||
return _story_configuration_container.get_children()[index]
|
||||
|
||||
return null
|
||||
|
||||
|
||||
func _recompile_if_necessary(resources: PackedStringArray):
|
||||
# Making sure the resources have been imported before recompiling.
|
||||
await get_tree().create_timer(0.5).timeout
|
||||
|
||||
for story_configuration in configuration.stories:
|
||||
var watched_folder_path: String = configuration.get_watched_folder_path(story_configuration)
|
||||
|
||||
if watched_folder_path.is_empty():
|
||||
return
|
||||
|
||||
for resource in resources:
|
||||
if resource.begins_with(watched_folder_path):
|
||||
_compile_story(story_configuration)
|
||||
break
|
||||
|
||||
|
||||
func _disable_all_buttons(disable: bool):
|
||||
_add_new_story_button.disabled = disable
|
||||
_build_all_button.disabled = disable
|
||||
for child in _story_configuration_container.get_children():
|
||||
child.disable_all_buttons(disable)
|
||||
|
||||
|
||||
func _connect_signals():
|
||||
_build_all_button.connect("pressed", Callable(self, "_build_all_button_pressed"))
|
||||
_add_new_story_button.connect("pressed", Callable(self, "_add_new_story_button_pressed"))
|
||||
|
||||
_file_dialog.connect("file_selected", Callable(self, "_on_file_selected"))
|
||||
_file_dialog.connect("dir_selected", Callable(self, "_on_file_selected"))
|
||||
|
||||
_scroll_container.get_v_scroll_bar().connect("changed", Callable(self, "_scrollbar_changed"))
|
75
addons/inkgd/editor/panel/stories/ink_story_panel.tscn
Normal file
75
addons/inkgd/editor/panel/stories/ink_story_panel.tscn
Normal file
|
@ -0,0 +1,75 @@
|
|||
[gd_scene load_steps=4 format=3 uid="uid://b16uj28y2mqmk"]
|
||||
|
||||
[ext_resource type="Script" path="res://addons/inkgd/editor/panel/stories/ink_story_panel.gd" id="1"]
|
||||
|
||||
[sub_resource type="Image" id="Image_3omov"]
|
||||
data = {
|
||||
"data": PackedByteArray(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
|
||||
"format": "LumAlpha8",
|
||||
"height": 16,
|
||||
"mipmaps": false,
|
||||
"width": 16
|
||||
}
|
||||
|
||||
[sub_resource type="ImageTexture" id="2"]
|
||||
image = SubResource("Image_3omov")
|
||||
|
||||
[node name="Story" type="Control"]
|
||||
layout_mode = 3
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
script = ExtResource("1")
|
||||
|
||||
[node name="ScrollContainer" type="ScrollContainer" parent="."]
|
||||
layout_mode = 0
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
|
||||
[node name="StoriesVBoxContainer" type="VBoxContainer" parent="ScrollContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="HBoxContainer" type="HBoxContainer" parent="ScrollContainer/StoriesVBoxContainer"]
|
||||
layout_mode = 2
|
||||
alignment = 2
|
||||
|
||||
[node name="Label" type="Label" parent="ScrollContainer/StoriesVBoxContainer/HBoxContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
text = "Managed Stories"
|
||||
|
||||
[node name="AddNewStoryButton" type="Button" parent="ScrollContainer/StoriesVBoxContainer/HBoxContainer"]
|
||||
layout_mode = 2
|
||||
mouse_filter = 1
|
||||
theme_override_constants/h_separation = 8
|
||||
text = "New story"
|
||||
icon = SubResource("2")
|
||||
|
||||
[node name="VSeparator" type="VSeparator" parent="ScrollContainer/StoriesVBoxContainer/HBoxContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="BuildAllButton" type="Button" parent="ScrollContainer/StoriesVBoxContainer/HBoxContainer"]
|
||||
layout_mode = 2
|
||||
mouse_filter = 1
|
||||
theme_override_constants/h_separation = 10
|
||||
text = "Compile All"
|
||||
|
||||
[node name="MarginContainer" type="MarginContainer" parent="ScrollContainer/StoriesVBoxContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Panel" type="Panel" parent="ScrollContainer/StoriesVBoxContainer/MarginContainer"]
|
||||
self_modulate = Color(1, 1, 1, 0.686275)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="MarginContainer" type="MarginContainer" parent="ScrollContainer/StoriesVBoxContainer/MarginContainer"]
|
||||
layout_mode = 2
|
||||
theme_override_constants/margin_left = 5
|
||||
theme_override_constants/margin_top = 5
|
||||
theme_override_constants/margin_right = 5
|
||||
theme_override_constants/margin_bottom = 5
|
||||
|
||||
[node name="StoryConfigurationVBoxContainer" type="VBoxContainer" parent="ScrollContainer/StoriesVBoxContainer/MarginContainer/MarginContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
theme_override_constants/separation = 15
|
Loading…
Add table
Add a link
Reference in a new issue