Skip to content

Instantly share code, notes, and snippets.

@assertchris
Last active May 20, 2022 11:26
Show Gist options
  • Save assertchris/98058e3eb817450547822a6d073c37f5 to your computer and use it in GitHub Desktop.
Save assertchris/98058e3eb817450547822a6d073c37f5 to your computer and use it in GitHub Desktop.
iOS-like scroll picker container for text selection
extends ScrollContainer
class_name GameScrollPicker
export (Array, String) var items := [] setget set_items
export (Resource) var label_theme
export var label_height := 50
onready var _items := $Items as VBoxContainer
func set_items(items : Array) -> void:
for i in range(2):
var label = create_label('')
_items.add_child(label)
for i in items.size():
var label = create_label(items[i])
_items.add_child(label)
for i in range(1):
var label = create_label('')
_items.add_child(label)
func create_label(text : String) -> Label:
var label = Label.new()
label.text = text
label.theme = label_theme
label.align = label.ALIGN_CENTER
label.valign = label.VALIGN_CENTER
label.rect_min_size = Vector2(0, label_height)
return label
func _process(_delta: float) -> void:
if not label_height:
return
rect_min_size = Vector2(0, label_height * 5)
for child in _items.get_children():
if child.rect_position.y == scroll_vertical + (label_height * 2):
child.modulate.a = 1.0
elif child.rect_position.y == scroll_vertical + (label_height * 1) or child.rect_position.y == scroll_vertical + (label_height * 3):
child.modulate.a = 0.5
else:
child.modulate.a = 0.1
"""
Original: https://github.com/godotengine/godot/issues/21137
Helper Script for ScrollContainer to let them scroll with InputListeners inside.
Buttons inside should react to release, in order to be not activated during scroll.
Does not work with Touch Screen Buttons as they handle the input before.
"""
export (Vector2) var delta_for_swipe := Vector2(8, 8)
var look_for_swipe := false
var swiping := false
var swipe_start : Vector2
var swipe_mouse_start : Vector2
var swipe_mouse_times := []
var swipe_mouse_positions := []
var tween : Tween
func _input(ev) -> void:
if !is_visible_in_tree():
return
if ev is InputEventScreenDrag and swiping:
accept_event()
return
if ev is InputEventMouseButton:
if ev.pressed and get_viewport_transform().xform(get_global_rect()).has_point(ev.global_position):
look_for_swipe = true
swipe_mouse_start = ev.global_position
elif swiping:
swipe_mouse_times.append(OS.get_ticks_msec())
swipe_mouse_positions.append(ev.global_position)
var source := Vector2(get_h_scroll(), get_v_scroll())
var idx := swipe_mouse_times.size() - 1
var now := OS.get_ticks_msec()
var cutoff := now - 100
for i in range(swipe_mouse_times.size() - 1, -1, -1):
if swipe_mouse_times[i] >= cutoff:
idx = i
else: break
var flick_start : Vector2 = swipe_mouse_positions[idx]
var flick_dur := min(0.3, (ev.global_position - flick_start).length() / 1000)
if flick_dur > 0.0:
tween = Tween.new()
add_child(tween)
var delta : Vector2 = ev.global_position - flick_start
var target := source - delta * flick_dur * 15.0
tween.interpolate_method(self, 'set_h_scroll', source.x, stepify(target.x, label_height), flick_dur, Tween.TRANS_LINEAR, Tween.EASE_OUT)
tween.interpolate_method(self, 'set_v_scroll', source.y, stepify(target.y, label_height), flick_dur, Tween.TRANS_LINEAR, Tween.EASE_OUT)
tween.interpolate_callback(tween, flick_dur, 'queue_free')
tween.start()
swiping = false
swipe_mouse_times = []
swipe_mouse_positions = []
else:
look_for_swipe = false
if ev is InputEventMouseMotion:
if look_for_swipe:
var delta = ev.global_position - swipe_mouse_start
if abs(delta.x) > delta_for_swipe.x or abs(delta.y) > delta_for_swipe.y:
swiping = true
look_for_swipe = false
swipe_start = Vector2(get_h_scroll(), get_v_scroll())
swipe_mouse_start = ev.global_position
swipe_mouse_times = [OS.get_ticks_msec()]
swipe_mouse_positions = [swipe_mouse_start]
if is_instance_valid(tween) and tween is Tween:
tween.stop_all()
if swiping:
var delta : Vector2 = ev.global_position - swipe_mouse_start
set_h_scroll(stepify(swipe_start.x - delta.x, label_height))
set_v_scroll(stepify(swipe_start.y - delta.y, label_height))
swipe_mouse_times.append(OS.get_ticks_msec())
swipe_mouse_positions.append(ev.global_position)
ev.position = Vector2.ZERO
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment