Files
tekton/scripts/ui/date_picker.gd
2026-05-11 17:24:47 +08:00

98 lines
3.1 KiB
GDScript

extends Button
signal date_selected(date_str: String)
@onready var popup = $PopupPanel
@onready var month_year_lbl = $PopupPanel/VBox/Header/MonthYearLbl
@onready var days_grid = $PopupPanel/VBox/DaysGrid
@onready var prev_btn = $PopupPanel/VBox/Header/PrevBtn
@onready var next_btn = $PopupPanel/VBox/Header/NextBtn
@onready var clear_btn = $PopupPanel/VBox/ClearBtn
var current_date: Dictionary
var view_date: Dictionary
const MONTHS = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
func _ready() -> void:
var now = Time.get_datetime_dict_from_system()
view_date = {"year": now.year, "month": now.month, "day": now.day}
pressed.connect(_on_button_pressed)
prev_btn.pressed.connect(_on_prev_month)
next_btn.pressed.connect(_on_next_month)
clear_btn.pressed.connect(_on_clear_pressed)
_update_calendar()
func _on_button_pressed() -> void:
_update_calendar()
popup.popup_centered()
func _on_prev_month() -> void:
view_date.month -= 1
if view_date.month < 1:
view_date.month = 12
view_date.year -= 1
_update_calendar()
func _on_next_month() -> void:
view_date.month += 1
if view_date.month > 12:
view_date.month = 1
view_date.year += 1
_update_calendar()
func _on_clear_pressed() -> void:
clear_date()
func clear_date() -> void:
current_date = {}
text = "Select Date..."
emit_signal("date_selected", "")
popup.hide()
func _update_calendar() -> void:
month_year_lbl.text = str(MONTHS[view_date.month - 1]) + " " + str(view_date.year)
for child in days_grid.get_children():
child.queue_free()
var first_day_dict = {"year": view_date.year, "month": view_date.month, "day": 1}
var first_day_unix = Time.get_unix_time_from_datetime_dict(first_day_dict)
var first_day_weekday = Time.get_datetime_dict_from_unix_time(first_day_unix).weekday
# Godot weekday: 0 = Sunday, 1 = Monday...
for i in range(first_day_weekday):
var empty = Control.new()
days_grid.add_child(empty)
var days_in_month = _get_days_in_month(view_date.month, view_date.year)
for d in range(1, days_in_month + 1):
var btn = Button.new()
btn.text = str(d)
btn.custom_minimum_size = Vector2(32, 32)
if not current_date.is_empty() and current_date.year == view_date.year and current_date.month == view_date.month and current_date.day == d:
btn.add_theme_color_override("font_color", Color.YELLOW)
btn.pressed.connect(_on_day_clicked.bind(d))
days_grid.add_child(btn)
func _on_day_clicked(day: int) -> void:
current_date = {"year": view_date.year, "month": view_date.month, "day": day}
var date_str = "%04d-%02d-%02dT00:00:00Z" % [current_date.year, current_date.month, current_date.day]
text = "%04d-%02d-%02d" % [current_date.year, current_date.month, current_date.day]
emit_signal("date_selected", date_str)
popup.hide()
func get_date_iso() -> String:
if current_date.is_empty():
return ""
return "%04d-%02d-%02dT00:00:00Z" % [current_date.year, current_date.month, current_date.day]
func _get_days_in_month(month: int, year: int) -> int:
if month in [1, 3, 5, 7, 8, 10, 12]: return 31
if month in [4, 6, 9, 11]: return 30
if year % 4 == 0 and (year % 100 != 0 or year % 400 == 0): return 29
return 28