Skip to content

Commit 0e7579f

Browse files
committed
Get basic exports working
1 parent 8a37c45 commit 0e7579f

31 files changed

+1291
-203
lines changed

addons/parley/main_panel.gd

Lines changed: 53 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,12 @@
44
class_name ParleyMainPanel extends VBoxContainer
55

66

7+
const ParleyExport = preload("./parley_export.gd")
8+
9+
710
const new_file_icon: CompressedTexture2D = preload("./assets/New.svg")
811
const load_file_icon: CompressedTexture2D = preload("./assets/Load.svg")
9-
const export_to_csv_icon: CompressedTexture2D = preload("./assets/Export.svg")
12+
const export_icon: CompressedTexture2D = preload("./assets/Export.svg")
1013
const insert_after_icon: CompressedTexture2D = preload("./assets/InsertAfter.svg")
1114
const dialogue_icon: CompressedTexture2D = preload("./assets/Dialogue.svg")
1215
const dialogue_option_icon: CompressedTexture2D = preload("./assets/DialogueOption.svg")
@@ -38,10 +41,11 @@ var parley_manager: ParleyManager
3841

3942
@onready var file_menu: MenuButton = %FileMenu
4043
@onready var insert_menu: MenuButton = %InsertMenu
44+
@onready var translations_menu: MenuButton = %TranslationMenu
4145
@onready var docs_button: Button = %DocsButton
4246
@onready var new_dialogue_sequence_modal: ParleyNewDialogueSequenceModal = %NewDialogueSequenceModal
4347
@onready var edit_dialogue_sequence_modal: ParleyEditDialogueSequenceModal = %EditDialogueSequenceModal
44-
@onready var export_to_csv_modal: ParleyExportToCsvModal = %ExportToCsvModal
48+
@onready var export_modal: ParleyExportModal = %ExportModal
4549
@onready var select_locale_modal: Window = %SelectLocaleModal
4650
@onready var editor: HSplitContainer = %EditorView
4751
@onready var sidebar: ParleySidebar = %Sidebar
@@ -218,6 +222,7 @@ func _render_test_locale_editor(on_ready: bool = false) -> void:
218222
func _setup(on_ready: bool = false) -> void:
219223
_setup_file_menu()
220224
_setup_insert_menu()
225+
_render_translations_menu()
221226
_render_toolbar()
222227
_render_bottom_panel()
223228
_render_test_locale_editor(on_ready)
@@ -230,7 +235,7 @@ func _setup_file_menu() -> void:
230235
popup.add_icon_item(new_file_icon, "New Dialogue Sequence...", 0)
231236
popup.add_icon_item(load_file_icon, "Open Dialogue Sequence...", 1)
232237
popup.add_separator("Export")
233-
popup.add_icon_item(export_to_csv_icon, "Export to CSV...", 2)
238+
popup.add_icon_item(export_icon, "Export to CSV...", 2)
234239
ParleyUtils.signals.safe_connect(popup.id_pressed, _on_file_id_pressed)
235240

236241

@@ -252,6 +257,22 @@ func _setup_insert_menu() -> void:
252257
popup.add_icon_item(end_node_icon, ParleyDialogueSequenceAst.get_type_name(ParleyDialogueSequenceAst.Type.END), ParleyDialogueSequenceAst.Type.END)
253258
popup.add_icon_item(group_node_icon, ParleyDialogueSequenceAst.get_type_name(ParleyDialogueSequenceAst.Type.GROUP), ParleyDialogueSequenceAst.Type.GROUP)
254259
ParleyUtils.signals.safe_connect(popup.id_pressed, _on_insert_id_pressed)
260+
261+
262+
func _render_translations_menu() -> void:
263+
var popup: PopupMenu = translations_menu.get_popup()
264+
popup.clear()
265+
266+
popup.add_icon_item(export_icon, "Export Dialogue to CSV...", 0)
267+
popup.set_item_tooltip(0, "Export Dialogue Text Translations to CSV")
268+
269+
popup.add_icon_item(export_icon, "Export Characters to CSV...", 1)
270+
popup.set_item_tooltip(1, "Export Character Translations to CSV")
271+
272+
popup.add_icon_item(export_icon, "Import Dialogue from CSV...", 2)
273+
popup.set_item_tooltip(2, "Import Dialogue Text Translations from CSV")
274+
275+
ParleyUtils.signals.safe_connect(popup.id_pressed, _on_translations_menu_id_pressed)
255276
#endregion
256277

