Last active
May 20, 2022 11:26
-
-
Save assertchris/98058e3eb817450547822a6d073c37f5 to your computer and use it in GitHub Desktop.
iOS-like scroll picker container for text selection
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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