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