You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
199 lines
6.0 KiB
199 lines
6.0 KiB
6 months ago
|
@tool
|
||
|
class_name DialogicVisualEditorFieldNumber
|
||
|
extends DialogicVisualEditorField
|
||
|
|
||
|
## Event block field for integers and floats. Improved version of the native spinbox.
|
||
|
|
||
|
@export var allow_string : bool = false
|
||
|
@export var step: float = 0.1
|
||
|
@export var enforce_step: bool = true
|
||
|
@export var min: float = 0
|
||
|
@export var max: float= 999
|
||
|
@export var value = 0.0
|
||
|
@export var prefix: String = ""
|
||
|
@export var suffix: String = ""
|
||
|
|
||
|
var _is_holding_button: bool = false #For handling incrementing while holding key or click
|
||
|
|
||
|
#region MAIN METHODS
|
||
|
################################################################################
|
||
|
|
||
|
func _ready() -> void:
|
||
|
if %Value.text.is_empty():
|
||
|
set_value(value)
|
||
|
|
||
|
update_prefix(prefix)
|
||
|
update_suffix(suffix)
|
||
|
$Value_Panel.add_theme_stylebox_override('panel', get_theme_stylebox('panel', 'DialogicEventEdit'))
|
||
|
|
||
|
|
||
|
func _load_display_info(info: Dictionary) -> void:
|
||
|
match info.get('mode', 0):
|
||
|
0: #FLOAT
|
||
|
use_float_mode(info.get('step', 0.1))
|
||
|
1: #INT
|
||
|
use_int_mode(info.get('step', 1))
|
||
|
2: #DECIBLE:
|
||
|
use_decibel_mode(info.get('step', step))
|
||
|
|
||
|
for option in info.keys():
|
||
|
match option:
|
||
|
'min': min = info[option]
|
||
|
'max': max = info[option]
|
||
|
'prefix': update_prefix(info[option])
|
||
|
'suffix': update_suffix(info[option])
|
||
|
'step':
|
||
|
enforce_step = true
|
||
|
step = info[option]
|
||
|
'hide_step_button': %Spin.hide()
|
||
|
|
||
|
|
||
|
func _set_value(new_value: Variant) -> void:
|
||
|
_on_value_text_submitted(str(new_value), true)
|
||
|
%Value.tooltip_text = tooltip_text
|
||
|
|
||
|
|
||
|
func _autofocus():
|
||
|
%Value.grab_focus()
|
||
|
|
||
|
|
||
|
func get_value() -> float:
|
||
|
return value
|
||
|
|
||
|
|
||
|
func use_float_mode(value_step: float = 0.1) -> void:
|
||
|
step = value_step
|
||
|
update_suffix("")
|
||
|
enforce_step = false
|
||
|
|
||
|
|
||
|
func use_int_mode(value_step: float = 1) -> void:
|
||
|
step = value_step
|
||
|
update_suffix("")
|
||
|
enforce_step = true
|
||
|
|
||
|
|
||
|
func use_decibel_mode(value_step: float = step) -> void:
|
||
|
max = 6
|
||
|
update_suffix("dB")
|
||
|
min = -80
|
||
|
|
||
|
#endregion
|
||
|
|
||
|
#region UI FUNCTIONALITY
|
||
|
################################################################################
|
||
|
var _stop_button_holding: Callable = func(button: BaseButton) -> void:
|
||
|
_is_holding_button = false
|
||
|
if button.button_up.get_connections().find(_stop_button_holding):
|
||
|
button.button_up.disconnect(_stop_button_holding)
|
||
|
if button.focus_exited.get_connections().find(_stop_button_holding):
|
||
|
button.focus_exited.disconnect(_stop_button_holding)
|
||
|
if button.mouse_exited.get_connections().find(_stop_button_holding):
|
||
|
button.mouse_exited.disconnect(_stop_button_holding)
|
||
|
|
||
|
|
||
|
func _holding_button(value_direction: int, button: BaseButton) -> void:
|
||
|
if _is_holding_button:
|
||
|
return
|
||
|
if _stop_button_holding.get_bound_arguments_count() > 0:
|
||
|
_stop_button_holding.unbind(0)
|
||
|
|
||
|
_is_holding_button = true
|
||
|
|
||
|
#Ensure removal of our value changing routine when it shouldn't run anymore
|
||
|
button.button_up.connect(_stop_button_holding.bind(button))
|
||
|
button.focus_exited.connect(_stop_button_holding.bind(button))
|
||
|
button.mouse_exited.connect(_stop_button_holding.bind(button))
|
||
|
|
||
|
var scene_tree: SceneTree = get_tree()
|
||
|
var delay_timer_ms: int = 600
|
||
|
|
||
|
#Instead of awaiting for the duration, await per-frame so we can catch any changes in _is_holding_button and exit completely
|
||
|
while(delay_timer_ms > 0):
|
||
|
if _is_holding_button == false:
|
||
|
return
|
||
|
var pre_time: int = Time.get_ticks_msec()
|
||
|
await scene_tree.process_frame
|
||
|
delay_timer_ms -= Time.get_ticks_msec() - pre_time
|
||
|
|
||
|
var change_speed: float = 0.25
|
||
|
|
||
|
while(_is_holding_button == true):
|
||
|
await scene_tree.create_timer(change_speed).timeout
|
||
|
change_speed = maxf(0.05, change_speed - 0.01)
|
||
|
_on_value_text_submitted(str(value+(step * value_direction)))
|
||
|
|
||
|
|
||
|
func update_prefix(to_prefix: String) -> void:
|
||
|
prefix = to_prefix
|
||
|
%Prefix.visible = to_prefix != null and to_prefix != ""
|
||
|
%Prefix.text = prefix
|
||
|
|
||
|
|
||
|
func update_suffix(to_suffix: String) -> void:
|
||
|
suffix = to_suffix
|
||
|
%Suffix.visible = to_suffix != null and to_suffix != ""
|
||
|
%Suffix.text = suffix
|
||
|
|
||
|
#endregion
|
||
|
|
||
|
#region SIGNAL METHODS
|
||
|
################################################################################
|
||
|
func _on_gui_input(event: InputEvent) -> void:
|
||
|
if event.is_action('ui_up') and event.get_action_strength('ui_up') > 0.5:
|
||
|
_on_value_text_submitted(str(value+step))
|
||
|
elif event.is_action('ui_down') and event.get_action_strength('ui_down') > 0.5:
|
||
|
_on_value_text_submitted(str(value-step))
|
||
|
|
||
|
|
||
|
func _on_increment_button_down(button: NodePath) -> void:
|
||
|
_on_value_text_submitted(str(value+step))
|
||
|
_holding_button(1.0, get_node(button) as BaseButton)
|
||
|
|
||
|
|
||
|
func _on_decrement_button_down(button: NodePath) -> void:
|
||
|
_on_value_text_submitted(str(value-step))
|
||
|
_holding_button(-1.0, get_node(button) as BaseButton)
|
||
|
|
||
|
|
||
|
func _on_value_text_submitted(new_text: String, no_signal:= false) -> void:
|
||
|
if new_text.is_valid_float():
|
||
|
var temp: float = min(max(new_text.to_float(), min), max)
|
||
|
if !enforce_step:
|
||
|
value = temp
|
||
|
else:
|
||
|
value = snapped(temp, step)
|
||
|
elif allow_string:
|
||
|
value = new_text
|
||
|
%Value.text = str(value).pad_decimals(len(str(float(step)-floorf(step)))-2)
|
||
|
if not no_signal:
|
||
|
value_changed.emit(property_name, value)
|
||
|
# Visually disable Up or Down arrow when limit is reached to better indicate a limit has been hit
|
||
|
%Spin/Decrement.disabled = value <= min
|
||
|
%Spin/Increment.disabled = value >= max
|
||
|
|
||
|
|
||
|
# If prefix or suffix was clicked, select the actual value box instead and move the caret to the closest side.
|
||
|
func _on_sublabel_clicked(event: InputEvent) -> void:
|
||
|
if event is InputEventMouseButton and event.pressed and event.button_index == MOUSE_BUTTON_LEFT:
|
||
|
var mousePos: Vector2 = get_global_mouse_position()
|
||
|
mousePos.x -= get_minimum_size().x / 2
|
||
|
if mousePos.x > global_position.x:
|
||
|
(%Value as LineEdit).caret_column = (%Value as LineEdit).text.length()
|
||
|
else:
|
||
|
(%Value as LineEdit).caret_column = 0
|
||
|
(%Value as LineEdit).grab_focus()
|
||
|
|
||
|
|
||
|
func _on_value_focus_exited() -> void:
|
||
|
_on_value_text_submitted(%Value.text)
|
||
|
$Value_Panel.add_theme_stylebox_override('panel', get_theme_stylebox('panel', 'DialogicEventEdit'))
|
||
|
|
||
|
|
||
|
func _on_value_focus_entered() -> void:
|
||
|
$Value_Panel.add_theme_stylebox_override('panel', get_theme_stylebox('focus', 'DialogicEventEdit'))
|
||
|
%Value.select_all.call_deferred()
|
||
|
|
||
|
#endregion
|
||
|
|