Skip to content

Instantly share code, notes, and snippets.

@xsellier
Created July 29, 2021 08:50
Show Gist options
  • Save xsellier/d5e1ebc05e084f3255756ababe1a32b0 to your computer and use it in GitHub Desktop.
Save xsellier/d5e1ebc05e084f3255756ababe1a32b0 to your computer and use it in GitHub Desktop.
AnimatedToggle button for Godot Engine 2.1
tool
extends TextureButton
const ANIMATION_DURATION = 0.667
const TICK_TEXTURE = preload('res://theme/blank/white-128x128-circle.tex')
const BUTTON_BACKGROUND = preload('res://theme/blank/bean-128x60.tex')
export(float, 0.1, 1.0, 0.01) var tick_ratio = 0.8 setget set_tick_ratio, get_tick_ratio
export(Color) var unselected_background = Color('#12171e') setget set_unselected_background, get_unselected_background
export(Color) var unselected_tick = Color('#fefefe') setget set_unselected_tick, get_unselected_tick
export(Color) var selected_background = Color('#0092e9') setget set_selected_background, get_selected_background
export(Color) var selected_tick = Color('#fefefe') setget set_selected_tick, get_selected_tick
export(Color) var warning_background = Color('#ff6363') setget set_warning_background, get_warning_background
export(bool) var wargning_color = false setget set_warning, is_warning
var TOGGLER_POSITIONS = [
Vector2(0, 0),
Vector2(0, 0)
]
var texture_frame_node = TextureFrame.new()
var tween_node = Tween.new()
var button_texture_size = Vector2()
var button_texture_aspect = 1.0
func _init():
set_toggle_mode(true)
set_normal_texture(BUTTON_BACKGROUND)
set_resize_mode(RESIZE_STRETCH)
set_stretch_mode(STRETCH_KEEP_ASPECT_CENTERED)
button_texture_size = get_normal_texture().get_size()
button_texture_aspect = button_texture_size.get_aspect()
texture_frame_node.set_texture(TICK_TEXTURE)
texture_frame_node.set_expand(true)
texture_frame_node.set_stretch_mode(TextureFrame.STRETCH_KEEP_ASPECT_CENTERED)
add_child(tween_node)
add_child(texture_frame_node)
connect('resized', self, '_update_tick')
connect('toggled', self, '_update_toggler')
call_deferred('_update_tick')
func set_unselected_background(value):
if unselected_background != value:
unselected_background = value
_update_tick()
func set_unselected_tick(value):
if unselected_tick != value:
unselected_tick = value
_update_tick()
func set_selected_background(value):
if selected_background != value:
selected_background = value
_update_tick()
func set_selected_tick(value):
if selected_tick != value:
selected_tick = value
_update_tick()
func set_warning_background(value):
if warning_background != value:
warning_background = value
_update_toggler(is_pressed())
func set_warning(value):
if wargning_color != value:
wargning_color = value
_update_toggler(is_pressed())
func is_warning():
return wargning_color
func get_warning_background():
return warning_background
func get_unselected_background():
return unselected_background
func get_unselected_tick():
return unselected_tick
func get_selected_background():
return selected_background
func get_selected_tick():
return selected_tick
func set_tick_ratio(value):
tick_ratio = value
_update_tick()
func get_tick_ratio():
return tick_ratio
func set_disabled(value):
.set_disabled(value)
if value:
set_opacity(0.6)
else:
set_opacity(1.0)
func set_button_pressed(value):
set_pressed(value)
_update_toggler(value)
func toggle():
set_button_pressed(not is_pressed())
func _update_tick():
var button_size = get_size()
var texture_size_y = floor(min(button_size.x / button_texture_aspect, button_size.y))
var texture_size_x = floor(min(button_size.x, button_size.y * button_texture_aspect))
var texture_size = Vector2(texture_size_x, texture_size_y)
var tick_computed_size = (Vector2(texture_size.y, texture_size.y) * tick_ratio).floor()
var tick_position = (button_size - texture_size) / 2.0
var tick_color = selected_tick if is_pressed() else unselected_tick
var postion_decal_ratio = (Vector2(texture_size.y, texture_size.y) - tick_computed_size) / 2.0
texture_frame_node.set_custom_minimum_size(tick_computed_size)
texture_frame_node.set_size(tick_computed_size)
texture_frame_node.set_modulate(tick_color)
TOGGLER_POSITIONS[0] = tick_position + postion_decal_ratio
TOGGLER_POSITIONS[1] = tick_position + postion_decal_ratio
TOGGLER_POSITIONS[1].x += texture_size.x - tick_computed_size.x - 2.0 * postion_decal_ratio.x
var tick_position_computed = TOGGLER_POSITIONS[1] if is_pressed() else TOGGLER_POSITIONS[0]
texture_frame_node.set_pos(tick_position_computed)
call_deferred('_update_toggler', is_pressed())
func _update_toggler(value):
var from_position = texture_frame_node.get_pos()
var to_position = TOGGLER_POSITIONS[1] if value else TOGGLER_POSITIONS[0]
var from_color = get_modulate()
var to_color = selected_background if value else unselected_background
var tick_from_color = texture_frame_node.get_modulate()
var tick_to_color = selected_tick if value else unselected_tick
if is_warning():
to_color = warning_background
tween_node.remove_all()
tween_node.interpolate_property(texture_frame_node, 'rect/pos', from_position, to_position, ANIMATION_DURATION, Tween.TRANS_BOUNCE, Tween.EASE_OUT)
tween_node.interpolate_property(texture_frame_node, 'modulate', tick_from_color, tick_to_color, ANIMATION_DURATION, Tween.TRANS_SINE, Tween.EASE_OUT)
tween_node.interpolate_property(self, 'params/modulate', from_color, to_color, ANIMATION_DURATION, Tween.TRANS_SINE, Tween.EASE_OUT)
tween_node.start()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment