253 lines
6.8 KiB
GDScript
253 lines
6.8 KiB
GDScript
extends Container
|
|
class_name TopicDraggable
|
|
|
|
const SCROLL_SPEED = 25.0
|
|
|
|
onready var topic_feed: VBoxContainer = get_node("..")
|
|
onready var scroll_container: ScrollContainer = get_node("../..")
|
|
onready var v_scroll: VScrollBar = get_node("../../_v_scroll")
|
|
onready var editable = get_node("TopicEditable")
|
|
onready var tween = get_node("Tween")
|
|
|
|
var global_position setget _set_global_position
|
|
var local_position setget _set_local_position
|
|
var _in_fit_in_animation = false
|
|
var _previous_global_position
|
|
var _previous_scroll
|
|
var _offset
|
|
var _something_passed = false
|
|
|
|
|
|
func _ready():
|
|
pass
|
|
|
|
|
|
func _gui_input(event):
|
|
if event is InputEventMouseButton and event.button_index == BUTTON_LEFT:
|
|
if event.is_pressed():
|
|
if event.shift:
|
|
topic_feed._toggle_selection_result = _set_selection(null)
|
|
topic_feed._shift_hold = true
|
|
else:
|
|
_deselect_all()
|
|
if not editable.edit_mode:
|
|
if event.doubleclick:
|
|
editable._enable_edit_mode()
|
|
editable.text_edit.grab_focus()
|
|
yield(get_tree(), "idle_frame")
|
|
editable.text_edit.select_all()
|
|
elif !_in_fit_in_animation:
|
|
_set_as_grabbed()
|
|
|
|
|
|
func _input(event):
|
|
if event is InputEventMouseButton and event.button_index == BUTTON_LEFT:
|
|
if event.is_pressed():
|
|
if !_is_mouse_on_topic() and editable.edit_mode:
|
|
editable.text_edit._confirm()
|
|
else:
|
|
if _is_grabbed():
|
|
_fit_in_animation()
|
|
topic_feed._shift_hold = false
|
|
|
|
if event is InputEventMouseMotion:
|
|
if _is_grabbed():
|
|
_move_block(event)
|
|
topic_feed.check_all_passings()
|
|
if topic_feed._shift_hold and _is_mouse_on_topic():
|
|
# warning-ignore:return_value_discarded
|
|
_set_selection(topic_feed._toggle_selection_result)
|
|
|
|
if event is InputEventMouseButton:
|
|
if _is_grabbed():
|
|
var scroll_value = 0.0
|
|
|
|
if event.button_index == BUTTON_WHEEL_UP:
|
|
scroll_value = -SCROLL_SPEED
|
|
elif event.button_index == BUTTON_WHEEL_DOWN:
|
|
scroll_value = SCROLL_SPEED
|
|
|
|
if scroll_value != 0.0:
|
|
scroll_container.scroll_vertical += scroll_value
|
|
_previous_scroll = scroll_container.scroll_vertical
|
|
topic_feed.check_all_passings()
|
|
|
|
|
|
func _set_selection(to) -> bool:
|
|
# If 'to' is null, selection is toggled.
|
|
if topic_feed.selected_topics.has(self) and to != true:
|
|
topic_feed.selected_topics.erase(self)
|
|
editable._update_color()
|
|
return false
|
|
elif !topic_feed.selected_topics.has(self) and to != false:
|
|
topic_feed.selected_topics.append(self)
|
|
editable._update_color()
|
|
return true
|
|
else:
|
|
return topic_feed.selected_topics.has(self)
|
|
|
|
|
|
func _deselect_all():
|
|
topic_feed.selected_topics.clear()
|
|
topic_feed.update_all_colors()
|
|
|
|
|
|
func _set_as_grabbed():
|
|
var rect = editable.get_global_rect()
|
|
rect_min_size.y = editable.rect_size.y
|
|
editable.set_as_toplevel(true)
|
|
editable.mouse_filter = MOUSE_FILTER_IGNORE
|
|
editable.rect_position = rect.position
|
|
topic_feed.currently_grabbed_topic = self
|
|
_previous_global_position = editable.rect_global_position
|
|
_previous_scroll = scroll_container.scroll_vertical
|
|
_offset = 0
|
|
_move_block(InputEventMouseMotion.new())
|
|
|
|
|
|
func _fit_in_animation():
|
|
_in_fit_in_animation = true
|
|
topic_feed.currently_grabbed_topic = null
|
|
|
|
var overhead = _topic_overhead(rect_global_position.y)
|
|
|
|
var from = editable.rect_global_position
|
|
var to
|
|
|
|
if overhead > 0.0:
|
|
var sc_rect = scroll_container.get_global_rect()
|
|
to = Vector2(
|
|
sc_rect.position.x,
|
|
sc_rect.end.y - rect_size.y
|
|
)
|
|
elif overhead < 0.0:
|
|
to = scroll_container.rect_global_position
|
|
else:
|
|
to = rect_global_position - Vector2(0.0, overhead)
|
|
|
|
tween.stop_all()
|
|
tween.interpolate_property(self, "global_position",
|
|
from, to,
|
|
0.12, Tween.TRANS_LINEAR, Tween.EASE_IN_OUT
|
|
)
|
|
|
|
if overhead != 0.0:
|
|
tween.interpolate_property(scroll_container, "scroll_vertical",
|
|
scroll_container.scroll_vertical, scroll_container.scroll_vertical + overhead,
|
|
0.12, Tween.TRANS_LINEAR, Tween.EASE_IN_OUT
|
|
)
|
|
|
|
tween.start()
|
|
|
|
yield(tween, "tween_completed")
|
|
editable.set_as_toplevel(false)
|
|
editable.mouse_filter = MOUSE_FILTER_PASS
|
|
rect_min_size.y = 0
|
|
editable.rect_position = Vector2.ZERO
|
|
_in_fit_in_animation = false
|
|
|
|
|
|
func _move_block(event):
|
|
_offset += event.relative.y
|
|
|
|
var virtual_position = _previous_global_position + Vector2(0.0, _offset)
|
|
var overhead = _topic_overhead(virtual_position.y)
|
|
|
|
virtual_position.y -= overhead
|
|
|
|
if get_index() == topic_feed.get_child_count() - 2:
|
|
if virtual_position.y > rect_global_position.y:
|
|
virtual_position.y = rect_global_position.y
|
|
|
|
_set_global_position(virtual_position)
|
|
scroll_container.scroll_vertical = _previous_scroll + overhead
|
|
|
|
|
|
# How much topic is out of scroll_container bounds.
|
|
func _topic_overhead(y_pos):
|
|
var scroll_rect = scroll_container.get_global_rect()
|
|
scroll_rect.size.y -= editable.rect_size.y
|
|
var overhead = 0
|
|
|
|
# Higher?
|
|
if y_pos < scroll_rect.position.y:
|
|
overhead = y_pos - scroll_rect.position.y
|
|
|
|
# Lower?
|
|
if y_pos > scroll_rect.end.y:
|
|
overhead = y_pos - scroll_rect.end.y
|
|
|
|
return overhead
|
|
|
|
|
|
func _is_mouse_on_topic() -> bool:
|
|
var on_topic = get_global_rect().has_point(get_global_mouse_position())
|
|
return _is_mouse_on_topic_feed() and on_topic
|
|
|
|
|
|
func _is_mouse_on_topic_feed() -> bool:
|
|
return scroll_container.get_global_rect().has_point(get_global_mouse_position())
|
|
|
|
|
|
func _is_grabbed() -> bool:
|
|
return topic_feed.currently_grabbed_topic == self
|
|
|
|
|
|
func set_previous_position():
|
|
_previous_global_position = editable.rect_global_position
|
|
|
|
|
|
func check_for_passing() -> bool:
|
|
var dragged: TopicDraggable = topic_feed.currently_grabbed_topic
|
|
if dragged == self or dragged == null:
|
|
return false
|
|
|
|
var dir = sign(dragged.get_index() - get_index())
|
|
|
|
var self_rect = get_global_rect()
|
|
var self_half_size = self_rect.size.y * 0.5
|
|
# Center line.
|
|
var self_coll_line = self_rect.position.y + self_half_size
|
|
|
|
var dragged_rect = dragged.editable.get_global_rect()
|
|
var dragged_half_size = dragged_rect.size.y * 0.5
|
|
var dragged_half_pos = dragged_rect.position.y + dragged_half_size
|
|
# Top or bottom line, depending on if moved up or down.
|
|
var dragged_coll_line = dragged_half_pos + dragged_half_size * -dir
|
|
|
|
# +1 if dragged_coll_line is below; -1 if above.
|
|
var coll_dir = sign(self_coll_line - dragged_coll_line)
|
|
|
|
if coll_dir == dir:
|
|
topic_feed.set_all_previous_positions()
|
|
topic_feed.move_child(
|
|
topic_feed.currently_grabbed_topic,
|
|
get_index()
|
|
)
|
|
_something_passed = true
|
|
Data.topics.dirty_flag = true
|
|
return true
|
|
return false
|
|
|
|
|
|
func setup_tween():
|
|
if _something_passed:
|
|
var _previous_local_position = _previous_global_position - rect_global_position
|
|
|
|
tween.stop_all()
|
|
tween.interpolate_property(self, "local_position",
|
|
_previous_local_position, Vector2.ZERO, 0.15,
|
|
Tween.TRANS_LINEAR, Tween.EASE_IN_OUT
|
|
)
|
|
tween.start()
|
|
_something_passed = false
|
|
yield(tween, "tween_completed")
|
|
|
|
|
|
func _set_global_position(value):
|
|
editable.set_global_position(value)
|
|
|
|
|
|
func _set_local_position(value):
|
|
editable.rect_position = value
|