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")