diary/user_interface/utility_controls/content_fit_text_edit.gd

155 lines
3.8 KiB
GDScript3
Raw Normal View History

extends TextEdit
class_name ContentFitTextEdit
signal confirmed(content)
const PLACEHOLDER_VISIBILITY = 0.35
const MAIN_THEME = preload("res://user_interface/main.theme")
export(NodePath) var expansion_target = @"."
export(int) var height_addition = 0
export(int) var min_height = 0
export(int) var max_height = 0
export(bool) var expand_width = false
export(int) var width_addition = 0
export(int) var min_width = 0
export(int) var max_width = 488
export(String) var placeholder = ""
export(bool) var confirm_on_focus_exit = false
var reference_label: Label
var width_reference_label: Label
func _ready():
reference_label = Label.new()
reference_label.name = "@@9"
width_reference_label = Label.new()
width_reference_label.name = "@@10"
width_reference_label.theme = MAIN_THEME
width_reference_label.self_modulate.a = 0.0
width_reference_label.set_as_toplevel(true)
reference_label.margin_top = 2.0
reference_label.anchor_right = 1.0
reference_label.margin_right = -9.0
reference_label.autowrap = true
add_child(reference_label)
add_child(width_reference_label)
_check_for_placeholder(false)
# warning-ignore:return_value_discarded
connect("text_changed", self, "_on_text_changed")
# warning-ignore:return_value_discarded
connect("resized", self, "_on_resized")
# warning-ignore:return_value_discarded
connect("focus_entered", self, "_on_focus_entered")
# warning-ignore:return_value_discarded
connect("focus_exited", self, "_on_focus_exited")
func _input(event):
if has_focus():
if event is InputEventKey and event.is_pressed():
if event.scancode == KEY_ENTER and not event.shift:
get_tree().set_input_as_handled()
_confirm()
func _on_text_changed():
adjust_size()
if expand_width:
# I honestly don't know why, but the second call helps with refreshing.
adjust_size()
func _on_resized():
_adjust_height()
func _on_focus_entered():
if has_focus():
_check_for_placeholder(true)
func _on_focus_exited():
_check_for_placeholder(false)
if confirm_on_focus_exit:
_confirm()
func _confirm():
emit_signal("confirmed", text)
func adjust_size():
if expand_width:
width_reference_label.rect_size.x = 1
width_reference_label.text = text
_adjust_width()
reference_label.text = text
_refresh()
_adjust_height()
func _adjust_width():
if is_connected("resized", self, "_on_resized"):
disconnect("resized", self, "_on_resized")
var target = get_node(expansion_target)
# I swear I'm not doing this for fun.
width_reference_label.visible = false
width_reference_label.visible = true
var width = width_reference_label.rect_size.x
target.rect_min_size.x = clamp(width, min_width, max_width) + width_addition
if not is_connected("resized", self, "_on_resized"):
# warning-ignore:return_value_discarded
connect("resized", self, "_on_resized")
func _adjust_height():
if is_connected("resized", self, "_on_resized"):
disconnect("resized", self, "_on_resized")
var target = get_node(expansion_target)
var height = reference_label.rect_size.y + height_addition
if max_height > 0:
height = min(height, max_height)
height = max(height, min_height)
target.rect_min_size.y = height
if not is_connected("resized", self, "_on_resized"):
# warning-ignore:return_value_discarded
connect("resized", self, "_on_resized")
func _check_for_placeholder(focus: bool):
if !focus and text.empty():
reference_label.text = placeholder
reference_label.self_modulate.a = PLACEHOLDER_VISIBILITY
else:
reference_label.self_modulate.a = 0.0
# Control sizes sometimes don't refresh properly, but this can be forces, by
# turning visibility off and on again.
func _refresh():
var had_focus = has_focus()
disconnect("focus_exited", self, "_on_focus_exited")
visible = false
visible = true
if had_focus:
grab_focus()
_check_for_placeholder(had_focus)
# warning-ignore:return_value_discarded
connect("focus_exited", self, "_on_focus_exited")