257278

@@ -265,8 +286,7 @@ func _on_file_id_pressed(id: int) -> void:
265286
# TODO: get this from config (note, see the Node inspector as well)
266287
open_file_dialogue.current_dir = "res://dialogue_sequences"
267288
2:
268-
export_to_csv_modal.dialogue_ast = dialogue_ast
269-
export_to_csv_modal.render()
289+
export_modal.render(ParleyExportModal.ExportType.Node, ParleyExportModal.FileType.Csv, dialogue_ast)
270290
_:
271291
print_rich(ParleyUtils.log.info_msg("Unknown option ID pressed: {id}".format({'id': id})))
272292

@@ -320,6 +340,19 @@ func _on_insert_id_pressed(type: ParleyDialogueSequenceAst.Type) -> void:
320340
await refresh()
321341

322342

343+
func _on_translations_menu_id_pressed(id: int) -> void:
344+
match id:
345+
0:
346+
export_modal.render(ParleyExportModal.ExportType.DialogueTextTranslation, ParleyExportModal.FileType.Csv, dialogue_ast)
347+
1:
348+
export_modal.render(ParleyExportModal.ExportType.CharacterNameTranslation, ParleyExportModal.FileType.Csv, dialogue_ast)
349+
1:
350+
# IMPORT
351+
return
352+
_:
353+
print_rich(ParleyUtils.log.info_msg("Unknown option ID pressed: {id}".format({'id': id})))
354+
355+
323356
func _on_save_pressed() -> void:
324357
var result: int = _save_dialogue()
325358
if result != OK:
@@ -697,6 +730,21 @@ func _on_docs_button_pressed() -> void:
697730
var result: int = OS.shell_open(href)
698731
if result != OK:
699732
push_error(ParleyUtils.log.error_msg("Unable to navigate to Parley Documentation at %s: %s" % [href, result]))
733+
734+
735+
func _on_export_requested(export_type: ParleyExportModal.ExportType, file_type: ParleyExportModal.FileType, dialogue_sequence_ast: ParleyDialogueSequenceAst, path: String) -> void:
736+
var file_type_name: String = ParleyUtils.string.get_enum_key_name(ParleyExportModal.FileType, file_type)
737+
var export_type_name: String = ParleyUtils.string.get_enum_key_name(ParleyExportModal.ExportType, export_type)
738+
match export_type:
739+
ParleyExportModal.ExportType.Node:
740+
ParleyExport.export_node(file_type, dialogue_sequence_ast, path)
741+
ParleyExportModal.ExportType.DialogueTextTranslation:
742+
ParleyExport.export_dialogue_text_translation(file_type, dialogue_sequence_ast, path)
743+
ParleyExportModal.ExportType.CharacterNameTranslation:
744+
ParleyExport.export_character_name_translation(file_type, dialogue_sequence_ast, path)
745+
_:
746+
push_error(ParleyUtils.log.error_msg("Unable to export data: unknown export type (file_type:%s, export_type:%s)" % [file_type_name, export_type_name]))
747+
return
700748
#endregion
701749

702750

addons/parley/main_panel.tscn

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
[ext_resource type="Script" uid="uid://b3tj6amhgmct6" path="res://addons/parley/stores/action/action_store.gd" id="26_anq7l"]
2727
[ext_resource type="Texture2D" uid="uid://es7k6io6r0lm" path="res://addons/parley/assets/Translation.svg" id="27_owjo5"]
2828
[ext_resource type="Script" uid="uid://cbi8x2vk7bku1" path="res://addons/parley/stores/character/character_store.gd" id="28_anq7l"]
29-
[ext_resource type="PackedScene" uid="uid://c6cagjh7y5wn4" path="res://addons/parley/modals/export_to_csv_modal.tscn" id="29_wngpy"]
29+
[ext_resource type="PackedScene" uid="uid://c6cagjh7y5wn4" path="res://addons/parley/modals/export_modal.tscn" id="29_wngpy"]
3030
[ext_resource type="PackedScene" uid="uid://cjgxxvotxhj1g" path="res://addons/parley/components/bottom_panel.tscn" id="29_xxhvx"]
3131
[ext_resource type="Script" uid="uid://ob0am6au6mmt" path="res://addons/parley/stores/fact/fact_store.gd" id="30_7jaih"]
3232
[ext_resource type="Script" uid="uid://cjo7uxv32sr14" path="res://addons/parley/models/edge_ast.gd" id="30_rspbv"]
@@ -181,6 +181,21 @@ popup/item_12/text = "Group"
181181
popup/item_12/icon = ExtResource("10_h0et1")
182182
popup/item_12/id = 6
183183

