mirror of
https://codeberg.org/StreamGraph/StreamGraph.git
synced 2024-11-13 19:49:55 +01:00
1ce3cd0367
Reviewed-on: https://codeberg.org/StreamGraph/StreamGraph/pulls/146 Co-authored-by: Lera Elvoé <yagich@poto.cafe> Co-committed-by: Lera Elvoé <yagich@poto.cafe>
654 lines
23 KiB
GDScript
654 lines
23 KiB
GDScript
# (c) 2023-present Eroax
|
|
# (c) 2023-present Yagich
|
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
|
extends Control
|
|
class_name DeckHolderRenderer
|
|
|
|
## Renderer class for [DeckHolder]
|
|
##
|
|
## Entry point for the [GraphEdit] based Renderer
|
|
|
|
## Reference to the base scene for [DeckRendererGraphEdit]
|
|
@export var DECK_SCENE: PackedScene
|
|
@export var DEBUG_DECKS_LIST: PackedScene
|
|
@export var DEBUG_NODES_LIST: PackedScene
|
|
|
|
const PERSISTENCE_NAMESPACE := "default"
|
|
|
|
## Reference to the main windows [TabContainerCustom]
|
|
@onready var tab_container := %TabContainerCustom as TabContainerCustom
|
|
## Reference to the [FileDialog] used for File operations through the program.
|
|
@onready var file_dialog: FileDialog = $FileDialog
|
|
|
|
## Enum for storing the Options in the "File" PopupMenu.
|
|
enum FileMenuId {
|
|
NEW,
|
|
OPEN,
|
|
SAVE = 3,
|
|
SAVE_AS,
|
|
CLOSE = 6,
|
|
RECENTS,
|
|
}
|
|
@onready var file_popup_menu: PopupMenu = %File as PopupMenu
|
|
var max_recents := 4
|
|
var recent_files := []
|
|
var recent_path: String
|
|
@onready var unsaved_changes_dialog_single_deck := $UnsavedChangesDialogSingleDeck as UnsavedChangesDialogSingleDeck
|
|
@onready var unsaved_changes_dialog: ConfirmationDialog = $UnsavedChangesDialog
|
|
|
|
enum ConnectionsMenuId {
|
|
OBS,
|
|
TWITCH,
|
|
RPC,
|
|
}
|
|
|
|
enum DebugMenuId {
|
|
DECKS,
|
|
NODES,
|
|
EMBED_SUBWINDOWS,
|
|
}
|
|
@onready var debug_popup_menu: PopupMenu = %Debug
|
|
|
|
enum HelpMenuId {
|
|
DOCS,
|
|
ABOUT,
|
|
}
|
|
@onready var about_dialog: AcceptDialog = %AboutDialog
|
|
|
|
enum EditMenuId {
|
|
COPY,
|
|
PASTE,
|
|
DUPLICATE,
|
|
SETTINGS,
|
|
}
|
|
@onready var edit_popup_menu: PopupMenu = %Edit
|
|
@onready var settings_dialog: SettingsDialog = %SettingsDialog
|
|
|
|
## Weak Reference to the Deck that is currently going to be saved.
|
|
var _deck_to_save: WeakRef
|
|
|
|
@onready var no_obsws := %NoOBSWS as NoOBSWS
|
|
|
|
@onready var obs_setup_dialog := $OBSWebsocketSetupDialog as OBSWebsocketSetupDialog
|
|
@onready var twitch_setup_dialog := $Twitch_Setup_Dialog as TwitchSetupDialog
|
|
@onready var rpc_setup_dialog := $RPCSetupDialog as RPCSetupDialog
|
|
|
|
@onready var bottom_dock: BottomDock = %BottomDock
|
|
@onready var sidebar_split: HSplitContainer = %SidebarSplit
|
|
@onready var sidebar: Sidebar = %Sidebar as Sidebar
|
|
|
|
signal quit_completed()
|
|
signal rpc_start_requested(port: int)
|
|
signal rpc_stop_requested()
|
|
|
|
|
|
func _ready() -> void:
|
|
tab_container.add_button_pressed.connect(add_empty_deck)
|
|
tab_container.tab_changed.connect(_on_tab_container_tab_changed)
|
|
tab_container.tab_about_to_change.connect(_on_tab_container_tab_about_to_change)
|
|
RendererPersistence.init_namespace(PERSISTENCE_NAMESPACE)
|
|
|
|
var embed_subwindows: bool = RendererPersistence.get_or_create(PERSISTENCE_NAMESPACE, "config", "embed_subwindows", true)
|
|
debug_popup_menu.set_item_checked(
|
|
DebugMenuId.EMBED_SUBWINDOWS,
|
|
embed_subwindows
|
|
)
|
|
|
|
get_tree().get_root().gui_embed_subwindows = embed_subwindows
|
|
file_dialog.use_native_dialog = not embed_subwindows
|
|
|
|
recent_files = RendererPersistence.get_or_create(
|
|
PERSISTENCE_NAMESPACE, "config",
|
|
"recent_files", []
|
|
)
|
|
recent_path = RendererPersistence.get_or_create(
|
|
PERSISTENCE_NAMESPACE, "config",
|
|
"recent_path", OS.get_system_dir(OS.SYSTEM_DIR_DOCUMENTS)
|
|
)
|
|
|
|
RendererShortcuts.load_overrides()
|
|
|
|
reset_popup_menu_shortcuts()
|
|
|
|
add_recents_to_menu()
|
|
|
|
var rpc_port: int = RendererPersistence.get_or_create(
|
|
PERSISTENCE_NAMESPACE, "config",
|
|
"rpc_server_port", 6907
|
|
)
|
|
rpc_setup_dialog.set_port(rpc_port)
|
|
rpc_setup_dialog.start_requested.connect(
|
|
func(port: int):
|
|
rpc_start_requested.emit(port)
|
|
RendererPersistence.set_value(
|
|
PERSISTENCE_NAMESPACE, "config",
|
|
"rpc_server_port", port
|
|
)
|
|
)
|
|
rpc_setup_dialog.stop_requested.connect(
|
|
func():
|
|
rpc_stop_requested.emit()
|
|
)
|
|
|
|
rpc_setup_dialog.confirmed.connect(
|
|
func():
|
|
RendererPersistence.set_value(
|
|
PERSISTENCE_NAMESPACE, "config",
|
|
"rpc_server_port", rpc_setup_dialog.get_port()
|
|
)
|
|
)
|
|
|
|
tab_container.tab_close_requested.connect(
|
|
func(tab: int):
|
|
if tab_container.get_tab_metadata(tab, "dirty") and not tab_container.get_tab_metadata(tab, "group"):
|
|
unsaved_changes_dialog_single_deck.set_meta("tab", tab)
|
|
unsaved_changes_dialog_single_deck.show()
|
|
return
|
|
await close_tab(tab)
|
|
)
|
|
|
|
file_dialog.canceled.connect(disconnect_file_dialog_signals)
|
|
Connections.obs_websocket = no_obsws
|
|
Connections.twitch = %Twitch_Connection
|
|
|
|
no_obsws.event_received.connect(
|
|
func(m: NoOBSWS.Message):
|
|
Connections._obs_event_received(m.get_data())
|
|
)
|
|
|
|
Connections.twitch.chat_received_rich.connect(Connections._twitch_chat_received)
|
|
|
|
bottom_dock.variable_viewer.top_field_edited.connect(
|
|
func(old_name: String, new_name: String, new_value: Variant) -> void:
|
|
get_active_deck_renderer().dirty = true
|
|
get_active_deck().update_variable(old_name, new_name, new_value)
|
|
)
|
|
|
|
bottom_dock.variable_viewer.top_field_removed.connect(
|
|
func(field_name: String) -> void:
|
|
get_active_deck_renderer().dirty = true
|
|
get_active_deck().remove_variable(field_name)
|
|
)
|
|
|
|
sidebar_split.dragger_visibility = SplitContainer.DRAGGER_HIDDEN_COLLAPSED
|
|
sidebar.go_to_node_requested.connect(
|
|
func(node_id: String) -> void:
|
|
# we can reasonably assume its the current deck
|
|
var deck := get_active_deck()
|
|
var node := deck.get_node(node_id)
|
|
var deck_renderer := get_active_deck_renderer()
|
|
deck_renderer.focus_node(deck_renderer.get_node_renderer(node))
|
|
)
|
|
|
|
|
|
func reset_popup_menu_shortcuts() -> void:
|
|
file_popup_menu.set_item_shortcut(FileMenuId.NEW, RendererShortcuts.get_shortcut("new_deck"))
|
|
file_popup_menu.set_item_shortcut(FileMenuId.OPEN, RendererShortcuts.get_shortcut("open_deck"))
|
|
file_popup_menu.set_item_shortcut(FileMenuId.SAVE, RendererShortcuts.get_shortcut("save_deck"))
|
|
file_popup_menu.set_item_shortcut(FileMenuId.SAVE_AS, RendererShortcuts.get_shortcut("save_deck_as"))
|
|
file_popup_menu.set_item_shortcut(FileMenuId.CLOSE, RendererShortcuts.get_shortcut("close_deck"))
|
|
|
|
edit_popup_menu.set_item_shortcut(EditMenuId.COPY, RendererShortcuts.get_shortcut("copy_nodes"))
|
|
edit_popup_menu.set_item_shortcut(EditMenuId.PASTE, RendererShortcuts.get_shortcut("paste_nodes"))
|
|
edit_popup_menu.set_item_shortcut(EditMenuId.DUPLICATE, RendererShortcuts.get_shortcut("duplicate_nodes"))
|
|
edit_popup_menu.set_item_shortcut(EditMenuId.SETTINGS, RendererShortcuts.get_shortcut("settings"))
|
|
|
|
|
|
func reset_recents_shortcuts() -> void:
|
|
for i in recent_files.size():
|
|
var s := RendererShortcuts.get_shortcut("open_recent_deck_%s" % [i + 1])
|
|
file_popup_menu.set_item_shortcut(file_popup_menu.get_item_count() - recent_files.size() + i, s)
|
|
|
|
|
|
func _notification(what: int) -> void:
|
|
if what == RendererShortcuts.NOTIFICATION_SHORTCUTS_UPDATED:
|
|
reset_popup_menu_shortcuts()
|
|
|
|
|
|
func _on_tab_container_tab_about_to_change(previous_tab: int) -> void:
|
|
var deck := get_deck_at_tab(previous_tab)
|
|
Util.safe_disconnect(deck.variables_updated, bottom_dock.rebuild_variable_tree)
|
|
|
|
var deck_renderer := get_deck_renderer_at_tab(previous_tab)
|
|
Util.safe_disconnect(deck_renderer.node_selected, set_sidebar_node)
|
|
Util.safe_disconnect(deck_renderer.node_deselected, set_sidebar_node)
|
|
|
|
Util.pop_batch(&"sidebar_signals")
|
|
|
|
|
|
func _on_tab_container_tab_changed(tab: int) -> void:
|
|
var is_group = tab_container.get_tab_metadata(tab, "group", false)
|
|
file_popup_menu.set_item_disabled(FileMenuId.SAVE, is_group)
|
|
file_popup_menu.set_item_disabled(FileMenuId.SAVE_AS, is_group)
|
|
bottom_dock.rebuild_variable_tree(get_active_deck().variable_stack)
|
|
var deck := get_active_deck()
|
|
deck.variables_updated.connect(bottom_dock.rebuild_variable_tree.bind(deck.variable_stack))
|
|
|
|
sidebar.set_edited_deck(deck.id)
|
|
get_active_deck_renderer().node_selected.connect(set_sidebar_node)
|
|
get_active_deck_renderer().node_deselected.connect(set_sidebar_node)
|
|
sidebar.refresh_node_list()
|
|
|
|
var batch := Util.batch_begin()
|
|
batch.add(deck.node_added, refresh_sidebar_node_list)
|
|
batch.add(deck.node_removed, refresh_sidebar_node_list)
|
|
Util.push_batch(batch, &"sidebar_signals")
|
|
|
|
|
|
func set_sidebar_node(_node: Node) -> void:
|
|
var count = get_active_deck_renderer().get_selected_nodes().size()
|
|
if count != 1:
|
|
sidebar.set_edited_node()
|
|
return
|
|
|
|
var dnode := (get_active_deck_renderer().get_selected_nodes()[0] as DeckNodeRendererGraphNode).node
|
|
sidebar.set_edited_node(dnode._id)
|
|
|
|
|
|
func refresh_sidebar_node_list(_unused1 = null, _unused2 = null, _unused3 = null) -> void:
|
|
sidebar.refresh_node_list()
|
|
|
|
|
|
## Called when the File button in the [MenuBar] is pressed with the [param id]
|
|
## of the button within it that was pressed.
|
|
func _on_file_id_pressed(id: int) -> void:
|
|
match id:
|
|
FileMenuId.NEW:
|
|
add_empty_deck()
|
|
FileMenuId.OPEN:
|
|
open_open_dialog(recent_path)
|
|
FileMenuId.SAVE when tab_container.get_tab_count() > 0:
|
|
save_active_deck()
|
|
FileMenuId.SAVE_AS when tab_container.get_tab_count() > 0:
|
|
open_save_dialog(tab_container.get_tab_metadata(tab_container.get_current_tab(), "path"))
|
|
FileMenuId.CLOSE:
|
|
close_current_tab()
|
|
_ when id in range(FileMenuId.RECENTS, FileMenuId.RECENTS + max_recents + 1):
|
|
open_deck_at_path(recent_files[id - FileMenuId.RECENTS - 1])
|
|
|
|
|
|
func _on_edit_id_pressed(id: int) -> void:
|
|
match id:
|
|
EditMenuId.SETTINGS:
|
|
settings_dialog.popup_centered()
|
|
EditMenuId.COPY:
|
|
var r := get_active_deck_renderer()
|
|
r._on_copy_nodes_request()
|
|
EditMenuId.PASTE:
|
|
var r := get_active_deck_renderer()
|
|
r._on_paste_nodes_request()
|
|
EditMenuId.DUPLICATE:
|
|
var r := get_active_deck_renderer()
|
|
r._on_duplicate_nodes_request()
|
|
|
|
|
|
func _on_edit_about_to_popup() -> void:
|
|
# enable/disable the copy/paste buttons depending on if there's a deck renderer and if it has nodes selected
|
|
if tab_container.get_tab_count() == 0:
|
|
edit_popup_menu.set_item_disabled(EditMenuId.COPY, true)
|
|
edit_popup_menu.set_item_disabled(EditMenuId.PASTE, true)
|
|
edit_popup_menu.set_item_disabled(EditMenuId.DUPLICATE, true)
|
|
return
|
|
|
|
edit_popup_menu.set_item_disabled(EditMenuId.PASTE, false)
|
|
var r := get_active_deck_renderer()
|
|
edit_popup_menu.set_item_disabled(EditMenuId.COPY, r.get_selected_nodes().size() == 0)
|
|
edit_popup_menu.set_item_disabled(EditMenuId.DUPLICATE, r.get_selected_nodes().size() == 0)
|
|
|
|
|
|
## Adds an empty [DeckRendererGraphEdit] with a corresponding [Deck] for it's data.
|
|
func add_empty_deck() -> void:
|
|
var deck := DeckHolder.add_empty_deck()
|
|
var inst: DeckRendererGraphEdit = DECK_SCENE.instantiate()
|
|
inst.deck = deck
|
|
var tab := tab_container.add_content(inst, "<unsaved deck>")
|
|
tab_container.set_tab_metadata(tab, "id", deck.id)
|
|
tab_container.set_tab_metadata(tab, "group", false)
|
|
tab_container.set_tab_metadata(tab, "path", recent_path.path_join(""))
|
|
inst.group_enter_requested.connect(_on_deck_renderer_group_enter_requested)
|
|
inst.dirty_state_changed.connect(_on_deck_renderer_dirty_state_changed.bind(inst))
|
|
tab_container.set_current_tab(tab)
|
|
bottom_dock.variable_viewer.enable_new_button()
|
|
|
|
|
|
## Closes the current tab in [member tab_container]
|
|
func close_current_tab() -> void:
|
|
tab_container.close_tab(tab_container.get_current_tab())
|
|
|
|
|
|
func close_tab(tab: int) -> void:
|
|
if not tab_container.get_tab_metadata(tab, "group"):
|
|
var groups := DeckHolder.close_deck(tab_container.get_tab_metadata(tab, "id"))
|
|
# close tabs associated with this deck's groups
|
|
for group in groups:
|
|
for c_tab in range(tab_container.get_tab_count() - 1, -1, -1):
|
|
if tab_container.get_tab_metadata(c_tab, "id") == group:
|
|
tab_container.close_tab(c_tab)
|
|
await get_tree().process_frame
|
|
|
|
tab_container.close_tab(tab)
|
|
if tab_container.get_tab_count() == 0:
|
|
bottom_dock.variable_viewer.disable_new_button()
|
|
|
|
## Opens [member file_dialog] with the mode [member FileDialog.FILE_MODE_SAVE_FILE]
|
|
## as well as getting a weakref to the active [Deck]
|
|
func open_save_dialog(path: String) -> void:
|
|
file_dialog.file_mode = FileDialog.FILE_MODE_SAVE_FILE
|
|
file_dialog.title = "Save a Deck"
|
|
file_dialog.current_path = path
|
|
_deck_to_save = weakref(get_active_deck())
|
|
file_dialog.popup_centered()
|
|
file_dialog.file_selected.connect(_on_file_dialog_save_file, CONNECT_ONE_SHOT)
|
|
|
|
## Opens [member file_dialog] with the mode [FileDialog.FILE_MODE_OPEN_FILES]
|
|
## with the supplied [param path]
|
|
func open_open_dialog(path: String) -> void:
|
|
file_dialog.file_mode = FileDialog.FILE_MODE_OPEN_FILES
|
|
file_dialog.title = "Open Deck(s)"
|
|
file_dialog.current_path = path + "/"
|
|
file_dialog.popup_centered()
|
|
file_dialog.files_selected.connect(_on_file_dialog_open_files, CONNECT_ONE_SHOT)
|
|
|
|
## Connected to [signal FileDialog.save_file] on [member file_dialog].
|
|
## Saves the selected [Deck] if it still exists.
|
|
func _on_file_dialog_save_file(path: String) -> void:
|
|
var deck: Deck = _deck_to_save.get_ref() as Deck
|
|
if not deck:
|
|
return
|
|
|
|
deck.save_path = path
|
|
tab_container.set_tab_title(tab_container.get_current_tab(), path.get_file())
|
|
var renderer: DeckRendererGraphEdit = tab_container.get_content(tab_container.get_current_tab()) as DeckRendererGraphEdit
|
|
renderer.dirty = false
|
|
# TODO: put this into DeckHolder instead
|
|
var json := JSON.stringify(deck.to_dict(), "\t")
|
|
var f := FileAccess.open(path, FileAccess.WRITE)
|
|
f.store_string(json)
|
|
add_recent_file(get_active_deck().save_path)
|
|
recent_path = path.get_base_dir()
|
|
RendererPersistence.set_value(PERSISTENCE_NAMESPACE, "config", "recent_path", recent_path)
|
|
|
|
|
|
## Connected to [signal FileDialog.open_files] on [member file_dialog]. Opens
|
|
## the selected paths, instantiating [DeckRenderGraphEdit]s and [Deck]s for each.
|
|
func _on_file_dialog_open_files(paths: PackedStringArray) -> void:
|
|
for path in paths:
|
|
open_deck_at_path(path)
|
|
|
|
|
|
func open_deck_at_path(path: String) -> void:
|
|
for tab in tab_container.get_tab_count():
|
|
if tab_container.get_tab_metadata(tab, "path") == path:
|
|
tab_container.set_current_tab(tab)
|
|
return
|
|
|
|
var deck := DeckHolder.open_deck_from_file(path)
|
|
var inst: DeckRendererGraphEdit = DECK_SCENE.instantiate()
|
|
inst.deck = deck
|
|
var tab := tab_container.add_content(inst, path.get_file())
|
|
tab_container.set_tab_metadata(tab, "id", deck.id)
|
|
tab_container.set_tab_metadata(tab, "group", false)
|
|
tab_container.set_tab_metadata(tab, "path", path)
|
|
inst.initialize_from_deck()
|
|
inst.group_enter_requested.connect(_on_deck_renderer_group_enter_requested)
|
|
inst.dirty_state_changed.connect(_on_deck_renderer_dirty_state_changed.bind(inst))
|
|
add_recent_file(path)
|
|
recent_path = path.get_base_dir()
|
|
RendererPersistence.set_value(PERSISTENCE_NAMESPACE, "config", "recent_path", recent_path)
|
|
tab_container.set_current_tab(tab)
|
|
bottom_dock.variable_viewer.enable_new_button()
|
|
|
|
|
|
## Returns the current deck in the [member tab_container].
|
|
func get_active_deck() -> Deck:
|
|
return get_deck_at_tab(tab_container.get_current_tab())
|
|
|
|
|
|
## Returns the deck at [param tab] in the [member tab_container].
|
|
func get_deck_at_tab(tab: int) -> Deck:
|
|
return get_deck_renderer_at_tab(tab).deck
|
|
|
|
|
|
## Returns the current deck renderer in the [member tab_container].
|
|
func get_active_deck_renderer() -> DeckRendererGraphEdit:
|
|
return get_deck_renderer_at_tab(tab_container.get_current_tab())
|
|
|
|
|
|
## Returns the deck renderer at [param tab] in the [member tab_container].
|
|
func get_deck_renderer_at_tab(tab: int) -> DeckRendererGraphEdit:
|
|
if tab_container.is_empty():
|
|
return null
|
|
|
|
return tab_container.get_content(tab) as DeckRendererGraphEdit
|
|
|
|
|
|
## Saves the active [Deck] in [member tab_container]
|
|
func save_active_deck() -> void:
|
|
save_tab(tab_container.get_current_tab())
|
|
|
|
|
|
func save_tab(tab: int) -> void:
|
|
if tab_container.get_tab_metadata(tab, "group"):
|
|
return
|
|
|
|
var renderer := tab_container.get_content(tab) as DeckRendererGraphEdit
|
|
var deck := renderer.deck
|
|
if deck.save_path.is_empty():
|
|
open_save_dialog("res://")
|
|
else:
|
|
var json := JSON.stringify(deck.to_dict(), "\t")
|
|
var f := FileAccess.open(deck.save_path, FileAccess.WRITE)
|
|
f.store_string(json)
|
|
add_recent_file(deck.save_path)
|
|
renderer.dirty = false
|
|
|
|
|
|
## Disconnects the [FileDialog] signals if they are already connected.
|
|
func disconnect_file_dialog_signals() -> void:
|
|
if file_dialog.file_selected.is_connected(_on_file_dialog_save_file):
|
|
file_dialog.file_selected.disconnect(_on_file_dialog_save_file)
|
|
|
|
if file_dialog.files_selected.is_connected(_on_file_dialog_open_files):
|
|
file_dialog.files_selected.disconnect(_on_file_dialog_open_files)
|
|
|
|
## Connected to [signal DeckRenderGraphEdit.group_entered_request] to allow entering
|
|
## groups based off the given [param group_id] and [param deck]. As well as adding
|
|
## a corresponding tab to [member tab_container]
|
|
func _on_deck_renderer_group_enter_requested(group_id: String) -> void:
|
|
#var group_deck := deck.get_group(group_id)
|
|
for tab in tab_container.get_tab_count():
|
|
if tab_container.get_tab_metadata(tab, "id") == group_id:
|
|
tab_container.set_current_tab(tab)
|
|
return
|
|
var group_deck := DeckHolder.get_deck(group_id)
|
|
var deck_renderer: DeckRendererGraphEdit = DECK_SCENE.instantiate()
|
|
deck_renderer.deck = group_deck
|
|
deck_renderer.initialize_from_deck()
|
|
var tab := tab_container.add_content(deck_renderer, "(g) %s" % group_id.left(8))
|
|
tab_container.set_tab_metadata(tab, "id", group_id)
|
|
tab_container.set_tab_metadata(tab, "group", true)
|
|
deck_renderer.group_enter_requested.connect(_on_deck_renderer_group_enter_requested)
|
|
tab_container.set_current_tab(tab)
|
|
|
|
|
|
func _on_connections_id_pressed(id: int) -> void:
|
|
match id:
|
|
ConnectionsMenuId.OBS:
|
|
obs_setup_dialog.popup_centered()
|
|
ConnectionsMenuId.TWITCH:
|
|
twitch_setup_dialog.popup_centered()
|
|
ConnectionsMenuId.RPC:
|
|
rpc_setup_dialog.popup_centered()
|
|
|
|
|
|
func _on_obs_websocket_setup_dialog_connect_button_pressed(state: OBSWebsocketSetupDialog.ConnectionState) -> void:
|
|
match state:
|
|
OBSWebsocketSetupDialog.ConnectionState.DISCONNECTED:
|
|
obs_setup_dialog.set_button_state(OBSWebsocketSetupDialog.ConnectionState.CONNECTING)
|
|
no_obsws.subscriptions = obs_setup_dialog.get_subscriptions()
|
|
no_obsws.connect_to_obsws(obs_setup_dialog.get_port(), obs_setup_dialog.get_password())
|
|
await no_obsws.connection_ready
|
|
obs_setup_dialog.set_button_state(OBSWebsocketSetupDialog.ConnectionState.CONNECTED)
|
|
OBSWebsocketSetupDialog.ConnectionState.CONNECTED:
|
|
no_obsws.disconnect_from_obsws()
|
|
obs_setup_dialog.set_button_state(OBSWebsocketSetupDialog.ConnectionState.DISCONNECTED)
|
|
|
|
|
|
func _process(delta: float) -> void:
|
|
DeckHolder.send_event(&"process", {"delta": delta})
|
|
|
|
|
|
func _on_debug_id_pressed(id: int) -> void:
|
|
match id:
|
|
DebugMenuId.DECKS:
|
|
var d := AcceptDialog.new()
|
|
var debug_decks: DebugDecksList = DEBUG_DECKS_LIST.instantiate()
|
|
d.add_child(debug_decks)
|
|
d.canceled.connect(d.queue_free)
|
|
d.confirmed.connect(d.queue_free)
|
|
debug_decks.item_pressed.connect(_on_debug_decks_viewer_item_pressed)
|
|
add_child(d)
|
|
d.popup_centered()
|
|
DebugMenuId.NODES:
|
|
var d := AcceptDialog.new()
|
|
var debug_nodes: DebugNodesList = DEBUG_NODES_LIST.instantiate()
|
|
d.add_child(debug_nodes)
|
|
d.canceled.connect(d.queue_free)
|
|
d.confirmed.connect(d.queue_free)
|
|
debug_nodes.build(get_active_deck())
|
|
add_child(d)
|
|
d.popup_centered()
|
|
DebugMenuId.EMBED_SUBWINDOWS:
|
|
var c := debug_popup_menu.is_item_checked(id)
|
|
debug_popup_menu.set_item_checked(id, not c)
|
|
get_tree().get_root().gui_embed_subwindows = not c
|
|
RendererPersistence.set_value(PERSISTENCE_NAMESPACE, "config", "embed_subwindows", not c)
|
|
file_dialog.use_native_dialog = c
|
|
|
|
|
|
func _on_debug_decks_viewer_item_pressed(deck_id: String, instance_id: String) -> void:
|
|
if instance_id == "":
|
|
var deck := DeckHolder.get_deck(deck_id)
|
|
var inst: DeckRendererGraphEdit = DECK_SCENE.instantiate()
|
|
inst.deck = deck
|
|
var tab := tab_container.add_content(inst, "<Deck %s>" % [deck_id.left(8)])
|
|
tab_container.set_tab_metadata(tab, "id", deck.id)
|
|
inst.initialize_from_deck()
|
|
inst.group_enter_requested.connect(_on_deck_renderer_group_enter_requested)
|
|
tab_container.set_current_tab(tab)
|
|
else:
|
|
var deck := DeckHolder.get_group_instance(deck_id, instance_id)
|
|
var inst: DeckRendererGraphEdit = DECK_SCENE.instantiate()
|
|
inst.deck = deck
|
|
var tab := tab_container.add_content(inst, "<Group %s::%s>" % [deck_id.left(8), instance_id.left(8)])
|
|
tab_container.set_tab_metadata(tab, "id", deck.id)
|
|
inst.initialize_from_deck()
|
|
inst.group_enter_requested.connect(_on_deck_renderer_group_enter_requested)
|
|
tab_container.set_current_tab(tab)
|
|
|
|
|
|
func _on_deck_renderer_dirty_state_changed(renderer: DeckRendererGraphEdit) -> void:
|
|
var idx: int = range(tab_container.get_tab_count()).filter(
|
|
func(x: int):
|
|
return tab_container.get_content(x) == renderer
|
|
)[0]
|
|
var title := tab_container.get_tab_title(idx).trim_suffix("(*)")
|
|
if renderer.dirty:
|
|
tab_container.set_tab_title(idx, "%s(*)" % title)
|
|
else:
|
|
tab_container.set_tab_title(idx, title.trim_suffix("(*)"))
|
|
tab_container.set_tab_metadata(idx, "dirty", renderer.dirty)
|
|
|
|
|
|
func add_recent_file(path: String) -> void:
|
|
var item := recent_files.find(path)
|
|
if item == -1:
|
|
recent_files.push_front(path)
|
|
else:
|
|
recent_files.push_front(recent_files.pop_at(item))
|
|
recent_files = recent_files.slice(0, max_recents)
|
|
|
|
add_recents_to_menu()
|
|
|
|
|
|
func add_recents_to_menu() -> void:
|
|
if recent_files.is_empty():
|
|
return
|
|
|
|
if file_popup_menu.get_item_count() > FileMenuId.RECENTS + 1:
|
|
var end := file_popup_menu.get_item_count() - FileMenuId.RECENTS - 1
|
|
for i in end:
|
|
file_popup_menu.remove_item(file_popup_menu.get_item_count() - 1)
|
|
|
|
var reduce_length := recent_files.any(func(x: String): return x.length() > 35)
|
|
|
|
for i in recent_files.size():
|
|
var file = recent_files[i] as String
|
|
if reduce_length:
|
|
# shorten the basepath to be the first letter of all folders
|
|
var base: String = Array(
|
|
file.get_base_dir().split("/", false)
|
|
).reduce(
|
|
func(a: String, s: String):
|
|
return a + s[0] + "/",
|
|
"/")
|
|
var filename := file.get_file()
|
|
file = base.path_join(filename)
|
|
|
|
file_popup_menu.add_item(file)
|
|
|
|
reset_recents_shortcuts()
|
|
RendererPersistence.set_value(PERSISTENCE_NAMESPACE, "config", "recent_files", recent_files)
|
|
|
|
|
|
func request_quit() -> void:
|
|
RendererPersistence.commit(PERSISTENCE_NAMESPACE)
|
|
|
|
if range(tab_container.get_tab_count()).any(func(x: int): return tab_container.get_content(x).dirty):
|
|
unsaved_changes_dialog.show()
|
|
else:
|
|
for i in range(tab_container.get_tab_count() - 1, -1, -1):
|
|
await close_tab(i)
|
|
|
|
#get_tree().quit()
|
|
quit_completed.emit()
|
|
|
|
|
|
func _on_unsaved_changes_dialog_single_deck_confirmed() -> void:
|
|
save_tab(unsaved_changes_dialog_single_deck.get_meta("tab"))
|
|
await close_tab(unsaved_changes_dialog_single_deck.get_meta("tab"))
|
|
|
|
|
|
func _on_unsaved_changes_dialog_single_deck_custom_action(action: StringName) -> void:
|
|
if action == &"force_close":
|
|
await close_tab(unsaved_changes_dialog_single_deck.get_meta("tab"))
|
|
unsaved_changes_dialog_single_deck.hide()
|
|
|
|
|
|
func _on_unsaved_changes_dialog_confirmed() -> void:
|
|
for i in range(tab_container.get_tab_count() - 1, -1, -1):
|
|
await close_tab(i)
|
|
#get_tree().quit()
|
|
quit_completed.emit()
|
|
|
|
|
|
func _unhandled_key_input(event: InputEvent) -> void:
|
|
if RendererShortcuts.check_shortcut("toggle_bottom_dock", event):
|
|
bottom_dock.visible = !bottom_dock.visible
|
|
accept_event()
|
|
|
|
if RendererShortcuts.check_shortcut("toggle_sidebar", event):
|
|
sidebar.visible = !sidebar.visible
|
|
if sidebar.visible:
|
|
sidebar_split.dragger_visibility = SplitContainer.DRAGGER_VISIBLE
|
|
else:
|
|
sidebar_split.dragger_visibility = SplitContainer.DRAGGER_HIDDEN_COLLAPSED
|
|
|
|
|
|
func _on_help_id_pressed(id: int) -> void:
|
|
match id:
|
|
HelpMenuId.ABOUT:
|
|
about_dialog.show()
|
|
HelpMenuId.DOCS:
|
|
OS.shell_open("https://codeberg.org/Eroax/StreamGraph/wiki")
|
|
|