first commit
This commit is contained in:
23
addons/phantom_camera/scripts/panel/editor.gd
Normal file
23
addons/phantom_camera/scripts/panel/editor.gd
Normal file
@@ -0,0 +1,23 @@
|
||||
@tool
|
||||
extends VBoxContainer
|
||||
|
||||
#region Onready
|
||||
|
||||
@onready var updater: Control = %UpdateButton
|
||||
@onready var viewfinder: Control = %ViewfinderPanel
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Variables
|
||||
|
||||
var editor_plugin: EditorPlugin
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Private Functions
|
||||
|
||||
func _ready():
|
||||
updater.editor_plugin = editor_plugin
|
||||
|
||||
#endregion
|
||||
1
addons/phantom_camera/scripts/panel/editor.gd.uid
Normal file
1
addons/phantom_camera/scripts/panel/editor.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://cgfwg3paxkj2x
|
||||
@@ -0,0 +1,162 @@
|
||||
#######################################################################
|
||||
# Credit goes to the Dialogue Manager plugin for this script
|
||||
# Check it out at: https://github.com/nathanhoad/godot_dialogue_manager
|
||||
#######################################################################
|
||||
|
||||
@tool
|
||||
extends Control
|
||||
|
||||
#region Constants
|
||||
|
||||
const TEMP_FILE_NAME = "user://temp.zip"
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Signals
|
||||
|
||||
signal failed()
|
||||
signal updated(updated_to_version: String)
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region @onready
|
||||
|
||||
#@onready var logo: TextureRect = %Logo
|
||||
@onready var _download_verion: Label = %DownloadVersionLabel
|
||||
@onready var _download_http_request: HTTPRequest = %DownloadHTTPRequest
|
||||
@onready var _download_button: Button = %DownloadButton
|
||||
@onready var _download_button_bg: NinePatchRect = %DownloadButtonBG
|
||||
@onready var _download_label: Label = %UpdateLabel
|
||||
|
||||
@onready var _breaking_label: Label = %BreakingLabel
|
||||
@onready var _breaking_margin_container: MarginContainer = %BreakingMarginContainer
|
||||
@onready var _breaking_options_button: OptionButton = %BreakingOptionButton
|
||||
#@onready var current_version_label: Label = %CurrentVersionLabel
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Variables
|
||||
|
||||
# Todo - For 4.2 upgrade - Shows current version
|
||||
var _download_dialogue: AcceptDialog
|
||||
var _button_texture_default: Texture2D = load("res://addons/phantom_camera/assets/PhantomCameraBtnPrimaryDefault.png")
|
||||
var _button_texture_hover: Texture2D = load("res://addons/phantom_camera/assets/PhantomCameraBtnPrimaryHover.png")
|
||||
|
||||
var next_version_release: Dictionary:
|
||||
set(value):
|
||||
next_version_release = value
|
||||
_download_verion.text = "%s update is available for download" % value.tag_name.substr(1)
|
||||
# Todo - For 4.2 upgrade
|
||||
#current_version_label.text = "Current version is " + editor_plugin.get_version()
|
||||
get:
|
||||
return next_version_release
|
||||
|
||||
var _breaking_window_height: float = 520
|
||||
var _breaking_window_height_update: float = 600
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Private Functions
|
||||
|
||||
func _ready() -> void:
|
||||
_download_http_request.request_completed.connect(_on_http_request_request_completed)
|
||||
_download_button.pressed.connect(_on_download_button_pressed)
|
||||
_download_button.mouse_entered.connect(_on_mouse_entered)
|
||||
_download_button.mouse_exited.connect(_on_mouse_exited)
|
||||
|
||||
_breaking_label.hide()
|
||||
_breaking_margin_container.hide()
|
||||
_breaking_options_button.hide()
|
||||
|
||||
_breaking_options_button.item_selected.connect(_on_item_selected)
|
||||
|
||||
|
||||
func _on_item_selected(index: int) -> void:
|
||||
if index == 1:
|
||||
_download_button.show()
|
||||
_download_dialogue.size = Vector2(_download_dialogue.size.x, _breaking_window_height_update)
|
||||
else:
|
||||
_download_button.hide()
|
||||
_download_dialogue.size = Vector2(_download_dialogue.size.x, _breaking_window_height)
|
||||
|
||||
|
||||
func _on_download_button_pressed() -> void:
|
||||
_download_http_request.request(next_version_release.zipball_url)
|
||||
_download_button.disabled = true
|
||||
_download_label.text = "Downloading..."
|
||||
_download_button_bg.hide()
|
||||
|
||||
|
||||
func _on_mouse_entered() -> void:
|
||||
_download_button_bg.set_texture(_button_texture_hover)
|
||||
|
||||
|
||||
func _on_mouse_exited() -> void:
|
||||
_download_button_bg.set_texture(_button_texture_default)
|
||||
|
||||
|
||||
func _on_http_request_request_completed(result: int, response_code: int, headers: PackedStringArray, body: PackedByteArray) -> void:
|
||||
if result != HTTPRequest.RESULT_SUCCESS:
|
||||
failed.emit()
|
||||
return
|
||||
|
||||
# Save the downloaded zip
|
||||
var zip_file: FileAccess = FileAccess.open(TEMP_FILE_NAME, FileAccess.WRITE)
|
||||
zip_file.store_buffer(body)
|
||||
zip_file.close()
|
||||
|
||||
OS.move_to_trash(ProjectSettings.globalize_path("res://addons/phantom_camera"))
|
||||
|
||||
var zip_reader: ZIPReader = ZIPReader.new()
|
||||
zip_reader.open(TEMP_FILE_NAME)
|
||||
var files: PackedStringArray = zip_reader.get_files()
|
||||
|
||||
var base_path = files[1]
|
||||
# Remove archive folder
|
||||
files.remove_at(0)
|
||||
# Remove assets folder
|
||||
files.remove_at(0)
|
||||
|
||||
for path in files:
|
||||
var new_file_path: String = path.replace(base_path, "")
|
||||
if path.ends_with("/"):
|
||||
DirAccess.make_dir_recursive_absolute("res://addons/%s" % new_file_path)
|
||||
else:
|
||||
var file: FileAccess = FileAccess.open("res://addons/%s" % new_file_path, FileAccess.WRITE)
|
||||
file.store_buffer(zip_reader.read_file(path))
|
||||
|
||||
zip_reader.close()
|
||||
DirAccess.remove_absolute(TEMP_FILE_NAME)
|
||||
|
||||
updated.emit(next_version_release.tag_name.substr(1))
|
||||
|
||||
|
||||
func _on_notes_button_pressed() -> void:
|
||||
OS.shell_open(next_version_release.html_url)
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Functions
|
||||
|
||||
func show_updater_warning(next_version_number: Array, current_version_number: Array) -> void:
|
||||
var current_version_number_0: int = current_version_number[0] as int
|
||||
var current_version_number_1: int = current_version_number[1] as int
|
||||
|
||||
var next_version_number_0: int = next_version_number[0] as int # Major release number in the new release
|
||||
var next_version_number_1: int = next_version_number[1] as int # Minor release number in the new release
|
||||
|
||||
if next_version_number_0 > current_version_number_0 or \
|
||||
next_version_number_1 > current_version_number_1:
|
||||
_breaking_label.show()
|
||||
_breaking_margin_container.show()
|
||||
_breaking_options_button.show()
|
||||
_download_button.hide()
|
||||
|
||||
_download_dialogue = get_parent()
|
||||
_download_dialogue.size = Vector2(_download_dialogue.size.x, _breaking_window_height)
|
||||
|
||||
#endregion
|
||||
@@ -0,0 +1 @@
|
||||
uid://cjblcocen12r3
|
||||
177
addons/phantom_camera/scripts/panel/updater/update_button.gd
Normal file
177
addons/phantom_camera/scripts/panel/updater/update_button.gd
Normal file
@@ -0,0 +1,177 @@
|
||||
#######################################################################
|
||||
# Credit goes to the Dialogue Manager plugin for this script
|
||||
# Check it out at: https://github.com/nathanhoad/godot_dialogue_manager
|
||||
#######################################################################
|
||||
|
||||
@tool
|
||||
extends Button
|
||||
|
||||
#region Constants
|
||||
|
||||
const REMOTE_RELEASE_URL: StringName = "https://api.github.com/repos/ramokz/phantom-camera/releases"
|
||||
const UPDATER_CONSTANTS := preload("res://addons/phantom_camera/scripts/panel/updater/updater_constants.gd")
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region @onready
|
||||
|
||||
@onready var http_request: HTTPRequest = %HTTPRequest
|
||||
@onready var download_dialog: AcceptDialog = %DownloadDialog
|
||||
@onready var download_update_panel: Control = %DownloadUpdatePanel
|
||||
@onready var needs_reload_dialog: AcceptDialog = %NeedsReloadDialog
|
||||
@onready var update_failed_dialog: AcceptDialog = %UpdateFailedDialog
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Variables
|
||||
|
||||
# The main editor plugin
|
||||
var editor_plugin: EditorPlugin
|
||||
|
||||
var needs_reload: bool = false
|
||||
|
||||
# A lambda that gets called just before refreshing the plugin. Return false to stop the reload.
|
||||
var on_before_refresh: Callable = func(): return true
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Private Functions
|
||||
|
||||
func _ready() -> void:
|
||||
hide()
|
||||
|
||||
# Check for updates on GitHub Releases
|
||||
check_for_update()
|
||||
|
||||
pressed.connect(_on_update_button_pressed)
|
||||
http_request.request_completed.connect(_request_request_completed)
|
||||
download_update_panel.updated.connect(_on_download_update_panel_updated)
|
||||
needs_reload_dialog.confirmed.connect(_on_needs_reload_dialog_confirmed)
|
||||
|
||||
|
||||
func _request_request_completed(result: int, response_code: int, headers: PackedStringArray, body: PackedByteArray) -> void:
|
||||
if result != HTTPRequest.RESULT_SUCCESS: return
|
||||
|
||||
if not editor_plugin: return
|
||||
var current_version: String = editor_plugin.get_version()
|
||||
|
||||
# Work out the next version from the releases information on GitHub
|
||||
var response: Array = JSON.parse_string(body.get_string_from_utf8())
|
||||
if typeof(response) != TYPE_ARRAY: return
|
||||
|
||||
# GitHub releases are in order of creation, not order of version
|
||||
var versions: Array = response.filter(func(release):
|
||||
var version: String = release.tag_name.substr(1)
|
||||
return version_to_number(version) > version_to_number(current_version)
|
||||
)
|
||||
|
||||
if versions.size() > 0:
|
||||
if ProjectSettings.get_setting(UPDATER_CONSTANTS.setting_updater_mode) == 1: ## For console output mode
|
||||
|
||||
print_rich("
|
||||
[color=#3AB99A] ********[/color]
|
||||
[color=#3AB99A] ************[/color]
|
||||
[color=#3AB99A]**************[/color]
|
||||
[color=#3AB99A]****** *** *[/color]
|
||||
[color=#3AB99A]****** ***[/color]
|
||||
[color=#3AB99A]********** *****[/color]
|
||||
[color=#3AB99A]******** ***********[/color]
|
||||
[color=#3AB99A]******** *********** **[/color]
|
||||
[color=#3AB99A]********* **************[/color]
|
||||
[color=#3AB99A]********** *************[/color]
|
||||
[color=#3AB99A]** ** ** ******* **[/color]
|
||||
[font_size=18][b]New Phantom Camera version is available[/b][/font_size]")
|
||||
|
||||
if FileAccess.file_exists("res://dev_scenes/3d/dev_scene_3d.tscn"):
|
||||
print_rich("[font_size=14][color=#EAA15E][b]As you're using a fork of the project, you will need to update it manually[/b][/color][/font_size]")
|
||||
|
||||
print_rich("[font_size=12]If you don't want to see this message, then it can be disabled inside:\n[code]Project Settings/Phantom Camera/Updater/Show New Release Info on Editor Launch in Output[/code]")
|
||||
|
||||
return
|
||||
|
||||
download_update_panel.next_version_release = versions[0]
|
||||
download_update_panel.show_updater_warning(
|
||||
versions[0].tag_name.substr(1).split("."),
|
||||
current_version.split(".")
|
||||
)
|
||||
_set_scale()
|
||||
editor_plugin.panel_button.add_theme_color_override("font_color", Color("#3AB99A"))
|
||||
editor_plugin.panel_button.icon = load("res://addons/phantom_camera/icons/phantom_camera_updater_panel_icon.svg")
|
||||
editor_plugin.panel_button.add_theme_color_override("icon_normal_color", Color("#3AB99A"))
|
||||
show()
|
||||
|
||||
|
||||
func _on_update_button_pressed() -> void:
|
||||
if needs_reload:
|
||||
var will_refresh = on_before_refresh.call()
|
||||
if will_refresh:
|
||||
EditorInterface.restart_editor(true)
|
||||
else:
|
||||
_set_scale()
|
||||
download_dialog.popup_centered()
|
||||
|
||||
|
||||
func _set_scale() -> void:
|
||||
var scale: float = EditorInterface.get_editor_scale()
|
||||
download_dialog.min_size = Vector2(300, 250) * scale
|
||||
|
||||
|
||||
func _on_download_dialog_close_requested() -> void:
|
||||
download_dialog.hide()
|
||||
|
||||
|
||||
func _on_download_update_panel_updated(updated_to_version: String) -> void:
|
||||
download_dialog.hide()
|
||||
|
||||
needs_reload_dialog.dialog_text = "Reload to finish update"
|
||||
needs_reload_dialog.ok_button_text = "Reload"
|
||||
needs_reload_dialog.cancel_button_text = "Cancel"
|
||||
needs_reload_dialog.popup_centered()
|
||||
|
||||
needs_reload = true
|
||||
text = "Reload Project"
|
||||
|
||||
|
||||
func _on_download_update_panel_failed() -> void:
|
||||
download_dialog.hide()
|
||||
update_failed_dialog.dialog_text = "Updated Failed"
|
||||
update_failed_dialog.popup_centered()
|
||||
|
||||
|
||||
func _on_needs_reload_dialog_confirmed() -> void:
|
||||
EditorInterface.restart_editor(true)
|
||||
|
||||
|
||||
func _on_timer_timeout() -> void:
|
||||
if not needs_reload:
|
||||
check_for_update()
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Public Functions
|
||||
|
||||
# Convert a version number to an actually comparable number
|
||||
func version_to_number(version: String) -> int:
|
||||
var regex = RegEx.new()
|
||||
regex.compile("[a-zA-Z]+")
|
||||
if regex.search(str(version)): return 0
|
||||
|
||||
var bits = version.split(".")
|
||||
var version_bit: int
|
||||
var multiplier: int = 10000
|
||||
for i in bits.size():
|
||||
version_bit += bits[i].to_int() * multiplier / (10 ** (i))
|
||||
|
||||
return version_bit
|
||||
|
||||
|
||||
func check_for_update() -> void:
|
||||
if ProjectSettings.get_setting(UPDATER_CONSTANTS.setting_updater_mode) == 0: return
|
||||
|
||||
http_request.request(REMOTE_RELEASE_URL)
|
||||
|
||||
#endregion
|
||||
@@ -0,0 +1 @@
|
||||
uid://bwc42i46603qn
|
||||
@@ -0,0 +1,8 @@
|
||||
extends RefCounted
|
||||
|
||||
# Plugin Project Settings Sections
|
||||
const setting_phantom_camera: StringName = "phantom_camera/"
|
||||
const setting_updater_name: StringName = setting_phantom_camera + "updater/"
|
||||
|
||||
# Updater Settings
|
||||
const setting_updater_mode: StringName = setting_updater_name + "updater_mode"
|
||||
@@ -0,0 +1 @@
|
||||
uid://c8qkbc38waor2
|
||||
112
addons/phantom_camera/scripts/panel/viewfinder/host_list.gd
Normal file
112
addons/phantom_camera/scripts/panel/viewfinder/host_list.gd
Normal file
@@ -0,0 +1,112 @@
|
||||
@tool
|
||||
extends VBoxContainer
|
||||
|
||||
#region Constants
|
||||
|
||||
const _constants := preload("res://addons/phantom_camera/scripts/phantom_camera/phantom_camera_constants.gd")
|
||||
const _host_list_item: PackedScene = preload("res://addons/phantom_camera/panel/viewfinder/host_list/host_list_item.tscn")
|
||||
|
||||
#endregion
|
||||
|
||||
signal pcam_host_removed(pcam_host: PhantomCameraHost)
|
||||
|
||||
@onready var _host_list_button: Button = %HostListButton
|
||||
@onready var _host_list_scroll_container: ScrollContainer = %ScrollContainer
|
||||
@onready var _host_list_item_container: VBoxContainer = %HostListContainer
|
||||
|
||||
var _host_list_open: bool = false
|
||||
|
||||
var _bottom_offset_value: float
|
||||
|
||||
var _pcam_host_list: Array[PhantomCameraHost]
|
||||
var _pcam_manager: Node
|
||||
|
||||
var _viewfinder_panel: Control
|
||||
|
||||
#region Private Functions
|
||||
|
||||
func _ready() -> void:
|
||||
_host_list_button.pressed.connect(_host_list_button_pressed)
|
||||
if Engine.has_singleton(_constants.PCAM_MANAGER_NODE_NAME):
|
||||
_pcam_manager = Engine.get_singleton(_constants.PCAM_MANAGER_NODE_NAME)
|
||||
_pcam_manager.pcam_host_removed_from_scene.connect(_remove_pcam_host)
|
||||
|
||||
if not get_parent() is Control: return # To prevent errors when opening the scene on its own
|
||||
_viewfinder_panel = get_parent()
|
||||
_viewfinder_panel.resized.connect(_set_offset_top)
|
||||
|
||||
_host_list_item_container.resized.connect(_set_offset_top)
|
||||
|
||||
|
||||
func _set_offset_top() -> void:
|
||||
offset_top = _set_host_list_size()
|
||||
|
||||
|
||||
func _host_list_button_pressed() -> void:
|
||||
_host_list_open = !_host_list_open
|
||||
|
||||
var tween: Tween = create_tween()
|
||||
var max_duration: float = 0.6
|
||||
|
||||
# 300 being the minimum size of the viewfinder's height
|
||||
var duration: float = clampf(
|
||||
max_duration / (300 / _host_list_item_container.size.y),
|
||||
0.3,
|
||||
max_duration)
|
||||
|
||||
tween.tween_property(self, "offset_top", _set_host_list_size(), duration)\
|
||||
.set_ease(Tween.EASE_OUT)\
|
||||
.set_trans(Tween.TRANS_QUINT)
|
||||
|
||||
|
||||
func _set_host_list_size() -> float:
|
||||
if not _host_list_open:
|
||||
return clampf(
|
||||
_viewfinder_panel.size.y - \
|
||||
_host_list_item_container.size.y - \
|
||||
_host_list_button.size.y - 20,
|
||||
0,
|
||||
INF
|
||||
)
|
||||
else:
|
||||
return (_viewfinder_panel.size.y - _host_list_button.size.y / 2)
|
||||
|
||||
|
||||
func _remove_pcam_host(pcam_host: PhantomCameraHost) -> void:
|
||||
if _pcam_host_list.has(pcam_host):
|
||||
_pcam_host_list.erase(pcam_host)
|
||||
|
||||
var freed_pcam_host: Control
|
||||
for host_list_item_instance in _host_list_item_container.get_children():
|
||||
if not host_list_item_instance.pcam_host == pcam_host: continue
|
||||
freed_pcam_host = host_list_item_instance
|
||||
host_list_item_instance.queue_free()
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Functions
|
||||
|
||||
func add_pcam_host(pcam_host: PhantomCameraHost, is_default: bool) -> void:
|
||||
if _pcam_host_list.has(pcam_host): return
|
||||
|
||||
_pcam_host_list.append(pcam_host)
|
||||
|
||||
var host_list_item_instance: PanelContainer = _host_list_item.instantiate()
|
||||
var switch_pcam_host_button: Button = host_list_item_instance.get_node("%SwitchPCamHost")
|
||||
if is_default: switch_pcam_host_button.button_pressed = true
|
||||
|
||||
if not pcam_host.tree_exiting.is_connected(_remove_pcam_host):
|
||||
pcam_host.tree_exiting.connect(_remove_pcam_host.bind(pcam_host))
|
||||
|
||||
host_list_item_instance.pcam_host = pcam_host
|
||||
|
||||
_host_list_item_container.add_child(host_list_item_instance)
|
||||
|
||||
|
||||
func clear_pcam_host_list() -> void:
|
||||
_pcam_host_list.clear()
|
||||
|
||||
for host_list_item_instance in _host_list_item_container.get_children():
|
||||
host_list_item_instance.queue_free()
|
||||
|
||||
#endregion
|
||||
@@ -0,0 +1 @@
|
||||
uid://c84cxry3t35ny
|
||||
@@ -0,0 +1,58 @@
|
||||
@tool
|
||||
extends Control
|
||||
|
||||
const button_group_resource: ButtonGroup = preload("res://addons/phantom_camera/panel/viewfinder/host_list/host_list_item_group.tres")
|
||||
const _constants = preload("res://addons/phantom_camera/scripts/phantom_camera/phantom_camera_constants.gd")
|
||||
|
||||
@onready var select_pcam_host: Button = %SelectPCamHost
|
||||
@onready var switch_pcam_host: Button = %SwitchPCamHost
|
||||
|
||||
var pcam_host: PhantomCameraHost:
|
||||
set(value):
|
||||
pcam_host = value
|
||||
if not is_instance_valid(value): return
|
||||
if not pcam_host.renamed.is_connected(_rename_pcam_host):
|
||||
pcam_host.renamed.connect(_rename_pcam_host)
|
||||
pcam_host.has_error.connect(_pcam_host_has_error)
|
||||
get:
|
||||
return pcam_host
|
||||
|
||||
var _pcam_manager: Node
|
||||
|
||||
#region Private fucntions
|
||||
|
||||
func _ready() -> void:
|
||||
switch_pcam_host.button_group = button_group_resource
|
||||
select_pcam_host.pressed.connect(_select_pcam)
|
||||
switch_pcam_host.pressed.connect(_switch_pcam_host)
|
||||
|
||||
if not is_instance_valid(pcam_host): return
|
||||
switch_pcam_host.text = pcam_host.name
|
||||
|
||||
_pcam_host_has_error()
|
||||
|
||||
|
||||
func _pcam_host_has_error() -> void:
|
||||
if pcam_host.show_warning:
|
||||
%ErrorPCamHost.visible = true
|
||||
else:
|
||||
%ErrorPCamHost.visible = false
|
||||
|
||||
|
||||
func _rename_pcam_host() -> void:
|
||||
switch_pcam_host.text = pcam_host.name
|
||||
|
||||
|
||||
func _select_pcam() -> void:
|
||||
EditorInterface.get_selection().clear()
|
||||
EditorInterface.get_selection().add_node(pcam_host)
|
||||
|
||||
|
||||
func _switch_pcam_host() -> void:
|
||||
if not Engine.has_singleton(_constants.PCAM_MANAGER_NODE_NAME): return
|
||||
if not is_instance_valid(_pcam_manager):
|
||||
_pcam_manager = Engine.get_singleton(_constants.PCAM_MANAGER_NODE_NAME)
|
||||
|
||||
_pcam_manager.viewfinder_pcam_host_switch.emit(pcam_host)
|
||||
|
||||
#endregion
|
||||
@@ -0,0 +1 @@
|
||||
uid://bv24ubx8mutw7
|
||||
605
addons/phantom_camera/scripts/panel/viewfinder/viewfinder.gd
Normal file
605
addons/phantom_camera/scripts/panel/viewfinder/viewfinder.gd
Normal file
@@ -0,0 +1,605 @@
|
||||
@tool
|
||||
extends Control
|
||||
|
||||
#region Constants
|
||||
|
||||
const _constants = preload("res://addons/phantom_camera/scripts/phantom_camera/phantom_camera_constants.gd")
|
||||
|
||||
# TODO - Should be in a central location
|
||||
const _camera_2d_icon: CompressedTexture2D = preload("res://addons/phantom_camera/icons/viewfinder/Camera2DIcon.svg")
|
||||
const _camera_3d_icon: CompressedTexture2D = preload("res://addons/phantom_camera/icons/viewfinder/Camera3DIcon.svg")
|
||||
const _pcam_host_icon: CompressedTexture2D = preload("res://addons/phantom_camera/icons/phantom_camera_host.svg")
|
||||
const _pcam_2D_icon: CompressedTexture2D = preload("res://addons/phantom_camera/icons/phantom_camera_2d.svg")
|
||||
const _pcam_3D_icon: CompressedTexture2D = preload("res://addons/phantom_camera/icons/phantom_camera_3d.svg")
|
||||
|
||||
const _overlay_color_alpha: float = 0.3
|
||||
|
||||
#endregion
|
||||
|
||||
#region @onready
|
||||
|
||||
@onready var dead_zone_center_hbox: VBoxContainer = %DeadZoneCenterHBoxContainer
|
||||
@onready var dead_zone_center_center_panel: Panel = %DeadZoneCenterCenterPanel
|
||||
@onready var dead_zone_left_center_panel: Panel = %DeadZoneLeftCenterPanel
|
||||
@onready var dead_zone_right_center_panel: Panel = %DeadZoneRightCenterPanel
|
||||
@onready var target_point: Panel = %TargetPoint
|
||||
|
||||
@onready var aspect_ratio_container: AspectRatioContainer = %AspectRatioContainer
|
||||
@onready var camera_viewport_panel: Panel = aspect_ratio_container.get_child(0)
|
||||
@onready var _viewfinder: Control = %Viewfinder
|
||||
@onready var _dead_zone_h_box_container: Control = %DeadZoneHBoxContainer
|
||||
@onready var sub_viewport: SubViewport = %SubViewport
|
||||
|
||||
@onready var _empty_state_control: Control = %EmptyStateControl
|
||||
@onready var _empty_state_icon: TextureRect = %EmptyStateIcon
|
||||
@onready var _empty_state_text: RichTextLabel = %EmptyStateText
|
||||
@onready var _add_node_button: Button = %AddNodeButton
|
||||
@onready var _add_node_button_text: RichTextLabel = %AddNodeTypeText
|
||||
|
||||
@onready var _priority_override_button: Button = %PriorityOverrideButton
|
||||
@onready var _priority_override_name_label: Label = %PriorityOverrideNameLabel
|
||||
|
||||
@onready var _camera_2d: Camera2D = %Camera2D
|
||||
|
||||
@onready var _pcam_host_list: VBoxContainer = %PCamHostList
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Variables
|
||||
|
||||
var _no_open_scene_icon: CompressedTexture2D = preload("res://addons/phantom_camera/icons/viewfinder/SceneTypesIcon.svg")
|
||||
var _no_open_scene_string: String = "[b]2D[/b] or [b]3D[/b] scene open"
|
||||
|
||||
var _selected_camera: Node
|
||||
var _active_pcam: Node
|
||||
|
||||
var _is_2d: bool
|
||||
|
||||
var _pcam_manager: Node
|
||||
|
||||
var _root_node: Node
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Variables
|
||||
|
||||
var pcam_host_group: Array[PhantomCameraHost]
|
||||
|
||||
var is_scene: bool
|
||||
|
||||
var viewfinder_visible: bool
|
||||
|
||||
var min_horizontal: float
|
||||
var max_horizontal: float
|
||||
var min_vertical: float
|
||||
var max_vertical: float
|
||||
|
||||
var pcam_host: PhantomCameraHost
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Private Functions
|
||||
|
||||
func _ready() -> void:
|
||||
if not Engine.is_editor_hint():
|
||||
set_process(true)
|
||||
camera_viewport_panel.self_modulate.a = 0
|
||||
|
||||
_root_node = get_tree().current_scene
|
||||
|
||||
if _root_node is Node2D || _root_node is Node3D:
|
||||
%SubViewportContainer.visible = false
|
||||
if _root_node is Node2D:
|
||||
_is_2d = true
|
||||
else:
|
||||
_is_2d = false
|
||||
|
||||
_set_viewfinder(_root_node, false)
|
||||
|
||||
if not Engine.is_editor_hint():
|
||||
_empty_state_control.visible = false
|
||||
|
||||
_priority_override_button.visible = false
|
||||
|
||||
# Triggered when viewport size is changed in Project Settings
|
||||
ProjectSettings.settings_changed.connect(_settings_changed)
|
||||
|
||||
# PCam Host List
|
||||
_pcam_host_list.visible = false
|
||||
_assign_manager()
|
||||
_visibility_check()
|
||||
|
||||
|
||||
func _pcam_host_switch(new_pcam_host: PhantomCameraHost) -> void:
|
||||
_set_viewfinder_camera(new_pcam_host, true)
|
||||
|
||||
|
||||
func _exit_tree() -> void:
|
||||
if aspect_ratio_container.resized.is_connected(_resized):
|
||||
aspect_ratio_container.resized.disconnect(_resized)
|
||||
|
||||
if _add_node_button.pressed.is_connected(_visibility_check):
|
||||
_add_node_button.pressed.disconnect(_visibility_check)
|
||||
|
||||
if is_instance_valid(_active_pcam):
|
||||
if _active_pcam.dead_zone_changed.is_connected(_on_dead_zone_changed):
|
||||
_active_pcam.dead_zone_changed.disconnect(_on_dead_zone_changed)
|
||||
|
||||
if _priority_override_button.pressed.is_connected(_select_override_pcam):
|
||||
_priority_override_button.pressed.disconnect(_select_override_pcam)
|
||||
|
||||
|
||||
func _process(_delta: float) -> void:
|
||||
if Engine.is_editor_hint() and not viewfinder_visible: return
|
||||
if not is_instance_valid(_active_pcam): return
|
||||
|
||||
var unprojected_position_clamped: Vector2 = Vector2(
|
||||
clamp(_active_pcam.viewport_position.x, min_horizontal, max_horizontal),
|
||||
clamp(_active_pcam.viewport_position.y, min_vertical, max_vertical)
|
||||
)
|
||||
|
||||
if not Engine.is_editor_hint():
|
||||
target_point.position = camera_viewport_panel.size * unprojected_position_clamped - target_point.size / 2
|
||||
|
||||
if not _is_2d: return
|
||||
if not is_instance_valid(pcam_host): return
|
||||
if not is_instance_valid(pcam_host.camera_2d): return
|
||||
|
||||
var window_size_height: float = ProjectSettings.get_setting("display/window/size/viewport_height")
|
||||
sub_viewport.size_2d_override = sub_viewport.size * (window_size_height / sub_viewport.size.y)
|
||||
|
||||
_camera_2d.global_transform = pcam_host.camera_2d.global_transform
|
||||
_camera_2d.offset = pcam_host.camera_2d.offset
|
||||
_camera_2d.zoom = pcam_host.camera_2d.zoom
|
||||
_camera_2d.ignore_rotation = pcam_host.camera_2d.ignore_rotation
|
||||
_camera_2d.anchor_mode = pcam_host.camera_2d.anchor_mode
|
||||
_camera_2d.limit_left = pcam_host.camera_2d.limit_left
|
||||
_camera_2d.limit_top = pcam_host.camera_2d.limit_top
|
||||
_camera_2d.limit_right = pcam_host.camera_2d.limit_right
|
||||
_camera_2d.limit_bottom = pcam_host.camera_2d.limit_bottom
|
||||
|
||||
|
||||
func _settings_changed() -> void:
|
||||
var viewport_width: float = ProjectSettings.get_setting("display/window/size/viewport_width")
|
||||
var viewport_height: float = ProjectSettings.get_setting("display/window/size/viewport_height")
|
||||
var ratio: float = viewport_width / viewport_height
|
||||
aspect_ratio_container.set_ratio(ratio)
|
||||
camera_viewport_panel.size.x = viewport_width / (viewport_height / sub_viewport.size.y)
|
||||
|
||||
# Applies Project Settings to Viewport
|
||||
sub_viewport.canvas_item_default_texture_filter = ProjectSettings.get_setting("rendering/textures/canvas_textures/default_texture_filter")
|
||||
|
||||
# TODO - Add resizer for Framed Viewfinder
|
||||
|
||||
|
||||
func _visibility_check() -> void:
|
||||
if not viewfinder_visible: return
|
||||
|
||||
var pcam_host: PhantomCameraHost
|
||||
var has_camera: bool = false
|
||||
if not Engine.has_singleton(_constants.PCAM_MANAGER_NODE_NAME): return
|
||||
|
||||
if not Engine.get_singleton(_constants.PCAM_MANAGER_NODE_NAME).get_phantom_camera_hosts().is_empty():
|
||||
has_camera = true
|
||||
pcam_host = Engine.get_singleton(_constants.PCAM_MANAGER_NODE_NAME).get_phantom_camera_hosts()[0]
|
||||
|
||||
var root: Node = EditorInterface.get_edited_scene_root()
|
||||
if root is Node2D:
|
||||
var camera_2d: Camera2D
|
||||
|
||||
if has_camera:
|
||||
camera_2d = pcam_host.camera_2d
|
||||
else:
|
||||
camera_2d = _get_camera_2d()
|
||||
|
||||
_is_2d = true
|
||||
is_scene = true
|
||||
_add_node_button.visible = true
|
||||
_check_camera(root, camera_2d)
|
||||
elif root is Node3D:
|
||||
var camera_3d: Camera3D
|
||||
if has_camera:
|
||||
camera_3d = pcam_host.camera_3d
|
||||
elif root.get_viewport() != null:
|
||||
if root.get_viewport().get_camera_3d() != null:
|
||||
camera_3d = root.get_viewport().get_camera_3d()
|
||||
|
||||
_is_2d = false
|
||||
is_scene = true
|
||||
_add_node_button.visible = true
|
||||
_check_camera(root, camera_3d)
|
||||
else:
|
||||
# Is not a 2D or 3D scene
|
||||
is_scene = false
|
||||
_set_empty_viewfinder_state(_no_open_scene_string, _no_open_scene_icon)
|
||||
_add_node_button.visible = false
|
||||
|
||||
# Checks if a new scene is created and changes viewfinder accordingly
|
||||
if not get_tree().node_added.is_connected(_node_added_to_scene):
|
||||
get_tree().node_added.connect(_node_added_to_scene)
|
||||
|
||||
if not _priority_override_button.pressed.is_connected(_select_override_pcam):
|
||||
_priority_override_button.pressed.connect(_select_override_pcam)
|
||||
|
||||
|
||||
func _node_added_to_scene(node: Node) -> void:
|
||||
if node is Node2D or node is Node3D:
|
||||
get_tree().node_added.disconnect(_node_added_to_scene)
|
||||
_visibility_check()
|
||||
|
||||
|
||||
func _get_camera_2d() -> Camera2D:
|
||||
var edited_scene_root: Node = EditorInterface.get_edited_scene_root()
|
||||
|
||||
if edited_scene_root == null: return null
|
||||
|
||||
var viewport: Viewport = edited_scene_root.get_viewport()
|
||||
if viewport == null: return null
|
||||
|
||||
var viewport_rid: RID = viewport.get_viewport_rid()
|
||||
if viewport_rid == null: return null
|
||||
|
||||
var camerasGroupName: String = "__cameras_%d" % viewport_rid.get_id()
|
||||
var cameras: Array[Node] = get_tree().get_nodes_in_group(camerasGroupName)
|
||||
|
||||
for camera in cameras:
|
||||
if camera is Camera2D and camera.is_current:
|
||||
return camera
|
||||
|
||||
return null
|
||||
|
||||
|
||||
func _check_camera(root: Node, camera: Node) -> void:
|
||||
var camera_string: String
|
||||
var pcam_string: String
|
||||
var color: Color
|
||||
var camera_icon: CompressedTexture2D
|
||||
var pcam_icon: CompressedTexture2D
|
||||
|
||||
if _is_2d:
|
||||
camera_string = _constants.CAMERA_2D_NODE_NAME
|
||||
pcam_string = _constants.PCAM_2D_NODE_NAME
|
||||
color = _constants.COLOR_2D
|
||||
camera_icon = _camera_2d_icon
|
||||
pcam_icon = _pcam_2D_icon
|
||||
else:
|
||||
camera_string = _constants.CAMERA_3D_NODE_NAME
|
||||
pcam_string = _constants.PCAM_3D_NODE_NAME
|
||||
color = _constants.COLOR_3D
|
||||
camera_icon = _camera_3d_icon
|
||||
pcam_icon = _pcam_3D_icon
|
||||
|
||||
if camera:
|
||||
# Has Camera
|
||||
if camera.get_children().size() > 0:
|
||||
for cam_child in camera.get_children():
|
||||
if cam_child is PhantomCameraHost:
|
||||
pcam_host = cam_child
|
||||
|
||||
if pcam_host:
|
||||
if get_tree().root.get_node(_constants.PCAM_MANAGER_NODE_NAME).get_phantom_camera_2ds() or \
|
||||
get_tree().root.get_node(_constants.PCAM_MANAGER_NODE_NAME).get_phantom_camera_3ds():
|
||||
# Pcam exists in tree
|
||||
_set_viewfinder(root, true)
|
||||
_set_viewfinder_state()
|
||||
%NoSupportMsg.visible = false
|
||||
else:
|
||||
# No PCam in scene
|
||||
_update_button(pcam_string, pcam_icon, color)
|
||||
_set_empty_viewfinder_state(pcam_string, pcam_icon)
|
||||
else:
|
||||
# No PCamHost in scene
|
||||
_update_button(_constants.PCAM_HOST_NODE_NAME, _pcam_host_icon, _constants.PCAM_HOST_COLOR)
|
||||
_set_empty_viewfinder_state(_constants.PCAM_HOST_NODE_NAME, _pcam_host_icon)
|
||||
else:
|
||||
# No PCamHost in scene
|
||||
_update_button(_constants.PCAM_HOST_NODE_NAME, _pcam_host_icon, _constants.PCAM_HOST_COLOR)
|
||||
_set_empty_viewfinder_state(_constants.PCAM_HOST_NODE_NAME, _pcam_host_icon)
|
||||
else:
|
||||
# No Camera
|
||||
_update_button(camera_string, camera_icon, color)
|
||||
_set_empty_viewfinder_state(camera_string, camera_icon)
|
||||
|
||||
|
||||
func _update_button(text: String, icon: CompressedTexture2D, color: Color) -> void:
|
||||
_add_node_button_text.set_text("[center]Add [img=32]" + icon.resource_path + "[/img] [b]"+ text + "[/b][/center]");
|
||||
var button_theme_hover: StyleBoxFlat = _add_node_button.get_theme_stylebox("hover")
|
||||
button_theme_hover.border_color = color
|
||||
_add_node_button.add_theme_stylebox_override("hover", button_theme_hover)
|
||||
|
||||
|
||||
func _set_viewfinder_state() -> void:
|
||||
_empty_state_control.visible = false
|
||||
_viewfinder.visible = true
|
||||
|
||||
if is_instance_valid(_active_pcam):
|
||||
if _active_pcam.get_follow_mode() == _active_pcam.FollowMode.FRAMED:
|
||||
_dead_zone_h_box_container.visible = true
|
||||
target_point.visible = true
|
||||
else:
|
||||
_dead_zone_h_box_container.visible = false
|
||||
target_point.visible = false
|
||||
|
||||
|
||||
func _set_empty_viewfinder_state(text: String, icon: CompressedTexture2D) -> void:
|
||||
_viewfinder.visible = false
|
||||
_framed_view_visible(false)
|
||||
|
||||
_empty_state_control.visible = true
|
||||
_empty_state_icon.texture = icon
|
||||
if icon == _no_open_scene_icon:
|
||||
_empty_state_text.set_text("[center]No " + text + "[/center]")
|
||||
else:
|
||||
_empty_state_text.set_text("[center]No [b]" + text + "[/b] in scene[/center]")
|
||||
|
||||
if _add_node_button.pressed.is_connected(_add_node):
|
||||
_add_node_button.pressed.disconnect(_add_node)
|
||||
|
||||
_add_node_button.pressed.connect(_add_node.bind(text))
|
||||
|
||||
|
||||
func _add_node(node_type: String) -> void:
|
||||
var scene_root: Node = EditorInterface.get_edited_scene_root()
|
||||
|
||||
match node_type:
|
||||
_no_open_scene_string:
|
||||
pass
|
||||
_constants.CAMERA_2D_NODE_NAME:
|
||||
var camera: Camera2D = Camera2D.new()
|
||||
_instantiate_node(scene_root, camera, _constants.CAMERA_2D_NODE_NAME)
|
||||
_constants.CAMERA_3D_NODE_NAME:
|
||||
var camera: Camera3D = Camera3D.new()
|
||||
_instantiate_node(scene_root, camera, _constants.CAMERA_3D_NODE_NAME)
|
||||
_constants.PCAM_HOST_NODE_NAME:
|
||||
var pcam_host: PhantomCameraHost = PhantomCameraHost.new()
|
||||
var camera_owner: Node
|
||||
if _is_2d:
|
||||
camera_owner = _get_camera_2d()
|
||||
else:
|
||||
camera_owner = get_tree().get_edited_scene_root().get_viewport().get_camera_3d()
|
||||
_instantiate_node(
|
||||
scene_root,
|
||||
pcam_host,
|
||||
_constants.PCAM_HOST_NODE_NAME,
|
||||
camera_owner
|
||||
)
|
||||
_constants.PCAM_2D_NODE_NAME:
|
||||
var pcam_2D: PhantomCamera2D = PhantomCamera2D.new()
|
||||
_instantiate_node(scene_root, pcam_2D, _constants.PCAM_2D_NODE_NAME)
|
||||
_constants.PCAM_3D_NODE_NAME:
|
||||
var pcam_3D: PhantomCamera3D = PhantomCamera3D.new()
|
||||
_instantiate_node(scene_root, pcam_3D, _constants.PCAM_3D_NODE_NAME)
|
||||
|
||||
_visibility_check()
|
||||
|
||||
|
||||
func _instantiate_node(scene_root: Node, node: Node, name: String, parent: Node = scene_root) -> void:
|
||||
node.set_name(name)
|
||||
parent.add_child(node)
|
||||
node.owner = scene_root
|
||||
|
||||
|
||||
func _set_viewfinder(root: Node, editor: bool) -> void:
|
||||
pcam_host_group = get_tree().root.get_node(_constants.PCAM_MANAGER_NODE_NAME).get_phantom_camera_hosts()
|
||||
if pcam_host_group.size() != 0:
|
||||
if pcam_host_group.size() == 1:
|
||||
_pcam_host_list.visible = false
|
||||
_set_viewfinder_camera(pcam_host_group[0], editor)
|
||||
else:
|
||||
_pcam_host_list.visible = true
|
||||
_set_viewfinder_camera(pcam_host_group[0], editor)
|
||||
for i in pcam_host_group.size():
|
||||
var is_default: bool = false
|
||||
if i == 0:
|
||||
is_default = true
|
||||
_pcam_host_list.add_pcam_host(pcam_host_group[i], is_default)
|
||||
|
||||
|
||||
func _set_viewfinder_camera(new_pcam_host: PhantomCameraHost, editor: bool) -> void:
|
||||
pcam_host = new_pcam_host
|
||||
|
||||
if _is_2d:
|
||||
_selected_camera = pcam_host.camera_2d
|
||||
|
||||
if editor:
|
||||
sub_viewport.disable_3d = true
|
||||
pcam_host = pcam_host
|
||||
_camera_2d.zoom = pcam_host.camera_2d.zoom
|
||||
_camera_2d.offset = pcam_host.camera_2d.offset
|
||||
_camera_2d.ignore_rotation = pcam_host.camera_2d.ignore_rotation
|
||||
|
||||
sub_viewport.world_2d = pcam_host.camera_2d.get_world_2d()
|
||||
sub_viewport.render_target_update_mode = SubViewport.UPDATE_ALWAYS
|
||||
sub_viewport.render_target_clear_mode = SubViewport.CLEAR_MODE_ALWAYS
|
||||
sub_viewport.size_2d_override_stretch = true
|
||||
else:
|
||||
_selected_camera = pcam_host.camera_3d
|
||||
if editor:
|
||||
var camera_3d_rid: RID = _selected_camera.get_camera_rid()
|
||||
sub_viewport.disable_3d = false
|
||||
sub_viewport.world_3d = pcam_host.camera_3d.get_world_3d()
|
||||
RenderingServer.viewport_attach_camera(sub_viewport.get_viewport_rid(), camera_3d_rid)
|
||||
|
||||
if _selected_camera.keep_aspect == Camera3D.KeepAspect.KEEP_HEIGHT:
|
||||
aspect_ratio_container.set_stretch_mode(AspectRatioContainer.STRETCH_HEIGHT_CONTROLS_WIDTH)
|
||||
else:
|
||||
aspect_ratio_container.set_stretch_mode(AspectRatioContainer.STRETCH_WIDTH_CONTROLS_HEIGHT)
|
||||
|
||||
set_process(true)
|
||||
|
||||
if not pcam_host.viewfinder_update.is_connected(_on_update_editor_viewfinder):
|
||||
pcam_host.viewfinder_update.connect(_on_update_editor_viewfinder)
|
||||
|
||||
if not pcam_host.viewfinder_disable_dead_zone.is_connected(_disconnect_dead_zone):
|
||||
pcam_host.viewfinder_disable_dead_zone.connect(_disconnect_dead_zone)
|
||||
|
||||
if not aspect_ratio_container.resized.is_connected(_resized):
|
||||
aspect_ratio_container.resized.connect(_resized)
|
||||
|
||||
if is_instance_valid(pcam_host.get_active_pcam()):
|
||||
_active_pcam = pcam_host.get_active_pcam()
|
||||
else:
|
||||
_framed_view_visible(false)
|
||||
_active_pcam = null
|
||||
return
|
||||
|
||||
if not _active_pcam.follow_mode == PhantomCamera2D.FollowMode.FRAMED: return
|
||||
|
||||
_framed_view_visible(true)
|
||||
_on_dead_zone_changed()
|
||||
_connect_dead_zone()
|
||||
|
||||
|
||||
func _connect_dead_zone() -> void:
|
||||
if not _active_pcam and is_instance_valid(pcam_host.get_active_pcam()):
|
||||
_active_pcam = pcam_host.get_active_pcam()
|
||||
|
||||
if not _active_pcam.dead_zone_changed.is_connected(_on_dead_zone_changed):
|
||||
_active_pcam.dead_zone_changed.connect(_on_dead_zone_changed)
|
||||
|
||||
_framed_view_visible(true)
|
||||
_viewfinder.visible = true
|
||||
_on_dead_zone_changed()
|
||||
|
||||
func _disconnect_dead_zone() -> void:
|
||||
if not is_instance_valid(_active_pcam): return
|
||||
_framed_view_visible(_is_framed_pcam())
|
||||
|
||||
if _active_pcam.follow_mode_changed.is_connected(_check_follow_mode):
|
||||
_active_pcam.follow_mode_changed.disconnect(_check_follow_mode)
|
||||
|
||||
if _active_pcam.dead_zone_changed.is_connected(_on_dead_zone_changed):
|
||||
_active_pcam.dead_zone_changed.disconnect(_on_dead_zone_changed)
|
||||
|
||||
|
||||
func _resized() -> void:
|
||||
_on_dead_zone_changed()
|
||||
|
||||
|
||||
func _is_framed_pcam() -> bool:
|
||||
if not is_instance_valid(pcam_host): return false
|
||||
_active_pcam = pcam_host.get_active_pcam()
|
||||
if not is_instance_valid(_active_pcam): return false
|
||||
if not _active_pcam.follow_mode == PhantomCamera2D.FollowMode.FRAMED: return false
|
||||
|
||||
return true
|
||||
|
||||
|
||||
func _framed_view_visible(should_show: bool) -> void:
|
||||
if should_show:
|
||||
target_point.visible = true
|
||||
_dead_zone_h_box_container.visible = true
|
||||
else:
|
||||
target_point.visible = false
|
||||
_dead_zone_h_box_container.visible = false
|
||||
|
||||
|
||||
func _on_dead_zone_changed() -> void:
|
||||
if not is_instance_valid(_active_pcam): return
|
||||
if not _active_pcam.follow_mode == _active_pcam.FollowMode.FRAMED: return
|
||||
|
||||
# Waits until the camera_viewport_panel has been resized when launching the game
|
||||
if camera_viewport_panel.size.x == 0:
|
||||
await camera_viewport_panel.resized
|
||||
|
||||
if not _active_pcam == pcam_host.get_active_pcam():
|
||||
_active_pcam == pcam_host.get_active_pcam()
|
||||
|
||||
var dead_zone_width: float = _active_pcam.dead_zone_width * camera_viewport_panel.size.x
|
||||
var dead_zone_height: float = _active_pcam.dead_zone_height * camera_viewport_panel.size.y
|
||||
dead_zone_center_hbox.set_custom_minimum_size(Vector2(dead_zone_width, 0))
|
||||
dead_zone_center_center_panel.set_custom_minimum_size(Vector2(0, dead_zone_height))
|
||||
dead_zone_left_center_panel.set_custom_minimum_size(Vector2(0, dead_zone_height))
|
||||
dead_zone_right_center_panel.set_custom_minimum_size(Vector2(0, dead_zone_height))
|
||||
|
||||
min_horizontal = 0.5 - _active_pcam.dead_zone_width / 2
|
||||
max_horizontal = 0.5 + _active_pcam.dead_zone_width / 2
|
||||
min_vertical = 0.5 - _active_pcam.dead_zone_height / 2
|
||||
max_vertical = 0.5 + _active_pcam.dead_zone_height / 2
|
||||
|
||||
|
||||
func _check_follow_mode() -> void:
|
||||
_framed_view_visible(_is_framed_pcam())
|
||||
|
||||
|
||||
func _on_update_editor_viewfinder(check_framed_view: bool = false) -> void:
|
||||
_active_pcam = pcam_host.get_active_pcam()
|
||||
|
||||
if not is_instance_valid(_active_pcam): return
|
||||
|
||||
if not _active_pcam.follow_mode_changed.is_connected(_check_follow_mode):
|
||||
_active_pcam.follow_mode_changed.connect(_check_follow_mode)
|
||||
|
||||
if _active_pcam.priority_override:
|
||||
_priority_override_button.visible = true
|
||||
_priority_override_name_label.set_text(_active_pcam.name)
|
||||
_priority_override_button.set_tooltip_text(_active_pcam.name)
|
||||
else:
|
||||
_priority_override_button.visible = false
|
||||
|
||||
_framed_view_visible(false)
|
||||
if not check_framed_view: return
|
||||
if _is_framed_pcam(): _connect_dead_zone()
|
||||
|
||||
|
||||
func _select_override_pcam() -> void:
|
||||
EditorInterface.get_selection().clear()
|
||||
EditorInterface.get_selection().add_node(_active_pcam)
|
||||
|
||||
|
||||
func _assign_manager() -> void:
|
||||
if not is_instance_valid(_pcam_manager):
|
||||
if Engine.has_singleton(_constants.PCAM_MANAGER_NODE_NAME):
|
||||
_pcam_manager = Engine.get_singleton(_constants.PCAM_MANAGER_NODE_NAME)
|
||||
_pcam_manager.pcam_host_added_to_scene.connect(_pcam_changed)
|
||||
_pcam_manager.pcam_host_removed_from_scene.connect(_pcam_host_removed_from_scene)
|
||||
|
||||
_pcam_manager.pcam_added_to_scene.connect(_pcam_changed)
|
||||
_pcam_manager.pcam_removed_from_scene.connect(_pcam_changed)
|
||||
|
||||
_pcam_manager.viewfinder_pcam_host_switch.connect(_pcam_host_switch)
|
||||
|
||||
|
||||
func _pcam_host_removed_from_scene(pcam_host: PhantomCameraHost) -> void:
|
||||
if _pcam_manager.phantom_camera_hosts.size() < 2:
|
||||
_pcam_host_list.visible = false
|
||||
|
||||
_visibility_check()
|
||||
|
||||
|
||||
func _pcam_changed(pcam: Node) -> void:
|
||||
_visibility_check()
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Public Functions
|
||||
|
||||
func set_visibility(visible: bool) -> void:
|
||||
if visible:
|
||||
viewfinder_visible = true
|
||||
_visibility_check()
|
||||
else:
|
||||
viewfinder_visible = false
|
||||
|
||||
|
||||
func update_dead_zone() -> void:
|
||||
_set_viewfinder(_root_node, true)
|
||||
|
||||
|
||||
## TODO - Signal can be added directly to this file with the changes in Godot 4.5 (https://github.com/godotengine/godot/pull/102986)
|
||||
func scene_changed(scene_root: Node) -> void:
|
||||
_assign_manager()
|
||||
_priority_override_button.visible = false
|
||||
_pcam_host_list.clear_pcam_host_list()
|
||||
|
||||
if not scene_root is Node2D and not scene_root is Node3D:
|
||||
is_scene = false
|
||||
_pcam_host_list.visible = false
|
||||
_set_empty_viewfinder_state(_no_open_scene_string, _no_open_scene_icon)
|
||||
_add_node_button.visible = false
|
||||
else:
|
||||
_visibility_check()
|
||||
|
||||
#endregion
|
||||
@@ -0,0 +1 @@
|
||||
uid://drmv3363t8amc
|
||||
Reference in New Issue
Block a user