184+
[node name="TranslationMenu" type="MenuButton" parent="MarginContainer/MainContainer/HSplitContainer/MainViewPanel/MainViewContainer/Toolbar/MenuBar"]
185+
unique_name_in_owner = true
186+
layout_mode = 2
187+
text = "Translations"
188+
item_count = 3
189+
popup/item_0/text = "Export Dialogue to CSV..."
190+
popup/item_0/icon = ExtResource("12_242yd")
191+
popup/item_0/id = 0
192+
popup/item_1/text = "Export Characters to CSV..."
193+
popup/item_1/icon = ExtResource("12_242yd")
194+
popup/item_1/id = 1
195+
popup/item_2/text = "Import Dialogue from CSV..."
196+
popup/item_2/icon = ExtResource("12_242yd")
197+
popup/item_2/id = 2
198+
184199
[node name="VSeparator" type="VSeparator" parent="MarginContainer/MainContainer/HSplitContainer/MainViewPanel/MainViewContainer/Toolbar"]
185200
layout_mode = 2
186201

@@ -296,7 +311,7 @@ filters = PackedStringArray("*.ds")
296311
unique_name_in_owner = true
297312
visible = false
298313

299-
[node name="ExportToCsvModal" parent="." instance=ExtResource("29_wngpy")]
314+
[node name="ExportModal" parent="." instance=ExtResource("29_wngpy")]
300315
unique_name_in_owner = true
301316
visible = false
302317
dialogue_ast = SubResource("Resource_7hjis")
@@ -328,5 +343,6 @@ visible = false
328343
[connection signal="sidebar_toggled" from="MarginContainer/MainContainer/HSplitContainer/MainViewPanel/MainViewContainer/EditorView/GraphContainer/BottomPanel" to="." method="_on_bottom_panel_sidebar_toggled"]
329344
[connection signal="file_selected" from="OpenFileDialog" to="." method="_on_open_dialog_file_selected"]
330345
[connection signal="dialogue_ast_created" from="NewDialogueSequenceModal" to="." method="_on_new_dialogue_sequence_modal_dialogue_ast_created"]
346+
[connection signal="export_requested" from="ExportModal" to="." method="_on_export_requested"]
331347
[connection signal="dialogue_ast_edited" from="EditDialogueSequenceModal" to="." method="_on_edit_dialogue_sequence_modal_dialogue_ast_edited"]
332348
[connection signal="locale_changed" from="SelectLocaleModal" to="." method="_on_select_locale_modal_locale_changed"]
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
# Copyright 2024-2025 the Bisterix Studio authors. All rights reserved. MIT license.
2+
3+
@tool
4+
class_name ParleyExportModal extends Window
5+
6+
7+
#region DEFS
8+
@onready var path_editor: LineEdit = %PathEdit
9+
@onready var choose_path_modal: FileDialog = %ChoosePathModal
10+
@onready var status_label: RichTextLabel = %Status
11+
12+
13+
# TODO: rename
14+
@export var dialogue_ast: ParleyDialogueSequenceAst
15+
16+
17+
# TODO: get from config
18+
var base_path: String
19+
var export_path: String
20+
var file_type: FileType = FileType.Csv
21+
var export_type: ExportType = ExportType.DialogueTextTranslation : set = _set_export_type
22+
23+
24+
enum FileType {
25+
Csv,
26+
}
27+
28+
29+
enum ExportType {
30+
Node,
31+
DialogueTextTranslation,
32+
CharacterNameTranslation,
33+
}
34+
35+
36+
signal export_requested(export_type: ExportType, file_type: FileType, dialogue_sequence_ast: ParleyDialogueSequenceAst, path: String)
37+
#endregion
38+
39+
40+
#region SETTERS
41+
func _set_export_type(new_export_type: ExportType) -> void:
42+
export_type = new_export_type
43+
_render_title()
44+
_render_status()
45+
46+
47+
func _set_file_type(new_file_type: FileType) -> void:
48+
file_type = new_file_type
49+
_render_title()
50+
_render_status()
51+
#endregion
52+
53+
54+
#region LIFECYCLE
55+
# TODO: check where this is called
56+
func render(p_export_type: ExportType, p_file_type: FileType, p_dialogue_sequence_ast: ParleyDialogueSequenceAst) -> void:
57+
file_type = p_file_type
58+
export_type = p_export_type
59+
dialogue_ast = p_dialogue_sequence_ast
60+
61+
if not path_editor:
62+
return
63+
base_path = "res://exports"
64+
65+
export_path = base_path.path_join(_generate_file_name())
66+
path_editor.text = export_path
67+
show()
68+
69+
70+
func _render_title() -> void:
71+
title = "Export %s to %s" % [_get_export_type_name(), _get_file_type_name()]
72+
73+
74+
func _render_status() -> void:
75+
var text: String = """[color=#19e34f]
76+
[ul]%s path name is valid[/ul][/color][color=#19e34f]
77+
[ul]Will export the %s to %s[/ul][/color]
78+
""" % [_get_file_type_name(), _get_export_type_name(), _get_file_type_name()]
79+
if status_label:
80+
status_label.text = text
81+
#endregion
82+
83+
84+
#region SIGNALS
85+
func _on_export_button_pressed() -> void:
86+
if not dialogue_ast:
87+
push_error(ParleyUtils.log.error_msg("No Dialogue AST associated with export."))
88+
return
89+
export_requested.emit(export_type, file_type, dialogue_ast, export_path)
90+
hide()
91+
92+
93+
func _on_choose_path_modal_file_selected(path: String) -> void:
94+
if path_editor:
95+
path_editor.text = path
96+
base_path = path.get_base_dir()
97+
export_path = path
98+
99+
100+
func _on_cancel_button_pressed() -> void:
101+
hide()
102+
103+
104+
func _on_close_requested() -> void:
105+
hide()
106+
107+
108+
func _on_choose_path_button_pressed() -> void:
109+
if choose_path_modal:
110+
choose_path_modal.show()
111+
choose_path_modal.current_dir = base_path
112+
choose_path_modal.current_file = export_path
113+
#endregion
114+
115+
116+
#region CRUD
117+
func _generate_file_name() -> String:
118+
var timestamp: String = str(int(Time.get_unix_time_from_system()))
119+
var dialogue_sequence_ast_path: String = dialogue_ast.resource_path if dialogue_ast.resource_path else "dialogue.ds"
120+
var dialogue_sequence_ast_path_parts: PackedStringArray = dialogue_sequence_ast_path.split('/')
121+
var dialogue_sequence_name: String = dialogue_sequence_ast_path_parts[dialogue_sequence_ast_path_parts.size() - 1].to_snake_case().replace('.ds', '')
122+
var file_context: String = ""
123+
match export_type:
124+
ExportType.DialogueTextTranslation:
125+
file_context = "dialogue_text_translations"
126+
ExportType.CharacterNameTranslation:
127+
file_context = "character_name_translations"
128+
ExportType.Node:
129+
file_context = dialogue_sequence_name
130+
return "export_%s_%s%s" % [file_context, timestamp, _get_file_type_extension()]
131+
132+
133+
func _get_file_type_name() -> String:
134+
match file_type:
135+
FileType.Csv:
136+
return "CSV"
137+
_:
138+
push_warning(ParleyUtils.log.warn_msg("Unknown File Type: %s, defaulting to CSV" % ParleyUtils.string.get_enum_key_name(FileType, file_type)))
139+
return "CSV"
140+
141+
142+
func _get_file_type_extension() -> String:
143+
match file_type:
144+
FileType.Csv:
145+
return ".csv"
146+
_:
147+
push_warning(ParleyUtils.log.warn_msg("Unknown File Type: %s, defaulting to CSV" % ParleyUtils.string.get_enum_key_name(FileType, file_type)))
148+
return ".csv"
149+
150+
151+
func _get_export_type_name() -> String:
152+
match export_type:
153+
ExportType.Node:
154+
return "Dialogue Sequence"
155+
ExportType.DialogueTextTranslation:
156+
return "Dialogue Text Translations"
157+
ExportType.CharacterNameTranslation:
158+
return "Character Name Translations"
159+
_:
160+
push_warning(ParleyUtils.log.warn_msg("Unknown Export Type: %s, defaulting to Dialogue Text Translations" % ParleyUtils.string.get_enum_key_name(ExportType, export_type)))
161+
return "Dialogue Text Translations"
162+
#endregion

0 commit comments

Comments
 (0)