247 lines
6.7 KiB
GDScript3
247 lines
6.7 KiB
GDScript3
|
@tool
|
|||
|
extends Container
|
|||
|
##抽屉容器节点,可以用于将子节点侧滑,开启clip content可以做到完全隐藏子节点
|
|||
|
class_name DrawerContainer
|
|||
|
##按钮大小
|
|||
|
@export var custom_button_size:Vector2=Vector2.ZERO:
|
|||
|
set(val):
|
|||
|
custom_button_size=val
|
|||
|
side_button_size_changed()
|
|||
|
fit_children()
|
|||
|
fit_side_button()
|
|||
|
var button_size:Vector2=Vector2(100,200):
|
|||
|
set(val):
|
|||
|
button_size=val
|
|||
|
fit_children()
|
|||
|
fit_side_button()
|
|||
|
##按钮场景,根节点必须为basebutton或继承自basebutton,留空则使用默认按钮
|
|||
|
@export var button_tscn:PackedScene
|
|||
|
##布局模式
|
|||
|
@export var button_model:BUTTON_MODEL=BUTTON_MODEL.TOP
|
|||
|
enum BUTTON_MODEL{
|
|||
|
##按钮在上方,向下收纳
|
|||
|
TOP=0,
|
|||
|
##按钮在下方,向上收纳
|
|||
|
END=1,
|
|||
|
##按钮在左方,向右收纳
|
|||
|
LEFT=2,
|
|||
|
##按钮在右方,向左收纳
|
|||
|
RIGHT=3,
|
|||
|
}
|
|||
|
##动画时间
|
|||
|
@export var animation_time:float=0.5
|
|||
|
##是否自动隐藏
|
|||
|
@export var is_auto_hide:bool=false
|
|||
|
#隐藏计时器
|
|||
|
@onready var hide_timer:Timer=Timer.new()
|
|||
|
##是否自动收缩
|
|||
|
@export var is_auto_shrink:bool=false
|
|||
|
##是否禁用按钮
|
|||
|
@export var disable_button:bool=false:
|
|||
|
set(val):
|
|||
|
disable_button=val
|
|||
|
fit_side_button()
|
|||
|
fit_side_button()
|
|||
|
if side_button!=null:
|
|||
|
if val :
|
|||
|
side_button.hide()
|
|||
|
else:
|
|||
|
side_button.show()
|
|||
|
##动画过渡模式
|
|||
|
@export var animation_model:Tween.TransitionType=Tween.TransitionType.TRANS_BACK
|
|||
|
##当前持有的动画
|
|||
|
var now_keep_tween:Tween
|
|||
|
##当前是否打开
|
|||
|
@export var is_open:bool=true
|
|||
|
##持有的抽屉控制按钮的实例(内部节点)
|
|||
|
var side_button:BaseButton
|
|||
|
|
|||
|
##获取当前持有的侧边按钮
|
|||
|
func get_side_button()->BaseButton:
|
|||
|
return side_button
|
|||
|
|
|||
|
##当前动画状态,0为完全打开,1为完全关闭
|
|||
|
@export var rag:float=0:
|
|||
|
set(val):
|
|||
|
rag=val
|
|||
|
fit_side_button()
|
|||
|
fit_children()
|
|||
|
minimum_size_changed.emit()
|
|||
|
func _ready() -> void:
|
|||
|
add_child(hide_timer,false,Node.INTERNAL_MODE_FRONT)
|
|||
|
hide_timer.one_shot=true
|
|||
|
hide_timer.timeout.connect(hide_time_out)
|
|||
|
if is_open:
|
|||
|
rag=0
|
|||
|
else:
|
|||
|
rag=1
|
|||
|
if button_tscn!=null:
|
|||
|
var new_btn=button_tscn.instantiate()
|
|||
|
if new_btn is BaseButton:
|
|||
|
side_button=new_btn
|
|||
|
add_child(new_btn,false,Node.INTERNAL_MODE_FRONT)
|
|||
|
else:
|
|||
|
new_btn=Button.new()
|
|||
|
side_button=new_btn
|
|||
|
add_child(new_btn,false,Node.INTERNAL_MODE_FRONT)
|
|||
|
else:
|
|||
|
var new_btn=Button.new()
|
|||
|
side_button=new_btn
|
|||
|
add_child(new_btn,false,Node.INTERNAL_MODE_FRONT)
|
|||
|
side_button.pressed.connect(change_open)
|
|||
|
side_button.minimum_size_changed.connect(side_button_size_changed)
|
|||
|
side_button_size_changed()
|
|||
|
if disable_button:
|
|||
|
side_button.hide()
|
|||
|
resized.connect(resize)
|
|||
|
resize()
|
|||
|
_re_ready()
|
|||
|
pass # Replace with function body.
|
|||
|
##因为占用了ready函数,所以留了一个新的虚函数给使用节点重写
|
|||
|
func _re_ready()->void:
|
|||
|
|
|||
|
|
|||
|
|
|||
|
pass
|
|||
|
##对侧边栏按钮进行适配
|
|||
|
func fit_side_button()->void:
|
|||
|
var rect:Rect2
|
|||
|
if side_button!=null:
|
|||
|
match button_model:
|
|||
|
BUTTON_MODEL.TOP:
|
|||
|
rect=Rect2(0,(size.y-button_size.y)*rag,size.x,button_size.y)
|
|||
|
BUTTON_MODEL.END:
|
|||
|
rect=Rect2(0,(size.y-button_size.y)*(1-rag),size.x,button_size.y)
|
|||
|
BUTTON_MODEL.LEFT:
|
|||
|
rect=Rect2((size.x-button_size.x)*rag,0,button_size.x,size.y)
|
|||
|
BUTTON_MODEL.RIGHT:
|
|||
|
rect=Rect2((size.x-button_size.x)*(1-rag),0,button_size.x,size.y)
|
|||
|
|
|||
|
_:
|
|||
|
rect=Rect2()
|
|||
|
fit_child_in_rect(side_button,rect)
|
|||
|
##对子节点进行适配
|
|||
|
func fit_children()->void:
|
|||
|
var rect:Rect2
|
|||
|
if !disable_button:
|
|||
|
match button_model:
|
|||
|
BUTTON_MODEL.TOP:
|
|||
|
rect=Rect2(0,(size.y-button_size.y)*rag+button_size.y,size.x,size.y-button_size.y)
|
|||
|
BUTTON_MODEL.END:
|
|||
|
rect=Rect2(0,(size.y-button_size.y)*(-rag),size.x,size.y-button_size.y)
|
|||
|
BUTTON_MODEL.LEFT:
|
|||
|
rect=Rect2((size.x-button_size.x)*rag+button_size.x,0,size.x-button_size.x,size.y)
|
|||
|
BUTTON_MODEL.RIGHT:
|
|||
|
rect=Rect2((size.x-button_size.x)*(-rag),0,size.x-button_size.x,size.y)
|
|||
|
_:
|
|||
|
rect=Rect2()
|
|||
|
else:
|
|||
|
match button_model:
|
|||
|
BUTTON_MODEL.TOP:
|
|||
|
rect=Rect2(0,(size.y)*rag+button_size.y,size.x,size.y)
|
|||
|
BUTTON_MODEL.END:
|
|||
|
rect=Rect2(0,(size.y)*(-rag),size.x,size.y)
|
|||
|
BUTTON_MODEL.LEFT:
|
|||
|
rect=Rect2((size.x)*rag,0,size.x,size.y)
|
|||
|
BUTTON_MODEL.RIGHT:
|
|||
|
rect=Rect2((size.x)*(-rag),0,size.x,size.y)
|
|||
|
_:
|
|||
|
rect=Rect2()
|
|||
|
|
|||
|
|
|||
|
pass
|
|||
|
for i in get_children():
|
|||
|
if i is Control:
|
|||
|
fit_child_in_rect(i,rect)
|
|||
|
|
|||
|
##更改窗口的开闭状态,使用动画
|
|||
|
func change_open(opened:bool=false):
|
|||
|
if opened==is_open:
|
|||
|
return
|
|||
|
if now_keep_tween!=null:
|
|||
|
now_keep_tween.kill()
|
|||
|
if !opened:
|
|||
|
if is_auto_hide:
|
|||
|
hide_timer.start(animation_time)
|
|||
|
pass
|
|||
|
now_keep_tween=create_tween()
|
|||
|
now_keep_tween.set_trans(animation_model)
|
|||
|
now_keep_tween.tween_property(self,"rag",1,animation_time)
|
|||
|
else:
|
|||
|
now_keep_tween=create_tween()
|
|||
|
now_keep_tween.set_trans(animation_model)
|
|||
|
now_keep_tween.tween_property(self,"rag",0,animation_time)
|
|||
|
if is_auto_hide:
|
|||
|
show()
|
|||
|
hide_timer.stop()
|
|||
|
is_open=opened
|
|||
|
|
|||
|
|
|||
|
|
|||
|
pass
|
|||
|
##当此节点大小改变时触发
|
|||
|
func resize():
|
|||
|
fit_side_button()
|
|||
|
fit_children()
|
|||
|
##重写的虚函数,用于获取当前节点的最小大小
|
|||
|
func _get_minimum_size() -> Vector2:
|
|||
|
var res:Vector2=Vector2.ZERO
|
|||
|
|
|||
|
for i in get_children():
|
|||
|
if i is Control:
|
|||
|
var i_size:Vector2=i.get_minimum_size()
|
|||
|
res=Vector2(max(res.x,i_size.x),max(res.y,i_size.y))
|
|||
|
if not is_auto_shrink:
|
|||
|
if !disable_button:
|
|||
|
match button_model:
|
|||
|
BUTTON_MODEL.TOP:
|
|||
|
res=Vector2(max(res.x,button_size.x),res.y+button_size.y)
|
|||
|
BUTTON_MODEL.END:
|
|||
|
res=Vector2(max(res.x,button_size.x),res.y+button_size.y)
|
|||
|
BUTTON_MODEL.LEFT:
|
|||
|
res=Vector2(res.x+button_size.x,max(res.y,button_size.y))
|
|||
|
BUTTON_MODEL.RIGHT:
|
|||
|
res=Vector2(res.x+button_size.x,max(res.y,button_size.y))
|
|||
|
_:
|
|||
|
res=Vector2.ZERO
|
|||
|
else:
|
|||
|
if !disable_button:
|
|||
|
match button_model:
|
|||
|
BUTTON_MODEL.TOP:
|
|||
|
res=Vector2(max(res.x,button_size.x),res.y*rag+button_size.y)
|
|||
|
BUTTON_MODEL.END:
|
|||
|
res=Vector2(max(res.x,button_size.x),res.y*rag+button_size.y)
|
|||
|
BUTTON_MODEL.LEFT:
|
|||
|
res=Vector2(res.x*rag+button_size.x,max(res.y,button_size.y))
|
|||
|
BUTTON_MODEL.RIGHT:
|
|||
|
res=Vector2(res.x*rag+button_size.x,max(res.y,button_size.y))
|
|||
|
_:
|
|||
|
res=Vector2.ZERO
|
|||
|
else:
|
|||
|
match button_model:
|
|||
|
BUTTON_MODEL.TOP:
|
|||
|
res=Vector2(res.x,res.y*(1-rag))
|
|||
|
BUTTON_MODEL.END:
|
|||
|
res=Vector2(res.x*rag,res.y*(1-rag))
|
|||
|
BUTTON_MODEL.LEFT:
|
|||
|
res=Vector2(res.x*(1-rag),res.y)
|
|||
|
BUTTON_MODEL.RIGHT:
|
|||
|
res=Vector2(res.x*rag,res.y*(1-rag))
|
|||
|
_:
|
|||
|
res=Vector2.ZERO
|
|||
|
pass
|
|||
|
|
|||
|
return res
|
|||
|
##当侧边栏按钮大小更改时调用
|
|||
|
func side_button_size_changed()->void:
|
|||
|
if side_button:
|
|||
|
var new_size=side_button.get_minimum_size()
|
|||
|
button_size=Vector2(max(custom_button_size.x,new_size.x),max(custom_button_size.y,new_size.y))
|
|||
|
|
|||
|
func _process(delta: float) -> void:
|
|||
|
if Engine.is_editor_hint():
|
|||
|
fit_children()
|
|||
|
pass
|
|||
|
func hide_time_out():
|
|||
|
hide()
|