259 lines
9.1 KiB
GDScript
259 lines
9.1 KiB
GDScript
@tool
|
|
extends Control
|
|
|
|
@export var placeholder_text : String = "Select Resource"
|
|
|
|
### SETTINGS FOR THE RESOURCE PICKER
|
|
var file_extension : String = ""
|
|
var get_suggestions_func : Callable = get_default_suggestions
|
|
var empty_text : String = ""
|
|
@export var enable_pretty_name : bool = false
|
|
|
|
var resource_icon : Texture = null:
|
|
get:
|
|
return resource_icon
|
|
set(new_icon):
|
|
resource_icon = new_icon
|
|
%Icon.texture = new_icon
|
|
|
|
## STORING VALUE AND REFERENCE TO RESOURCE
|
|
var event_resource : DialogicEvent = null
|
|
var property_name : String
|
|
var current_value # Dynamic
|
|
var editor_reference
|
|
|
|
var current_selected = 0
|
|
|
|
# this signal is on all event parts and informs the event that a change happened.
|
|
signal value_changed(property_name, value)
|
|
|
|
################################################################################
|
|
## BASIC EVENT PART FUNCTIONS
|
|
################################################################################
|
|
# These functions have to be implemented by all scenes that are used to display
|
|
# values on the events.
|
|
|
|
func set_left_text(value:String) -> void:
|
|
$LeftText.text = str(value)
|
|
$LeftText.visible = !value.is_empty()
|
|
|
|
func set_right_text(value:String) -> void:
|
|
$RightText.text = str(value)
|
|
$RightText.visible = !value.is_empty()
|
|
|
|
func set_value(value, text : String = '') -> void:
|
|
if value == null:
|
|
%Search.text = empty_text
|
|
elif file_extension != "" and file_extension != ".dch" and file_extension != ".dtl":
|
|
%Search.text = value.resource_path
|
|
%Search.tooltip_text = value.resource_path
|
|
elif value:
|
|
if enable_pretty_name:
|
|
%Search.text = DialogicUtil.pretty_name(value)
|
|
else:
|
|
%Search.text = value
|
|
else:
|
|
%Search.text = empty_text
|
|
if text:
|
|
%Search.text = text
|
|
|
|
current_value = value
|
|
|
|
|
|
func changed_to_empty() -> void:
|
|
if file_extension != "" && file_extension != ".dch":
|
|
emit_signal("value_changed", property_name, null)
|
|
else:
|
|
emit_signal("value_changed", property_name, "")
|
|
|
|
|
|
################################################################################
|
|
## BASIC
|
|
################################################################################
|
|
func _ready():
|
|
%BG.add_theme_stylebox_override('panel', get_theme_stylebox('normal', 'LineEdit'))
|
|
%Focus.add_theme_stylebox_override('panel', get_theme_stylebox('focus', 'LineEdit'))
|
|
%Search.text_changed.connect(_on_Search_text_changed)
|
|
%Search.focus_entered.connect(_on_Search_focus_entered)
|
|
%Search.text_submitted.connect(_on_Search_text_entered)
|
|
var scale: float = DialogicUtil.get_editor_scale()
|
|
%SelectButton.icon = get_theme_icon("Collapse", "EditorIcons")
|
|
%Search.placeholder_text = placeholder_text
|
|
%Suggestions.add_theme_stylebox_override('bg', load("res://addons/dialogic/Editor/Events/styles/ResourceMenuPanelBackground.tres"))
|
|
%Suggestions.hide()
|
|
%Suggestions.item_selected.connect(suggestion_selected)
|
|
%Suggestions.item_clicked.connect(suggestion_selected)
|
|
if resource_icon == null:
|
|
self.resource_icon = null
|
|
|
|
%Search.placeholder_text = 'Select Resource'
|
|
if file_extension == '.dch':
|
|
%Search.placeholder_text = 'Select Character'
|
|
if file_extension == '.dtl':
|
|
%Search.placeholder_text = 'Select Timeline'
|
|
|
|
set_left_text('')
|
|
set_right_text('')
|
|
editor_reference = find_parent('EditorView')
|
|
|
|
func _exit_tree():
|
|
# Explicitly free any open cache resources on close, so we don't get leaked resource errors on shutdown
|
|
event_resource = null
|
|
|
|
################################################################################
|
|
## SEARCH & SUGGESTION POPUP
|
|
################################################################################
|
|
func _on_Search_text_entered(new_text:String) -> void:
|
|
if %Suggestions.get_item_count() and not %Search.text.is_empty():
|
|
if %Suggestions.is_anything_selected():
|
|
suggestion_selected(%Suggestions.get_selected_items()[0])
|
|
else:
|
|
suggestion_selected(0)
|
|
else:
|
|
changed_to_empty()
|
|
|
|
|
|
func _on_Search_text_changed(new_text:String, just_update:bool = false) -> void:
|
|
%Suggestions.clear()
|
|
|
|
if new_text == "" and !just_update:
|
|
changed_to_empty()
|
|
|
|
var suggestions :Dictionary = get_suggestions_func.call(new_text)
|
|
|
|
var line_length:int = 0
|
|
var idx:int = 0
|
|
for element in suggestions:
|
|
if new_text.is_empty() or new_text.to_lower() in element.to_lower() or new_text.to_lower() in str(suggestions[element].value).to_lower() or new_text.to_lower() in suggestions[element].get('tooltip', '').to_lower():
|
|
line_length = max(get_theme_font('font', 'Label').get_string_size(element, HORIZONTAL_ALIGNMENT_LEFT, -1, get_theme_font_size("font_size", 'Label')).x+80, line_length)
|
|
%Suggestions.add_item(element)
|
|
if suggestions[element].has('icon'):
|
|
%Suggestions.set_item_icon(idx, suggestions[element].icon)
|
|
elif suggestions[element].has('editor_icon'):
|
|
%Suggestions.set_item_icon(idx, get_theme_icon(suggestions[element].editor_icon[0],suggestions[element].editor_icon[1]))
|
|
|
|
%Suggestions.set_item_tooltip(idx, suggestions[element].get('tooltip', ''))
|
|
%Suggestions.set_item_metadata(idx, suggestions[element].value)
|
|
idx += 1
|
|
|
|
if not %Suggestions.visible:
|
|
%Suggestions.show()
|
|
%Suggestions.global_position = $PanelContainer.global_position+Vector2(0,1)*$PanelContainer.size.y
|
|
#%Suggestions.position = Vector2()
|
|
%Suggestions.size.x = max(%Search.size.x, line_length)
|
|
%Suggestions.size.y = min(%Suggestions.get_item_count()*35*DialogicUtil.get_editor_scale(), 200*DialogicUtil.get_editor_scale())
|
|
if %Suggestions.get_item_count():
|
|
%Suggestions.select(0)
|
|
current_selected = 0
|
|
else:
|
|
current_selected = -1
|
|
%Search.grab_focus()
|
|
|
|
func get_default_suggestions(input:String) -> Dictionary:
|
|
if file_extension.is_empty(): return {'Nothing found!':{'value':''}}
|
|
var suggestions: Dictionary = {}
|
|
if file_extension == ".dch":
|
|
suggestions['(No one)'] = {'value':'', 'editor_icon':["GuiRadioUnchecked", "EditorIcons"]}
|
|
|
|
for resource in editor_reference.character_directory.keys():
|
|
suggestions[resource] = {'value': resource, 'tooltip': editor_reference.character_directory[resource]['full_path']}
|
|
else:
|
|
var resources: Array = DialogicUtil.list_resources_of_type(file_extension)
|
|
|
|
for resource in resources:
|
|
suggestions[resource] = {'value':resource, 'tooltip':resource}
|
|
|
|
return suggestions
|
|
|
|
|
|
func suggestion_selected(index : int, position:=Vector2(), button_index:=MOUSE_BUTTON_LEFT) -> void:
|
|
if %Suggestions.is_item_disabled(index):
|
|
return
|
|
|
|
%Search.text = %Suggestions.get_item_text(index)
|
|
|
|
if %Suggestions.get_item_metadata(index) == null:
|
|
current_value = null
|
|
|
|
# if this is a resource, then load it instead of assigning the string:
|
|
elif file_extension != "" and file_extension != ".dch" and file_extension != ".dtl":
|
|
var file = load(%Suggestions.get_item_metadata(index))
|
|
current_value = file
|
|
else:
|
|
current_value = %Suggestions.get_item_metadata(index)
|
|
|
|
hide_suggestions()
|
|
|
|
%Search.grab_focus()
|
|
emit_signal("value_changed", property_name, current_value)
|
|
|
|
func _input(event:InputEvent):
|
|
if event is InputEventMouseButton and event.pressed:
|
|
if %Suggestions.visible:
|
|
if !%Suggestions.get_global_rect().has_point(get_global_mouse_position()):
|
|
hide_suggestions()
|
|
|
|
func hide_suggestions() -> void:
|
|
%SelectButton.button_pressed = false
|
|
%Suggestions.hide()
|
|
|
|
func _on_Search_focus_entered() -> void:
|
|
if %Search.text == "" or current_value == null or (typeof(current_value) == TYPE_STRING and current_value.is_empty()):
|
|
_on_Search_text_changed("")
|
|
|
|
func _on_SelectButton_toggled(button_pressed:bool) -> void:
|
|
if button_pressed:
|
|
_on_Search_text_changed('', true)
|
|
|
|
################################################################################
|
|
## DRAG AND DROP
|
|
################################################################################
|
|
|
|
func _can_drop_data(position, data) -> bool:
|
|
if typeof(data) == TYPE_DICTIONARY and data.has('files') and len(data.files) == 1:
|
|
if file_extension:
|
|
if data.files[0].ends_with(file_extension):
|
|
return true
|
|
else:
|
|
return false
|
|
return false
|
|
|
|
func _drop_data(position, data) -> void:
|
|
if data.files[0].ends_with('dch'):
|
|
for character in editor_reference.character_directory.keys():
|
|
if editor_reference.character_directory[character]["full_path"] == data.files[0]:
|
|
set_value(character)
|
|
break
|
|
elif data.files[0].ends_with('dtl'):
|
|
for timeline in editor_reference.timeline_directory.keys():
|
|
if editor_reference.timeline_directory[timeline] == data.files[0]:
|
|
set_value(timeline)
|
|
break
|
|
else:
|
|
var file = load(data.files[0])
|
|
set_value(file)
|
|
emit_signal("value_changed", property_name, file)
|
|
|
|
|
|
func _on_focus_entered():
|
|
%Search.grab_focus()
|
|
|
|
func _on_search_gui_input(event):
|
|
if event is InputEventKey and (event.keycode == KEY_DOWN or event.keycode == KEY_UP) and event.pressed:
|
|
if !%Suggestions.visible:
|
|
_on_Search_text_changed('', true)
|
|
current_selected = -1
|
|
if event.keycode == KEY_DOWN:
|
|
current_selected = wrapi(current_selected+1, 0, %Suggestions.item_count)
|
|
if event.keycode == KEY_UP:
|
|
current_selected = wrapi(current_selected-1, 0, %Suggestions.item_count)
|
|
%Suggestions.select(current_selected)
|
|
%Suggestions.ensure_current_is_visible()
|
|
|
|
func _on_search_focus_entered():
|
|
%Focus.show()
|
|
|
|
func _on_search_focus_exited():
|
|
%Focus.hide()
|
|
if !%Suggestions.get_global_rect().has_point(get_global_mouse_position()):
|
|
hide_suggestions()
|