input (date)

This commit is contained in:
Face
2025-07-25 13:43:11 +03:00
parent c1e442bb83
commit 465200cd28
40 changed files with 1554 additions and 67 deletions

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#ffffff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-arrow-down-icon lucide-arrow-down"><path d="M12 5v14"/><path d="m19 12-7 7-7-7"/></svg>

After

Width:  |  Height:  |  Size: 284 B

View File

@@ -0,0 +1,37 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://c1bqnfwurnnrc"
path="res://.godot/imported/arrow-down.svg-1e5275b4ffe06ccf19d892794fc84c5b.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://Assets/Icons/arrow-down.svg"
dest_files=["res://.godot/imported/arrow-down.svg-1e5275b4ffe06ccf19d892794fc84c5b.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
svg/scale=1.0
editor/scale_with_editor_scale=false
editor/convert_colors_with_editor_theme=false

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#ffffff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-arrow-up-icon lucide-arrow-up"><path d="m5 12 7-7 7 7"/><path d="M12 19V5"/></svg>

After

Width:  |  Height:  |  Size: 279 B

View File

@@ -0,0 +1,37 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://d1jslyy8aajcn"
path="res://.godot/imported/arrow-up.svg-e673f59c1623de68e856c93a57be6cb0.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://Assets/Icons/arrow-up.svg"
dest_files=["res://.godot/imported/arrow-up.svg-e673f59c1623de68e856c93a57be6cb0.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
svg/scale=1.0
editor/scale_with_editor_scale=false
editor/convert_colors_with_editor_theme=false

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#ffffff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-calendar-icon lucide-calendar"><path d="M8 2v4"/><path d="M16 2v4"/><rect width="18" height="18" x="3" y="4" rx="2"/><path d="M3 10h18"/></svg>

After

Width:  |  Height:  |  Size: 340 B

View File

@@ -0,0 +1,37 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://da721lhb4r0so"
path="res://.godot/imported/calendar.svg-4a7aa93bfd00cdce85eae886ac3d4d51.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://Assets/Icons/calendar.svg"
dest_files=["res://.godot/imported/calendar.svg-4a7aa93bfd00cdce85eae886ac3d4d51.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
svg/scale=1.0
editor/scale_with_editor_scale=false
editor/convert_colors_with_editor_theme=false

View File

@@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#ffffff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-calendar-icon lucide-calendar"><path d="M8 2v4"/><path d="M16 2v4"/><rect width="18" height="18" x="3" y="4" rx="2"/><path d="M3 10h18"/></svg>

After

Width:  |  Height:  |  Size: 379 B

View File

@@ -0,0 +1,37 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://mol3s1ujp0k2"
path="res://.godot/imported/calendar_16x16.svg-38c497b40cde0596f1f838e0a52171d2.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://Assets/Icons/calendar_16x16.svg"
dest_files=["res://.godot/imported/calendar_16x16.svg-38c497b40cde0596f1f838e0a52171d2.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
svg/scale=1.0
editor/scale_with_editor_scale=false
editor/convert_colors_with_editor_theme=false

View File

@@ -9,10 +9,11 @@ TODO:
8. **More input types** (url, tel, date, time, etc.)
9. **Required** attribute for inputs
10. Installer should register **gurt://** as a valid protocol thru the registry.
11. < input type=**datetime** />, essentially a type "date" but with a vertical separator, then `mm | ss | FORMAT` layout for time.
Issues:
1. **< br />** counts as 1 element in **WebsiteContainer**, therefore despite being (0,0) in size, it counts as double in spacing
Notes:
- **<input />** is sort-of inline in normal web. We render it as a block element (new-line).
- **< input />** is sort-of inline in normal web. We render it as a block element (new-line).
- A single `RichTextLabel` for inline text tags should stop, we should use invididual ones so it's easier to style and achieve separation through a `vboxcontainer`.

View File

@@ -20,8 +20,8 @@
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_c32on"]
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_7g0pl"]
bg_color = Color(0.168627, 0.168627, 0.168627, 1)
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_0v877"]
bg_color = Color(0.105882, 0.105882, 0.105882, 1)
corner_radius_top_left = 4
corner_radius_top_right = 4
corner_radius_bottom_right = 4
@@ -142,7 +142,7 @@ corner_radius_bottom_left = 4
[resource]
Button/styles/focus = SubResource("StyleBoxEmpty_c32on")
Button/styles/hover = SubResource("StyleBoxFlat_7g0pl")
Button/styles/hover = SubResource("StyleBoxFlat_0v877")
Button/styles/normal = SubResource("StyleBoxFlat_c32on")
CheckBox/constants/icon_max_width = 24
CheckBox/icons/checked = ExtResource("2_3k2jb")

View File

@@ -91,7 +91,7 @@ _data = {
}
[node name="Tab1" type="Control"]
custom_minimum_size = Vector2(350, 50)
custom_minimum_size = Vector2(0, 50)
layout_mode = 3
anchors_preset = 0
offset_right = 350.0
@@ -103,7 +103,7 @@ unique_name_in_owner = true
z_index = -2
clip_contents = true
layout_mode = 1
offset_right = 350.0
offset_right = 47.0
offset_bottom = 50.0
focus_mode = 0
mouse_default_cursor_shape = 2
@@ -124,9 +124,8 @@ text_overrun_behavior = 3
unique_name_in_owner = true
z_index = 1
layout_mode = 0
offset_left = 278.0
offset_left = -64.0
offset_top = 2.0
offset_right = 342.0
offset_bottom = 50.0
texture = ExtResource("3_q3baj")
@@ -134,9 +133,8 @@ texture = ExtResource("3_q3baj")
unique_name_in_owner = true
custom_minimum_size = Vector2(23, 23)
layout_mode = 0
offset_left = 8.0
offset_left = -23.0
offset_top = 13.0
offset_right = 31.0
offset_bottom = 36.0
texture = ExtResource("6_ib6pj")
expand_mode = 1
@@ -146,9 +144,8 @@ unique_name_in_owner = true
z_index = 2
custom_minimum_size = Vector2(34, 34)
layout_mode = 0
offset_left = 319.0
offset_left = -34.0
offset_top = 12.0
offset_right = 353.0
offset_bottom = 46.0
scale = Vector2(0.75, 0.75)
focus_mode = 0

View File

@@ -1,7 +1,8 @@
[gd_scene load_steps=4 format=3 uid="uid://c7yay102a3b4c"]
[gd_scene load_steps=5 format=3 uid="uid://c7yay102a3b4c"]
[ext_resource type="Script" uid="uid://kv6ebscarj2e" path="res://Scripts/Tags/input.gd" id="1_input"]
[ext_resource type="Theme" uid="uid://bn6rbmdy60lhr" path="res://Scenes/Styles/BrowserText.tres" id="2_theme"]
[ext_resource type="PackedScene" uid="uid://b6c1twaog7hui" path="res://addons/DatePicker/DateButton.tscn" id="3_a88g6"]
[sub_resource type="ButtonGroup" id="ButtonGroup_06us3"]
@@ -21,6 +22,7 @@ size_flags_vertical = 0
script = ExtResource("1_input")
[node name="LineEdit" type="LineEdit" parent="."]
visible = false
layout_mode = 1
offset_right = 400.0
offset_bottom = 35.0
@@ -48,9 +50,13 @@ button_group = SubResource("ButtonGroup_06us3")
flat = true
[node name="ColorPickerButton" type="ColorPickerButton" parent="."]
visible = false
layout_mode = 0
offset_right = 83.0
offset_bottom = 35.0
toggle_mode = false
[node name="DateButton" parent="." instance=ExtResource("3_a88g6")]
layout_mode = 0
[connection signal="popup_closed" from="ColorPickerButton" to="." method="_on_color_picker_popup_closed"]

View File

@@ -88,6 +88,9 @@ func _exit_tree():
loading_tween = null
remove_from_group("tabs")
func _enter_tree() -> void:
$AnimationPlayer.play("appear")
func _on_button_pressed() -> void:
# Check if click was on close button area
var mouse_pos = get_global_mouse_position()

View File

@@ -81,7 +81,6 @@ func create_tab() -> void:
tab.tab_closed.connect(_tab_closed.bind(index))
h_box_container.add_child(tab)
tab.animation.play("appear")
set_active_tab(index)

View File

@@ -6,9 +6,6 @@ const BROWSER_TEXT: Theme = preload("res://Scenes/Styles/BrowserText.tres")
var custom_hex_input: LineEdit
func init(element: HTMLParser.HTMLElement) -> void:
var line_edit: LineEdit = $LineEdit
var check_box: CheckBox = $CheckBox
var radio_button: CheckBox = $RadioButton
var color_picker_button: ColorPickerButton = $ColorPickerButton
var picker: ColorPicker = color_picker_button.get_picker()
@@ -54,55 +51,66 @@ func init(element: HTMLParser.HTMLElement) -> void:
var maxlength = element.get_attribute("maxlength")
var pattern = element.get_attribute("pattern")
if input_type == "checkbox":
if is_instance_valid(line_edit): line_edit.queue_free()
if is_instance_valid(radio_button): radio_button.queue_free()
if is_instance_valid(color_picker_button): color_picker_button.queue_free()
check_box.visible = true
if value and value == "true": check_box.button_pressed = true
custom_minimum_size = check_box.size
# Define which child should be active for each input type
var active_child_map = {
"checkbox": "CheckBox",
"radio": "RadioButton",
"color": "ColorPickerButton",
"password": "LineEdit",
"date": "DateButton"
}
var active_child_name = active_child_map.get(input_type, "LineEdit")
remove_unused_children(active_child_name)
var active_child = get_node(active_child_name)
active_child.visible = true
custom_minimum_size = active_child.size
elif input_type == "radio":
if is_instance_valid(line_edit): line_edit.queue_free()
if is_instance_valid(check_box): check_box.queue_free()
if is_instance_valid(color_picker_button): color_picker_button.queue_free()
radio_button.visible = true
radio_button.toggle_mode = true
if value and value == "true": radio_button.button_pressed = true
custom_minimum_size = radio_button.size
match input_type:
"checkbox":
var checkbox = active_child as CheckBox
if value and value == "true":
checkbox.button_pressed = true
"radio":
var radio = active_child as CheckBox
radio.toggle_mode = true
if value and value == "true":
radio.button_pressed = true
if group.length() > 0:
if not button_groups.has(group):
button_groups[group] = ButtonGroup.new()
radio.button_group = button_groups[group]
"color":
var color_button = active_child as ColorPickerButton
if value and value.length() > 0:
var color = Color.from_string(value, Color.WHITE)
color_button.color = color
"password":
var line_edit = active_child as LineEdit
line_edit.secret = true
setup_text_input(line_edit, placeholder, value, minlength, maxlength, pattern)
"date":
var date_button = active_child as DateButton
if value and value.length() > 0:
date_button.init_with_date(value)
else:
date_button.init()
_: # Default case (text input)
var line_edit = active_child as LineEdit
line_edit.secret = false
setup_text_input(line_edit, placeholder, value, minlength, maxlength, pattern)
if group.length() > 0:
if not button_groups.has(group):
button_groups[group] = ButtonGroup.new()
radio_button.button_group = button_groups[group]
elif input_type == "color":
if is_instance_valid(line_edit): line_edit.queue_free()
if is_instance_valid(check_box): check_box.queue_free()
if is_instance_valid(radio_button): radio_button.queue_free()
color_picker_button.visible = true
if value and value.length() > 0:
var color = Color.from_string(value, Color.WHITE)
color_picker_button.color = color
custom_minimum_size = color_picker_button.size
elif input_type == "password":
if is_instance_valid(check_box): check_box.queue_free()
if is_instance_valid(radio_button): radio_button.queue_free()
if is_instance_valid(color_picker_button): color_picker_button.queue_free()
line_edit.visible = true
line_edit.secret = true
custom_minimum_size = line_edit.size
setup_text_input(line_edit, placeholder, value, minlength, maxlength, pattern)
else:
if is_instance_valid(check_box): check_box.queue_free()
if is_instance_valid(radio_button): radio_button.queue_free()
if is_instance_valid(color_picker_button): color_picker_button.queue_free()
line_edit.visible = true
line_edit.secret = false
custom_minimum_size = line_edit.size
setup_text_input(line_edit, placeholder, value, minlength, maxlength, pattern)
func remove_unused_children(keep_child_name: String) -> void:
for child in get_children():
if child.name != keep_child_name:
child.queue_free()
func setup_text_input(line_edit: LineEdit, placeholder: String, value: String, minlength: String, maxlength: String, pattern: String) -> void:
if placeholder: line_edit.placeholder_text = placeholder

View File

@@ -92,6 +92,8 @@ line breaks
<h2>Color</h2>
<input type=\"color\" value=\"#ff0000\" />
<h2>Date</h2>
<input type=\"date\" value=\"2018-07-22\" />
<input type=\"password\" placeholder=\"your password...\" />
<button type=\"submit\">Submit</button>
@@ -104,7 +106,6 @@ line breaks
<separator direction=\"vertical\" />
</body>".to_utf8_buffer()
# Create parser and parse
var parser: HTMLParser = HTMLParser.new(html_bytes)
var parse_result = parser.parse()
@@ -113,7 +114,6 @@ line breaks
if parse_result.errors.size() > 0:
print("Parse errors: " + str(parse_result.errors))
# TODO: render the shit on the screen
var tab = tab_container.tabs[tab_container.active_tab]
var title = parser.get_title()

View File

@@ -0,0 +1 @@
uid://c134lf0pxabrf

View File

@@ -0,0 +1,95 @@
class_name Calendar
extends PopupPanel
@export var header: Button
@export var next: BaseButton
@export var previous: BaseButton
@export var view_parent: Control
@export var month_view: MonthView
@export var year_view: YearView
var margin: float = 16.0
var view: Node:
get:
return view_parent.get_child(0) if view_parent.get_child_count() > 0 else null
var _date_time: Dictionary = Time.get_datetime_dict_from_system()
## The date that the calendar is currently displaying.
var date_time: Dictionary:
get:
return _date_time
set(value):
_date_time = value
date_changed.emit()
var _selected: Dictionary = Time.get_datetime_dict_from_system()
## The date that the user has selected.
var selected: Dictionary:
get:
return _selected
set(value):
_selected = value
date_selected.emit()
## The earliest date that can be selected.
var lower_limit: Dictionary
## The latest date that can be selected.
var upper_limit: Dictionary
## The button that displays this calendar - can be null.
var calendar_button: Button
## The signal emitted when the view changes.
signal view_changed(view: Control)
## The signal emitted when the date changes.
signal date_changed()
## The signal emitted when the user selects a date in ANY view.
signal date_selected()
## The signal emitted when the user is finished selecting a date.
signal finished()
func init():
header.text = "%s %s" % [MonthView.num_to_month(date_time.month), date_time.year]
header.pressed.connect(_on_header_pressed)
previous.pressed.connect(func(): if view: view.previous())
next.pressed.connect(func(): if view: view.next())
year_view.init()
func _enter_tree():
get_tree().root.gui_focus_changed.connect(_on_gui_focus_changed)
func _exit_tree():
if get_tree() and get_tree().root:
get_tree().root.gui_focus_changed.disconnect(_on_gui_focus_changed)
func _on_header_pressed():
var is_default = month_view.visible
if is_default:
month_view.hide()
year_view.show()
else:
month_view.show()
year_view.hide()
func _on_gui_focus_changed(focus: Control):
if focus and not is_ancestor_of(focus) and not focus is DateButton:
visible = false
func set_view(new_view: Node):
if view:
view.queue_free()
new_view.calendar = self
view_parent.add_child(new_view)
view_changed.emit(new_view)
func _gui_input(event: InputEvent):
if event is InputEventMouseButton:
var mb = event as InputEventMouseButton
if mb.pressed:
if mb.button_index == MOUSE_BUTTON_WHEEL_DOWN and view:
view.next()
elif mb.button_index == MOUSE_BUTTON_WHEEL_UP and view:
view.previous()

View File

@@ -0,0 +1 @@
uid://bh27iqijrabku

View File

@@ -0,0 +1,88 @@
[gd_scene load_steps=14 format=3 uid="uid://dgn7djiy1xhlu"]
[ext_resource type="Theme" uid="uid://bn6rbmdy60lhr" path="res://Scenes/Styles/BrowserText.tres" id="1_1ddb1"]
[ext_resource type="Script" uid="uid://bh27iqijrabku" path="res://addons/DatePicker/Calendar.gd" id="1_heut6"]
[ext_resource type="Texture2D" uid="uid://d1jslyy8aajcn" path="res://Assets/Icons/arrow-up.svg" id="3_1ddb1"]
[ext_resource type="Texture2D" uid="uid://df1m4j7uxi63v" path="res://Assets/Icons/chevron-down.svg" id="3_rjgii"]
[ext_resource type="Texture2D" uid="uid://c1bqnfwurnnrc" path="res://Assets/Icons/arrow-down.svg" id="4_rjgii"]
[ext_resource type="PackedScene" uid="uid://n5ra5w5aupx7" path="res://addons/DatePicker/YearView.tscn" id="5_qmkbm"]
[ext_resource type="PackedScene" uid="uid://hiv2ckjbs43p" path="res://addons/DatePicker/MonthView.tscn" id="6_rjgii"]
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_w2pln"]
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_s0l8g"]
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_mavvk"]
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_j0d5i"]
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_1e668"]
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_5m4sc"]
[node name="Calendar" type="PopupPanel" node_paths=PackedStringArray("header", "next", "previous", "view_parent", "month_view", "year_view")]
size = Vector2i(263, 308)
visible = true
theme = ExtResource("1_1ddb1")
script = ExtResource("1_heut6")
header = NodePath("VboxContainer/HeaderContainer/HeaderButton")
next = NodePath("VboxContainer/HeaderContainer/Next")
previous = NodePath("VboxContainer/HeaderContainer/Previous")
view_parent = NodePath("VboxContainer/View")
month_view = NodePath("VboxContainer/View/MonthView")
year_view = NodePath("VboxContainer/View/YearView")
[node name="VboxContainer" type="VBoxContainer" parent="."]
offset_left = 15.0
offset_top = 15.0
offset_right = 248.0
offset_bottom = 293.0
theme_override_constants/separation = 12
[node name="HeaderContainer" type="HBoxContainer" parent="VboxContainer"]
layout_mode = 2
[node name="HeaderButton" type="Button" parent="VboxContainer/HeaderContainer"]
layout_mode = 2
size_flags_horizontal = 0
mouse_default_cursor_shape = 2
theme_override_styles/focus = SubResource("StyleBoxEmpty_w2pln")
theme_override_styles/pressed = SubResource("StyleBoxEmpty_s0l8g")
text = "July 1980"
icon = ExtResource("3_rjgii")
flat = true
alignment = 0
icon_alignment = 2
[node name="Spacer" type="Control" parent="VboxContainer/HeaderContainer"]
layout_mode = 2
size_flags_horizontal = 3
[node name="Previous" type="Button" parent="VboxContainer/HeaderContainer"]
layout_mode = 2
mouse_default_cursor_shape = 2
theme_override_styles/focus = SubResource("StyleBoxEmpty_mavvk")
theme_override_styles/pressed = SubResource("StyleBoxEmpty_j0d5i")
icon = ExtResource("3_1ddb1")
flat = true
[node name="Next" type="Button" parent="VboxContainer/HeaderContainer"]
layout_mode = 2
mouse_default_cursor_shape = 2
theme_override_styles/focus = SubResource("StyleBoxEmpty_1e668")
theme_override_styles/pressed = SubResource("StyleBoxEmpty_5m4sc")
icon = ExtResource("4_rjgii")
flat = true
[node name="View" type="Control" parent="VboxContainer"]
layout_mode = 2
size_flags_vertical = 3
[node name="MonthView" parent="VboxContainer/View" node_paths=PackedStringArray("calendar") instance=ExtResource("6_rjgii")]
layout_mode = 0
calendar = NodePath("../../..")
[node name="YearView" parent="VboxContainer/View" node_paths=PackedStringArray("calendar") instance=ExtResource("5_qmkbm")]
visible = false
layout_mode = 0
calendar = NodePath("../../..")

View File

@@ -0,0 +1,4 @@
[gd_resource type="ButtonGroup" format=3 uid="uid://bqxxq56yxl44h"]
[resource]
allow_unpress = true

View File

@@ -0,0 +1 @@
uid://ds2esqjkjc4h0

View File

@@ -0,0 +1,77 @@
class_name DateButton
extends Button
var calendar: Calendar
var calendar_control: Control
const CALENDAR = preload("res://addons/DatePicker/Calendar.tscn")
func init():
text = "mm/dd/yyyy"
_init_calendar()
func _init_calendar():
calendar = CALENDAR.instantiate()
add_child(calendar)
calendar.hide()
calendar.init()
pressed.connect(_on_button_pressed)
calendar.popup_hide.connect(func(): button_pressed = false)
calendar.finished.connect(_on_date_selected)
tree_exited.connect(func(): if is_instance_valid(calendar): calendar.queue_free())
func init_with_date(date_string: String) -> void:
_init_calendar()
var parsed_date = parse_date_string(date_string)
if parsed_date:
calendar.date_time = parsed_date
calendar.selected = parsed_date.duplicate()
update_button_text()
else:
text = "mm/dd/yyyy" # Set default text if parsing fails
func parse_date_string(date_string: String) -> Dictionary:
# Parse ISO date format (YYYY-MM-DD)
var parts = date_string.split("-")
if parts.size() != 3:
return {}
var year = parts[0].to_int()
var month = parts[1].to_int()
var day = parts[2].to_int()
# Validate date components
if year < 1 or month < 1 or month > 12 or day < 1 or day > 31:
return {}
return {
"year": year,
"month": month,
"day": day
}
func update_button_text() -> void:
var date = calendar.selected
text = "%d/%d/%d" % [date.month, date.day, date.year]
func _on_date_selected():
var date = calendar.selected
text = "%02d/%02d/%04d" % [date.month, date.day, date.year]
func _on_button_pressed():
if calendar.is_visible():
calendar.hide()
return
var viewport_height = get_viewport_rect().size.y
var show_above = false
if get_global_position().y + size.y + calendar.size.y > viewport_height and get_global_position().y * 2 + size.y > viewport_height:
show_above = true
var h_offset = (size.x - calendar.size.x) / 2
var v_offset = -calendar.size.y if show_above else size.y
calendar.position = get_screen_position() + Vector2(h_offset, v_offset)
calendar.popup()

View File

@@ -0,0 +1 @@
uid://do548vwv7m0rq

View File

@@ -0,0 +1,33 @@
[gd_scene load_steps=6 format=3 uid="uid://b6c1twaog7hui"]
[ext_resource type="Texture2D" uid="uid://mol3s1ujp0k2" path="res://Assets/Icons/calendar_16x16.svg" id="1_ef33s"]
[ext_resource type="Script" uid="uid://do548vwv7m0rq" path="res://addons/DatePicker/DateButton.gd" id="1_sskq5"]
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_ef33s"]
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_ufs0o"]
content_margin_left = 4.0
bg_color = Color(0.105882, 0.105882, 0.105882, 1)
corner_radius_top_left = 4
corner_radius_top_right = 4
corner_radius_bottom_right = 4
corner_radius_bottom_left = 4
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_pnupr"]
content_margin_left = 4.0
bg_color = Color(0.105882, 0.105882, 0.105882, 1)
corner_radius_top_left = 4
corner_radius_top_right = 4
corner_radius_bottom_right = 4
corner_radius_bottom_left = 4
[node name="DateButton" type="Button"]
offset_right = 115.0
offset_bottom = 34.0
theme_override_styles/focus = SubResource("StyleBoxEmpty_ef33s")
theme_override_styles/hover = SubResource("StyleBoxFlat_ufs0o")
theme_override_styles/normal = SubResource("StyleBoxFlat_pnupr")
action_mode = 0
text = "3/13/2025"
icon = ExtResource("1_ef33s")
script = ExtResource("1_sskq5")

View File

@@ -0,0 +1 @@
uid://crwtb840n4orl

View File

@@ -0,0 +1,19 @@
class_name ICalendarView
extends RefCounted
## A view that dictates how a calendar should be displayed (i.e. MonthView or YearView).
## The calendar that this view is a part of.
var calendar: Calendar
## When the user clicks the previous button (i.e. go to the previous year).
func previous():
pass
## When the user clicks the next button (i.e. go to the next year).
func next():
pass
## Update the view to reflect the selected date.
func refresh():
pass

View File

@@ -0,0 +1 @@
uid://lxw1ab33fva2

View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2024 Christopher Charbonneau
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -0,0 +1 @@
uid://bc88158gaxg4f

View File

@@ -0,0 +1,146 @@
class_name MonthView
extends VBoxContainer
@export var calendar: Calendar
var buttons: GridContainer
var dates: Array = []
var _updating: bool = false
func _ready():
buttons = $Days
for i in range(buttons.get_child_count()):
buttons.get_child(i).toggled.connect(_on_day_toggled.bind(i))
refresh()
func _on_day_toggled(toggled: bool, button_index: int):
if _updating or button_index >= dates.size() or not dates[button_index]:
return
var button = buttons.get_child(button_index)
if not toggled:
button.set_pressed_no_signal(true)
return
for i in range(buttons.get_child_count()):
if i != button_index:
buttons.get_child(i).set_pressed_no_signal(false)
calendar.selected = dates[button_index]
calendar.date_time = dates[button_index].duplicate()
calendar.hide()
calendar.finished.emit()
func previous():
var new_date = calendar.date_time.duplicate()
new_date.month -= 1
if new_date.month < 1:
new_date.month = 12
new_date.year -= 1
calendar.date_time = new_date
refresh()
func next():
var new_date = calendar.date_time.duplicate()
new_date.month += 1
if new_date.month > 12:
new_date.month = 1
new_date.year += 1
calendar.date_time = new_date
refresh()
func refresh():
_updating = true
calendar.header.text = "%s %s" % [num_to_month(calendar.date_time.month), calendar.date_time.year]
dates.clear()
dates.resize(buttons.get_child_count())
for i in range(buttons.get_child_count()):
var button = buttons.get_child(i)
button.text = ""
button.set_pressed_no_signal(false)
dates[i] = null
var first_day = calendar.date_time.duplicate()
first_day.day = 1
var start_day = Time.get_datetime_dict_from_unix_time(
Time.get_unix_time_from_datetime_dict(first_day)
).weekday % 7
var days_in_month = get_days_in_month(calendar.date_time.year, calendar.date_time.month)
var prev_month_num = calendar.date_time.month - 1
var prev_year = calendar.date_time.year
if prev_month_num < 1:
prev_month_num = 12
prev_year -= 1
var prev_days = get_days_in_month(prev_year, prev_month_num)
var gray_color = Color(0.51, 0.54, 0.596)
var dark_color = Color(0.133, 0.137, 0.137)
# Fill previous month days
for i in range(start_day):
var day = prev_days - start_day + i + 1
var button = buttons.get_child(i)
dates[i] = {"year": prev_year, "month": prev_month_num, "day": day}
button.text = str(day)
button.add_theme_color_override("font_color", gray_color)
button.add_theme_color_override("font_hover_color", gray_color)
button.set_pressed_no_signal(
day == calendar.selected.day and
calendar.selected.year == prev_year and
calendar.selected.month == prev_month_num
)
# Fill current month days
for i in range(days_in_month):
var button = buttons.get_child(i + start_day)
dates[i + start_day] = {"year": calendar.date_time.year, "month": calendar.date_time.month, "day": i + 1}
button.text = str(i + 1)
button.add_theme_color_override("font_color", dark_color)
button.add_theme_color_override("font_hover_color", dark_color)
button.set_pressed_no_signal(
i + 1 == calendar.selected.day and
calendar.selected.year == calendar.date_time.year and
calendar.selected.month == calendar.date_time.month
)
var next_month_num = calendar.date_time.month + 1
var next_year = calendar.date_time.year
if next_month_num > 12:
next_month_num = 1
next_year += 1
# Fill next month days
for i in range(days_in_month + start_day, buttons.get_child_count()):
var day = i + 1 - days_in_month - start_day
var button = buttons.get_child(i)
dates[i] = {"year": next_year, "month": next_month_num, "day": day}
button.text = str(day)
button.add_theme_color_override("font_color", gray_color)
button.add_theme_color_override("font_hover_color", gray_color)
button.set_pressed_no_signal(
day == calendar.selected.day and
calendar.selected.year == next_year and
calendar.selected.month == next_month_num
)
_updating = false
func get_days_in_month(year: int, month: int) -> int:
var thirty_one = [1, 3, 5, 7, 8, 10, 12]
var thirty = [4, 6, 9, 11]
if month in thirty_one:
return 31
elif month in thirty:
return 30
elif month == 2:
return 29 if (year % 4 == 0 and year % 100 != 0) or (year % 400 == 0) else 28
else:
return 0
static func num_to_month(month: int) -> String:
var months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
return months[month - 1]

View File

@@ -0,0 +1 @@
uid://drxqmka0n1ntw

View File

@@ -0,0 +1,642 @@
[gd_scene load_steps=7 format=3 uid="uid://hiv2ckjbs43p"]
[ext_resource type="Script" uid="uid://drxqmka0n1ntw" path="res://addons/DatePicker/MonthView.gd" id="1_iouni"]
[ext_resource type="ButtonGroup" uid="uid://bqxxq56yxl44h" path="res://addons/DatePicker/CalendarGroup.tres" id="2_nfkp2"]
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_5l1mp"]
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_5l1mp"]
bg_color = Color(0.613675, 0.748845, 0.957838, 1)
corner_radius_top_left = 4
corner_radius_top_right = 4
corner_radius_bottom_right = 4
corner_radius_bottom_left = 4
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_pressed"]
bg_color = Color(0.247059, 0.466667, 0.807843, 1)
corner_radius_top_left = 4
corner_radius_top_right = 4
corner_radius_bottom_right = 4
corner_radius_bottom_left = 4
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_ochoi"]
bg_color = Color(1, 1, 1, 1)
corner_radius_top_left = 4
corner_radius_top_right = 4
corner_radius_bottom_right = 4
corner_radius_bottom_left = 4
[node name="MonthView" type="VBoxContainer"]
offset_right = 234.0
offset_bottom = 240.0
script = ExtResource("1_iouni")
[node name="DayOfWeek" type="GridContainer" parent="."]
layout_mode = 2
columns = 7
[node name="Sunday" type="Label" parent="DayOfWeek"]
custom_minimum_size = Vector2(0, 36)
layout_mode = 2
size_flags_horizontal = 3
text = "Su"
horizontal_alignment = 1
vertical_alignment = 1
[node name="Monday" type="Label" parent="DayOfWeek"]
custom_minimum_size = Vector2(0, 36)
layout_mode = 2
size_flags_horizontal = 3
text = "Mo"
horizontal_alignment = 1
vertical_alignment = 1
[node name="Tuesday" type="Label" parent="DayOfWeek"]
custom_minimum_size = Vector2(0, 36)
layout_mode = 2
size_flags_horizontal = 3
text = "Tu"
horizontal_alignment = 1
vertical_alignment = 1
[node name="Wednesday" type="Label" parent="DayOfWeek"]
custom_minimum_size = Vector2(0, 36)
layout_mode = 2
size_flags_horizontal = 3
text = "We"
horizontal_alignment = 1
vertical_alignment = 1
[node name="Thursday" type="Label" parent="DayOfWeek"]
custom_minimum_size = Vector2(0, 36)
layout_mode = 2
size_flags_horizontal = 3
text = "Th"
horizontal_alignment = 1
vertical_alignment = 1
[node name="Friday" type="Label" parent="DayOfWeek"]
custom_minimum_size = Vector2(0, 36)
layout_mode = 2
size_flags_horizontal = 3
text = "Fr"
horizontal_alignment = 1
vertical_alignment = 1
[node name="Saturday" type="Label" parent="DayOfWeek"]
custom_minimum_size = Vector2(0, 36)
layout_mode = 2
size_flags_horizontal = 3
text = "Sa"
horizontal_alignment = 1
vertical_alignment = 1
[node name="Days" type="GridContainer" parent="."]
layout_mode = 2
columns = 7
[node name="Button0" type="Button" parent="Days"]
custom_minimum_size = Vector2(30, 30)
layout_mode = 2
mouse_default_cursor_shape = 2
theme_override_colors/font_color = Color(0, 0, 0, 1)
theme_override_colors/font_pressed_color = Color(1, 1, 1, 1)
theme_override_styles/focus = SubResource("StyleBoxEmpty_5l1mp")
theme_override_styles/hover = SubResource("StyleBoxFlat_5l1mp")
theme_override_styles/pressed = SubResource("StyleBoxFlat_pressed")
theme_override_styles/normal = SubResource("StyleBoxFlat_ochoi")
toggle_mode = true
button_group = ExtResource("2_nfkp2")
[node name="Button1" type="Button" parent="Days"]
custom_minimum_size = Vector2(30, 30)
layout_mode = 2
mouse_default_cursor_shape = 2
theme_override_colors/font_color = Color(0, 0, 0, 1)
theme_override_colors/font_pressed_color = Color(1, 1, 1, 1)
theme_override_styles/focus = SubResource("StyleBoxEmpty_5l1mp")
theme_override_styles/hover = SubResource("StyleBoxFlat_5l1mp")
theme_override_styles/pressed = SubResource("StyleBoxFlat_pressed")
theme_override_styles/normal = SubResource("StyleBoxFlat_ochoi")
toggle_mode = true
button_group = ExtResource("2_nfkp2")
[node name="Button2" type="Button" parent="Days"]
custom_minimum_size = Vector2(30, 30)
layout_mode = 2
mouse_default_cursor_shape = 2
theme_override_colors/font_color = Color(0, 0, 0, 1)
theme_override_colors/font_pressed_color = Color(1, 1, 1, 1)
theme_override_styles/focus = SubResource("StyleBoxEmpty_5l1mp")
theme_override_styles/hover = SubResource("StyleBoxFlat_5l1mp")
theme_override_styles/pressed = SubResource("StyleBoxFlat_pressed")
theme_override_styles/normal = SubResource("StyleBoxFlat_ochoi")
toggle_mode = true
button_group = ExtResource("2_nfkp2")
[node name="Button3" type="Button" parent="Days"]
custom_minimum_size = Vector2(30, 30)
layout_mode = 2
mouse_default_cursor_shape = 2
theme_override_colors/font_color = Color(0, 0, 0, 1)
theme_override_colors/font_pressed_color = Color(1, 1, 1, 1)
theme_override_styles/focus = SubResource("StyleBoxEmpty_5l1mp")
theme_override_styles/hover = SubResource("StyleBoxFlat_5l1mp")
theme_override_styles/pressed = SubResource("StyleBoxFlat_pressed")
theme_override_styles/normal = SubResource("StyleBoxFlat_ochoi")
toggle_mode = true
button_group = ExtResource("2_nfkp2")
[node name="Button4" type="Button" parent="Days"]
custom_minimum_size = Vector2(30, 30)
layout_mode = 2
mouse_default_cursor_shape = 2
theme_override_colors/font_color = Color(0, 0, 0, 1)
theme_override_colors/font_pressed_color = Color(1, 1, 1, 1)
theme_override_styles/focus = SubResource("StyleBoxEmpty_5l1mp")
theme_override_styles/hover = SubResource("StyleBoxFlat_5l1mp")
theme_override_styles/pressed = SubResource("StyleBoxFlat_pressed")
theme_override_styles/normal = SubResource("StyleBoxFlat_ochoi")
toggle_mode = true
button_group = ExtResource("2_nfkp2")
[node name="Button5" type="Button" parent="Days"]
custom_minimum_size = Vector2(30, 30)
layout_mode = 2
mouse_default_cursor_shape = 2
theme_override_colors/font_color = Color(0, 0, 0, 1)
theme_override_colors/font_pressed_color = Color(1, 1, 1, 1)
theme_override_styles/focus = SubResource("StyleBoxEmpty_5l1mp")
theme_override_styles/hover = SubResource("StyleBoxFlat_5l1mp")
theme_override_styles/pressed = SubResource("StyleBoxFlat_pressed")
theme_override_styles/normal = SubResource("StyleBoxFlat_ochoi")
toggle_mode = true
button_group = ExtResource("2_nfkp2")
[node name="Button6" type="Button" parent="Days"]
custom_minimum_size = Vector2(30, 30)
layout_mode = 2
mouse_default_cursor_shape = 2
theme_override_colors/font_color = Color(0, 0, 0, 1)
theme_override_colors/font_pressed_color = Color(1, 1, 1, 1)
theme_override_styles/focus = SubResource("StyleBoxEmpty_5l1mp")
theme_override_styles/hover = SubResource("StyleBoxFlat_5l1mp")
theme_override_styles/pressed = SubResource("StyleBoxFlat_pressed")
theme_override_styles/normal = SubResource("StyleBoxFlat_ochoi")
toggle_mode = true
button_group = ExtResource("2_nfkp2")
[node name="Button7" type="Button" parent="Days"]
custom_minimum_size = Vector2(30, 30)
layout_mode = 2
mouse_default_cursor_shape = 2
theme_override_colors/font_color = Color(0, 0, 0, 1)
theme_override_colors/font_pressed_color = Color(1, 1, 1, 1)
theme_override_styles/focus = SubResource("StyleBoxEmpty_5l1mp")
theme_override_styles/hover = SubResource("StyleBoxFlat_5l1mp")
theme_override_styles/pressed = SubResource("StyleBoxFlat_pressed")
theme_override_styles/normal = SubResource("StyleBoxFlat_ochoi")
toggle_mode = true
button_group = ExtResource("2_nfkp2")
[node name="Button8" type="Button" parent="Days"]
custom_minimum_size = Vector2(30, 30)
layout_mode = 2
mouse_default_cursor_shape = 2
theme_override_colors/font_color = Color(0, 0, 0, 1)
theme_override_colors/font_pressed_color = Color(1, 1, 1, 1)
theme_override_styles/focus = SubResource("StyleBoxEmpty_5l1mp")
theme_override_styles/hover = SubResource("StyleBoxFlat_5l1mp")
theme_override_styles/pressed = SubResource("StyleBoxFlat_pressed")
theme_override_styles/normal = SubResource("StyleBoxFlat_ochoi")
toggle_mode = true
button_group = ExtResource("2_nfkp2")
[node name="Button9" type="Button" parent="Days"]
custom_minimum_size = Vector2(30, 30)
layout_mode = 2
mouse_default_cursor_shape = 2
theme_override_colors/font_color = Color(0, 0, 0, 1)
theme_override_colors/font_pressed_color = Color(1, 1, 1, 1)
theme_override_styles/focus = SubResource("StyleBoxEmpty_5l1mp")
theme_override_styles/hover = SubResource("StyleBoxFlat_5l1mp")
theme_override_styles/pressed = SubResource("StyleBoxFlat_pressed")
theme_override_styles/normal = SubResource("StyleBoxFlat_ochoi")
toggle_mode = true
button_group = ExtResource("2_nfkp2")
[node name="Button10" type="Button" parent="Days"]
custom_minimum_size = Vector2(30, 30)
layout_mode = 2
mouse_default_cursor_shape = 2
theme_override_colors/font_color = Color(0, 0, 0, 1)
theme_override_colors/font_pressed_color = Color(1, 1, 1, 1)
theme_override_styles/focus = SubResource("StyleBoxEmpty_5l1mp")
theme_override_styles/hover = SubResource("StyleBoxFlat_5l1mp")
theme_override_styles/pressed = SubResource("StyleBoxFlat_pressed")
theme_override_styles/normal = SubResource("StyleBoxFlat_ochoi")
toggle_mode = true
button_group = ExtResource("2_nfkp2")
[node name="Button11" type="Button" parent="Days"]
custom_minimum_size = Vector2(30, 30)
layout_mode = 2
mouse_default_cursor_shape = 2
theme_override_colors/font_color = Color(0, 0, 0, 1)
theme_override_colors/font_pressed_color = Color(1, 1, 1, 1)
theme_override_styles/focus = SubResource("StyleBoxEmpty_5l1mp")
theme_override_styles/hover = SubResource("StyleBoxFlat_5l1mp")
theme_override_styles/pressed = SubResource("StyleBoxFlat_pressed")
theme_override_styles/normal = SubResource("StyleBoxFlat_ochoi")
toggle_mode = true
button_group = ExtResource("2_nfkp2")
[node name="Button12" type="Button" parent="Days"]
custom_minimum_size = Vector2(30, 30)
layout_mode = 2
mouse_default_cursor_shape = 2
theme_override_colors/font_color = Color(0, 0, 0, 1)
theme_override_colors/font_pressed_color = Color(1, 1, 1, 1)
theme_override_styles/focus = SubResource("StyleBoxEmpty_5l1mp")
theme_override_styles/hover = SubResource("StyleBoxFlat_5l1mp")
theme_override_styles/pressed = SubResource("StyleBoxFlat_pressed")
theme_override_styles/normal = SubResource("StyleBoxFlat_ochoi")
toggle_mode = true
button_group = ExtResource("2_nfkp2")
[node name="Button13" type="Button" parent="Days"]
custom_minimum_size = Vector2(30, 30)
layout_mode = 2
mouse_default_cursor_shape = 2
theme_override_colors/font_color = Color(0, 0, 0, 1)
theme_override_colors/font_pressed_color = Color(1, 1, 1, 1)
theme_override_styles/focus = SubResource("StyleBoxEmpty_5l1mp")
theme_override_styles/hover = SubResource("StyleBoxFlat_5l1mp")
theme_override_styles/pressed = SubResource("StyleBoxFlat_pressed")
theme_override_styles/normal = SubResource("StyleBoxFlat_ochoi")
toggle_mode = true
button_group = ExtResource("2_nfkp2")
[node name="Button14" type="Button" parent="Days"]
custom_minimum_size = Vector2(30, 30)
layout_mode = 2
mouse_default_cursor_shape = 2
theme_override_colors/font_color = Color(0, 0, 0, 1)
theme_override_colors/font_pressed_color = Color(1, 1, 1, 1)
theme_override_styles/focus = SubResource("StyleBoxEmpty_5l1mp")
theme_override_styles/hover = SubResource("StyleBoxFlat_5l1mp")
theme_override_styles/pressed = SubResource("StyleBoxFlat_pressed")
theme_override_styles/normal = SubResource("StyleBoxFlat_ochoi")
toggle_mode = true
button_group = ExtResource("2_nfkp2")
[node name="Button15" type="Button" parent="Days"]
custom_minimum_size = Vector2(30, 30)
layout_mode = 2
mouse_default_cursor_shape = 2
theme_override_colors/font_color = Color(0, 0, 0, 1)
theme_override_colors/font_pressed_color = Color(1, 1, 1, 1)
theme_override_styles/focus = SubResource("StyleBoxEmpty_5l1mp")
theme_override_styles/hover = SubResource("StyleBoxFlat_5l1mp")
theme_override_styles/pressed = SubResource("StyleBoxFlat_pressed")
theme_override_styles/normal = SubResource("StyleBoxFlat_ochoi")
toggle_mode = true
button_group = ExtResource("2_nfkp2")
[node name="Button16" type="Button" parent="Days"]
custom_minimum_size = Vector2(30, 30)
layout_mode = 2
mouse_default_cursor_shape = 2
theme_override_colors/font_color = Color(0, 0, 0, 1)
theme_override_colors/font_pressed_color = Color(1, 1, 1, 1)
theme_override_styles/focus = SubResource("StyleBoxEmpty_5l1mp")
theme_override_styles/hover = SubResource("StyleBoxFlat_5l1mp")
theme_override_styles/pressed = SubResource("StyleBoxFlat_pressed")
theme_override_styles/normal = SubResource("StyleBoxFlat_ochoi")
toggle_mode = true
button_group = ExtResource("2_nfkp2")
[node name="Button17" type="Button" parent="Days"]
custom_minimum_size = Vector2(30, 30)
layout_mode = 2
mouse_default_cursor_shape = 2
theme_override_colors/font_color = Color(0, 0, 0, 1)
theme_override_colors/font_pressed_color = Color(1, 1, 1, 1)
theme_override_styles/focus = SubResource("StyleBoxEmpty_5l1mp")
theme_override_styles/hover = SubResource("StyleBoxFlat_5l1mp")
theme_override_styles/pressed = SubResource("StyleBoxFlat_pressed")
theme_override_styles/normal = SubResource("StyleBoxFlat_ochoi")
toggle_mode = true
button_group = ExtResource("2_nfkp2")
[node name="Button18" type="Button" parent="Days"]
custom_minimum_size = Vector2(30, 30)
layout_mode = 2
mouse_default_cursor_shape = 2
theme_override_colors/font_color = Color(0, 0, 0, 1)
theme_override_colors/font_pressed_color = Color(1, 1, 1, 1)
theme_override_styles/focus = SubResource("StyleBoxEmpty_5l1mp")
theme_override_styles/hover = SubResource("StyleBoxFlat_5l1mp")
theme_override_styles/pressed = SubResource("StyleBoxFlat_pressed")
theme_override_styles/normal = SubResource("StyleBoxFlat_ochoi")
toggle_mode = true
button_group = ExtResource("2_nfkp2")
[node name="Button19" type="Button" parent="Days"]
custom_minimum_size = Vector2(30, 30)
layout_mode = 2
mouse_default_cursor_shape = 2
theme_override_colors/font_color = Color(0, 0, 0, 1)
theme_override_colors/font_pressed_color = Color(1, 1, 1, 1)
theme_override_styles/focus = SubResource("StyleBoxEmpty_5l1mp")
theme_override_styles/hover = SubResource("StyleBoxFlat_5l1mp")
theme_override_styles/pressed = SubResource("StyleBoxFlat_pressed")
theme_override_styles/normal = SubResource("StyleBoxFlat_ochoi")
toggle_mode = true
button_group = ExtResource("2_nfkp2")
[node name="Button20" type="Button" parent="Days"]
custom_minimum_size = Vector2(30, 30)
layout_mode = 2
mouse_default_cursor_shape = 2
theme_override_colors/font_color = Color(0, 0, 0, 1)
theme_override_colors/font_pressed_color = Color(1, 1, 1, 1)
theme_override_styles/focus = SubResource("StyleBoxEmpty_5l1mp")
theme_override_styles/hover = SubResource("StyleBoxFlat_5l1mp")
theme_override_styles/pressed = SubResource("StyleBoxFlat_pressed")
theme_override_styles/normal = SubResource("StyleBoxFlat_ochoi")
toggle_mode = true
button_group = ExtResource("2_nfkp2")
[node name="Button21" type="Button" parent="Days"]
custom_minimum_size = Vector2(30, 30)
layout_mode = 2
mouse_default_cursor_shape = 2
theme_override_colors/font_color = Color(0, 0, 0, 1)
theme_override_colors/font_pressed_color = Color(1, 1, 1, 1)
theme_override_styles/focus = SubResource("StyleBoxEmpty_5l1mp")
theme_override_styles/hover = SubResource("StyleBoxFlat_5l1mp")
theme_override_styles/pressed = SubResource("StyleBoxFlat_pressed")
theme_override_styles/normal = SubResource("StyleBoxFlat_ochoi")
toggle_mode = true
button_group = ExtResource("2_nfkp2")
[node name="Button22" type="Button" parent="Days"]
custom_minimum_size = Vector2(30, 30)
layout_mode = 2
mouse_default_cursor_shape = 2
theme_override_colors/font_color = Color(0, 0, 0, 1)
theme_override_colors/font_pressed_color = Color(1, 1, 1, 1)
theme_override_styles/focus = SubResource("StyleBoxEmpty_5l1mp")
theme_override_styles/hover = SubResource("StyleBoxFlat_5l1mp")
theme_override_styles/pressed = SubResource("StyleBoxFlat_pressed")
theme_override_styles/normal = SubResource("StyleBoxFlat_ochoi")
toggle_mode = true
button_group = ExtResource("2_nfkp2")
[node name="Button23" type="Button" parent="Days"]
custom_minimum_size = Vector2(30, 30)
layout_mode = 2
mouse_default_cursor_shape = 2
theme_override_colors/font_color = Color(0, 0, 0, 1)
theme_override_colors/font_pressed_color = Color(1, 1, 1, 1)
theme_override_styles/focus = SubResource("StyleBoxEmpty_5l1mp")
theme_override_styles/hover = SubResource("StyleBoxFlat_5l1mp")
theme_override_styles/pressed = SubResource("StyleBoxFlat_pressed")
theme_override_styles/normal = SubResource("StyleBoxFlat_ochoi")
toggle_mode = true
button_group = ExtResource("2_nfkp2")
[node name="Button24" type="Button" parent="Days"]
custom_minimum_size = Vector2(30, 30)
layout_mode = 2
mouse_default_cursor_shape = 2
theme_override_colors/font_color = Color(0, 0, 0, 1)
theme_override_colors/font_pressed_color = Color(1, 1, 1, 1)
theme_override_styles/focus = SubResource("StyleBoxEmpty_5l1mp")
theme_override_styles/hover = SubResource("StyleBoxFlat_5l1mp")
theme_override_styles/pressed = SubResource("StyleBoxFlat_pressed")
theme_override_styles/normal = SubResource("StyleBoxFlat_ochoi")
toggle_mode = true
button_group = ExtResource("2_nfkp2")
[node name="Button25" type="Button" parent="Days"]
custom_minimum_size = Vector2(30, 30)
layout_mode = 2
mouse_default_cursor_shape = 2
theme_override_colors/font_color = Color(0, 0, 0, 1)
theme_override_colors/font_pressed_color = Color(1, 1, 1, 1)
theme_override_styles/focus = SubResource("StyleBoxEmpty_5l1mp")
theme_override_styles/hover = SubResource("StyleBoxFlat_5l1mp")
theme_override_styles/pressed = SubResource("StyleBoxFlat_pressed")
theme_override_styles/normal = SubResource("StyleBoxFlat_ochoi")
toggle_mode = true
button_group = ExtResource("2_nfkp2")
[node name="Button26" type="Button" parent="Days"]
custom_minimum_size = Vector2(30, 30)
layout_mode = 2
mouse_default_cursor_shape = 2
theme_override_colors/font_color = Color(0, 0, 0, 1)
theme_override_colors/font_pressed_color = Color(1, 1, 1, 1)
theme_override_styles/focus = SubResource("StyleBoxEmpty_5l1mp")
theme_override_styles/hover = SubResource("StyleBoxFlat_5l1mp")
theme_override_styles/pressed = SubResource("StyleBoxFlat_pressed")
theme_override_styles/normal = SubResource("StyleBoxFlat_ochoi")
toggle_mode = true
button_group = ExtResource("2_nfkp2")
[node name="Button27" type="Button" parent="Days"]
custom_minimum_size = Vector2(30, 30)
layout_mode = 2
mouse_default_cursor_shape = 2
theme_override_colors/font_color = Color(0, 0, 0, 1)
theme_override_colors/font_pressed_color = Color(1, 1, 1, 1)
theme_override_styles/focus = SubResource("StyleBoxEmpty_5l1mp")
theme_override_styles/hover = SubResource("StyleBoxFlat_5l1mp")
theme_override_styles/pressed = SubResource("StyleBoxFlat_pressed")
theme_override_styles/normal = SubResource("StyleBoxFlat_ochoi")
toggle_mode = true
button_group = ExtResource("2_nfkp2")
[node name="Button28" type="Button" parent="Days"]
custom_minimum_size = Vector2(30, 30)
layout_mode = 2
mouse_default_cursor_shape = 2
theme_override_colors/font_color = Color(0, 0, 0, 1)
theme_override_colors/font_pressed_color = Color(1, 1, 1, 1)
theme_override_styles/focus = SubResource("StyleBoxEmpty_5l1mp")
theme_override_styles/hover = SubResource("StyleBoxFlat_5l1mp")
theme_override_styles/pressed = SubResource("StyleBoxFlat_pressed")
theme_override_styles/normal = SubResource("StyleBoxFlat_ochoi")
toggle_mode = true
button_group = ExtResource("2_nfkp2")
[node name="Button29" type="Button" parent="Days"]
custom_minimum_size = Vector2(30, 30)
layout_mode = 2
mouse_default_cursor_shape = 2
theme_override_colors/font_color = Color(0, 0, 0, 1)
theme_override_colors/font_pressed_color = Color(1, 1, 1, 1)
theme_override_styles/focus = SubResource("StyleBoxEmpty_5l1mp")
theme_override_styles/hover = SubResource("StyleBoxFlat_5l1mp")
theme_override_styles/pressed = SubResource("StyleBoxFlat_pressed")
theme_override_styles/normal = SubResource("StyleBoxFlat_ochoi")
toggle_mode = true
button_group = ExtResource("2_nfkp2")
[node name="Button30" type="Button" parent="Days"]
custom_minimum_size = Vector2(30, 30)
layout_mode = 2
mouse_default_cursor_shape = 2
theme_override_colors/font_color = Color(0, 0, 0, 1)
theme_override_colors/font_pressed_color = Color(1, 1, 1, 1)
theme_override_styles/focus = SubResource("StyleBoxEmpty_5l1mp")
theme_override_styles/hover = SubResource("StyleBoxFlat_5l1mp")
theme_override_styles/pressed = SubResource("StyleBoxFlat_pressed")
theme_override_styles/normal = SubResource("StyleBoxFlat_ochoi")
toggle_mode = true
button_group = ExtResource("2_nfkp2")
[node name="Button31" type="Button" parent="Days"]
custom_minimum_size = Vector2(30, 30)
layout_mode = 2
mouse_default_cursor_shape = 2
theme_override_colors/font_color = Color(0, 0, 0, 1)
theme_override_colors/font_pressed_color = Color(1, 1, 1, 1)
theme_override_styles/focus = SubResource("StyleBoxEmpty_5l1mp")
theme_override_styles/hover = SubResource("StyleBoxFlat_5l1mp")
theme_override_styles/pressed = SubResource("StyleBoxFlat_pressed")
theme_override_styles/normal = SubResource("StyleBoxFlat_ochoi")
toggle_mode = true
button_group = ExtResource("2_nfkp2")
[node name="Button32" type="Button" parent="Days"]
custom_minimum_size = Vector2(30, 30)
layout_mode = 2
mouse_default_cursor_shape = 2
theme_override_colors/font_color = Color(0, 0, 0, 1)
theme_override_colors/font_pressed_color = Color(1, 1, 1, 1)
theme_override_styles/focus = SubResource("StyleBoxEmpty_5l1mp")
theme_override_styles/hover = SubResource("StyleBoxFlat_5l1mp")
theme_override_styles/pressed = SubResource("StyleBoxFlat_pressed")
theme_override_styles/normal = SubResource("StyleBoxFlat_ochoi")
toggle_mode = true
button_group = ExtResource("2_nfkp2")
[node name="Button33" type="Button" parent="Days"]
custom_minimum_size = Vector2(30, 30)
layout_mode = 2
mouse_default_cursor_shape = 2
theme_override_colors/font_color = Color(0, 0, 0, 1)
theme_override_colors/font_pressed_color = Color(1, 1, 1, 1)
theme_override_styles/focus = SubResource("StyleBoxEmpty_5l1mp")
theme_override_styles/hover = SubResource("StyleBoxFlat_5l1mp")
theme_override_styles/pressed = SubResource("StyleBoxFlat_pressed")
theme_override_styles/normal = SubResource("StyleBoxFlat_ochoi")
toggle_mode = true
button_group = ExtResource("2_nfkp2")
[node name="Button34" type="Button" parent="Days"]
custom_minimum_size = Vector2(30, 30)
layout_mode = 2
mouse_default_cursor_shape = 2
theme_override_colors/font_color = Color(0, 0, 0, 1)
theme_override_colors/font_pressed_color = Color(1, 1, 1, 1)
theme_override_styles/focus = SubResource("StyleBoxEmpty_5l1mp")
theme_override_styles/hover = SubResource("StyleBoxFlat_5l1mp")
theme_override_styles/pressed = SubResource("StyleBoxFlat_pressed")
theme_override_styles/normal = SubResource("StyleBoxFlat_ochoi")
toggle_mode = true
button_group = ExtResource("2_nfkp2")
[node name="Button35" type="Button" parent="Days"]
custom_minimum_size = Vector2(30, 30)
layout_mode = 2
mouse_default_cursor_shape = 2
theme_override_colors/font_color = Color(0, 0, 0, 1)
theme_override_colors/font_pressed_color = Color(1, 1, 1, 1)
theme_override_styles/focus = SubResource("StyleBoxEmpty_5l1mp")
theme_override_styles/hover = SubResource("StyleBoxFlat_5l1mp")
theme_override_styles/pressed = SubResource("StyleBoxFlat_pressed")
theme_override_styles/normal = SubResource("StyleBoxFlat_ochoi")
toggle_mode = true
button_group = ExtResource("2_nfkp2")
[node name="Button36" type="Button" parent="Days"]
custom_minimum_size = Vector2(30, 30)
layout_mode = 2
mouse_default_cursor_shape = 2
theme_override_colors/font_color = Color(0, 0, 0, 1)
theme_override_colors/font_pressed_color = Color(1, 1, 1, 1)
theme_override_styles/focus = SubResource("StyleBoxEmpty_5l1mp")
theme_override_styles/hover = SubResource("StyleBoxFlat_5l1mp")
theme_override_styles/pressed = SubResource("StyleBoxFlat_pressed")
theme_override_styles/normal = SubResource("StyleBoxFlat_ochoi")
toggle_mode = true
button_group = ExtResource("2_nfkp2")
[node name="Button37" type="Button" parent="Days"]
custom_minimum_size = Vector2(30, 30)
layout_mode = 2
mouse_default_cursor_shape = 2
theme_override_colors/font_color = Color(0, 0, 0, 1)
theme_override_colors/font_pressed_color = Color(1, 1, 1, 1)
theme_override_styles/focus = SubResource("StyleBoxEmpty_5l1mp")
theme_override_styles/hover = SubResource("StyleBoxFlat_5l1mp")
theme_override_styles/pressed = SubResource("StyleBoxFlat_pressed")
theme_override_styles/normal = SubResource("StyleBoxFlat_ochoi")
toggle_mode = true
button_group = ExtResource("2_nfkp2")
[node name="Button38" type="Button" parent="Days"]
custom_minimum_size = Vector2(30, 30)
layout_mode = 2
mouse_default_cursor_shape = 2
theme_override_colors/font_color = Color(0, 0, 0, 1)
theme_override_colors/font_pressed_color = Color(1, 1, 1, 1)
theme_override_styles/focus = SubResource("StyleBoxEmpty_5l1mp")
theme_override_styles/hover = SubResource("StyleBoxFlat_5l1mp")
theme_override_styles/pressed = SubResource("StyleBoxFlat_pressed")
theme_override_styles/normal = SubResource("StyleBoxFlat_ochoi")
toggle_mode = true
button_group = ExtResource("2_nfkp2")
[node name="Button39" type="Button" parent="Days"]
custom_minimum_size = Vector2(30, 30)
layout_mode = 2
mouse_default_cursor_shape = 2
theme_override_colors/font_color = Color(0, 0, 0, 1)
theme_override_colors/font_pressed_color = Color(1, 1, 1, 1)
theme_override_styles/focus = SubResource("StyleBoxEmpty_5l1mp")
theme_override_styles/hover = SubResource("StyleBoxFlat_5l1mp")
theme_override_styles/pressed = SubResource("StyleBoxFlat_pressed")
theme_override_styles/normal = SubResource("StyleBoxFlat_ochoi")
toggle_mode = true
button_group = ExtResource("2_nfkp2")
[node name="Button40" type="Button" parent="Days"]
custom_minimum_size = Vector2(30, 30)
layout_mode = 2
mouse_default_cursor_shape = 2
theme_override_colors/font_color = Color(0, 0, 0, 1)
theme_override_colors/font_pressed_color = Color(1, 1, 1, 1)
theme_override_styles/focus = SubResource("StyleBoxEmpty_5l1mp")
theme_override_styles/hover = SubResource("StyleBoxFlat_5l1mp")
theme_override_styles/pressed = SubResource("StyleBoxFlat_pressed")
theme_override_styles/normal = SubResource("StyleBoxFlat_ochoi")
toggle_mode = true
button_group = ExtResource("2_nfkp2")
[node name="Button41" type="Button" parent="Days"]
custom_minimum_size = Vector2(30, 30)
layout_mode = 2
mouse_default_cursor_shape = 2
theme_override_colors/font_color = Color(0, 0, 0, 1)
theme_override_colors/font_pressed_color = Color(1, 1, 1, 1)
theme_override_styles/focus = SubResource("StyleBoxEmpty_5l1mp")
theme_override_styles/hover = SubResource("StyleBoxFlat_5l1mp")
theme_override_styles/pressed = SubResource("StyleBoxFlat_pressed")
theme_override_styles/normal = SubResource("StyleBoxFlat_ochoi")
toggle_mode = true
button_group = ExtResource("2_nfkp2")

View File

@@ -0,0 +1,4 @@
This is a heavily modified version of **DatePicker** by [chrisizeful](https://github.com/chrisizeful/)
- GitHub: https://github.com/chrisizeful/DatePicker
- Godot Asset: https://godotengine.org/asset-library/asset/3835

View File

@@ -0,0 +1 @@
uid://b5qslpdcfyikx

View File

@@ -0,0 +1,92 @@
class_name YearView
extends HBoxContainer
@export var calendar: Calendar
func init():
var button_example: Button = %Button
var year_container: VBoxContainer = %YearContainer
var buttons_data = []
for i in range(200):
var year = i + 1900
buttons_data.append(year)
for year in buttons_data:
var new_btn: Button = button_example.duplicate()
new_btn.name = "Year" + str(year)
new_btn.pressed.connect(_on_year_selected.bind(year))
new_btn.text = str(year)
year_container.add_child(new_btn)
button_example.queue_free()
year_container.resized.connect(func():
scroll_to_current_year()
refresh()
)
func scroll_to_current_year():
var year_container: VBoxContainer = %YearContainer
var scroll_container: ScrollContainer = $SmoothScrollContainer
var current_year = calendar.date_time.year
var target_button: Button = year_container.get_node_or_null("Year" + str(current_year))
if not target_button:
return
while target_button.position.y <= 0:
await get_tree().process_frame
for child in year_container.get_children():
if child is Button:
child.set_pressed_no_signal(child == target_button)
var button_position = target_button.position.y
var container_height = scroll_container.size.y
var button_height = target_button.size.y
var scroll_position = button_position - (container_height / 2) + (button_height / 2)
scroll_container.scroll_vertical = max(0, scroll_position)
func _on_year_selected(year: int):
var new_date = calendar.date_time.duplicate()
new_date.year = year
calendar.selected = new_date
calendar.date_time = new_date
if calendar.has_signal("date_changed"):
calendar.date_changed.emit(new_date)
calendar.year_view.hide()
calendar.month_view.show()
calendar.month_view.refresh()
calendar.finished.emit()
func previous():
var new_date = calendar.date_time.duplicate()
new_date.year -= 1
calendar.date_time = new_date
refresh()
func next():
var new_date = calendar.date_time.duplicate()
new_date.year += 1
calendar.date_time = new_date
refresh()
func refresh():
var current_time = Time.get_unix_time_from_system()
calendar.header.text = "%s %s" % [MonthView.num_to_month(calendar.date_time.month), calendar.date_time.year]
for child in %YearContainer.get_children():
if child is Button:
child.set_pressed_no_signal(false)
var target_button_name = "Year" + str(calendar.date_time.year)
var target_button = %YearContainer.get_node_or_null(target_button_name)
if target_button:
target_button.set_pressed_no_signal(true)

View File

@@ -0,0 +1 @@
uid://c8nfr825g08sy

View File

@@ -0,0 +1,82 @@
[gd_scene load_steps=11 format=3 uid="uid://n5ra5w5aupx7"]
[ext_resource type="Script" uid="uid://c8nfr825g08sy" path="res://addons/DatePicker/YearView.gd" id="1_hiiks"]
[ext_resource type="Script" uid="uid://bgqglerkcylxx" path="res://addons/SmoothScroll/SmoothScrollContainer.gd" id="1_sw7yn"]
[ext_resource type="ButtonGroup" uid="uid://bqxxq56yxl44h" path="res://addons/DatePicker/CalendarGroup.tres" id="2_2qddy"]
[ext_resource type="Script" uid="uid://b7h0k2h2qwlqv" path="res://addons/SmoothScroll/scroll_damper/expo_scroll_damper.gd" id="2_iofl3"]
[sub_resource type="Resource" id="Resource_wpifq"]
script = ExtResource("2_iofl3")
friction = 4.0
minimum_velocity = 0.4
rebound_strength = 7.0
[sub_resource type="Resource" id="Resource_kdl71"]
script = ExtResource("2_iofl3")
friction = 4.0
minimum_velocity = 0.4
rebound_strength = 7.0
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_iofl3"]
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_kdl71"]
content_margin_left = 8.0
bg_color = Color(0.168627, 0.168627, 0.168627, 1)
corner_radius_top_left = 4
corner_radius_top_right = 4
corner_radius_bottom_right = 4
corner_radius_bottom_left = 4
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_pressed"]
content_margin_left = 8.0
bg_color = Color(0.247059, 0.466667, 0.807843, 1)
corner_radius_top_left = 4
corner_radius_top_right = 4
corner_radius_bottom_right = 4
corner_radius_bottom_left = 4
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_wpifq"]
content_margin_left = 8.0
bg_color = Color(0.105882, 0.105882, 0.105882, 1)
corner_radius_top_left = 4
corner_radius_top_right = 4
corner_radius_bottom_right = 4
corner_radius_bottom_left = 4
[node name="YearView" type="HBoxContainer"]
script = ExtResource("1_hiiks")
[node name="SmoothScrollContainer" type="ScrollContainer" parent="."]
custom_minimum_size = Vector2(234, 240)
layout_mode = 2
script = ExtResource("1_sw7yn")
wheel_scroll_damper = SubResource("Resource_wpifq")
dragging_scroll_damper = SubResource("Resource_kdl71")
drag_with_mouse = false
allow_overdragging = false
metadata/_custom_type_script = "uid://bgqglerkcylxx"
[node name="YearContainer" type="VBoxContainer" parent="SmoothScrollContainer"]
unique_name_in_owner = true
custom_minimum_size = Vector2(234, 240)
layout_mode = 2
size_flags_horizontal = 4
size_flags_vertical = 4
[node name="Button" type="Button" parent="SmoothScrollContainer/YearContainer"]
unique_name_in_owner = true
custom_minimum_size = Vector2(34, 5)
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 3
mouse_filter = 1
theme_override_colors/font_color = Color(1, 1, 1, 1)
theme_override_colors/font_pressed_color = Color(1, 1, 1, 1)
theme_override_styles/focus = SubResource("StyleBoxEmpty_iofl3")
theme_override_styles/hover = SubResource("StyleBoxFlat_kdl71")
theme_override_styles/pressed = SubResource("StyleBoxFlat_pressed")
theme_override_styles/normal = SubResource("StyleBoxFlat_wpifq")
toggle_mode = true
button_group = ExtResource("2_2qddy")
text = "2025"
alignment = 0

View File

@@ -0,0 +1,7 @@
[plugin]
name="DatePicker"
description="A themed Godot calendar addon inspiried by the Windows 11 calendar."
author="Chris Charbonneau"
version="1.0.0"
script=""

View File

@@ -28,7 +28,7 @@ window/stretch/aspect="ignore"
[editor_plugins]
enabled=PackedStringArray("res://addons/SmoothScroll/plugin.cfg")
enabled=PackedStringArray("res://addons/DatePicker/plugin.cfg", "res://addons/SmoothScroll/plugin.cfg")
[file_customization]