Add base project
This commit is contained in:
parent
0cec0c70d5
commit
5abf7b3d81
2
.gitattributes
vendored
Normal file
2
.gitattributes
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
# Normalize EOL for all files that Git considers text files.
|
||||
* text=auto eol=lf
|
15
.gitignore
vendored
Normal file
15
.gitignore
vendored
Normal file
|
@ -0,0 +1,15 @@
|
|||
# Godot 4+ specific ignores
|
||||
.godot/
|
||||
|
||||
# Godot-specific ignores
|
||||
.import/
|
||||
export.cfg
|
||||
export_presets.cfg
|
||||
|
||||
# Imported translations (automatically generated from CSV files)
|
||||
*.translation
|
||||
|
||||
# Mono-specific ignores
|
||||
.mono/
|
||||
data_*/
|
||||
mono_crash.*.json
|
|
@ -5,3 +5,8 @@
|
|||
A simple period tracker.
|
||||
|
||||
Base idea is to track period but it can be used to track any other repetitive events.
|
||||
|
||||
## Credit
|
||||
|
||||
### Sniglet
|
||||
[Sniglet](https://www.design-research.be/by-womxn/) by [Haley Fiege](https://fonts.google.com/?query=Haley+Fiege).
|
||||
|
|
1
icon.svg
Normal file
1
icon.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg height="128" width="128" xmlns="http://www.w3.org/2000/svg"><rect x="2" y="2" width="124" height="124" rx="14" fill="#363d52" stroke="#212532" stroke-width="4"/><g transform="scale(.101) translate(122 122)"><g fill="#fff"><path d="M105 673v33q407 354 814 0v-33z"/><path fill="#478cbf" d="m105 673 152 14q12 1 15 14l4 67 132 10 8-61q2-11 15-15h162q13 4 15 15l8 61 132-10 4-67q3-13 15-14l152-14V427q30-39 56-81-35-59-83-108-43 20-82 47-40-37-88-64 7-51 8-102-59-28-123-42-26 43-46 89-49-7-98 0-20-46-46-89-64 14-123 42 1 51 8 102-48 27-88 64-39-27-82-47-48 49-83 108 26 42 56 81zm0 33v39c0 276 813 276 813 0v-39l-134 12-5 69q-2 10-14 13l-162 11q-12 0-16-11l-10-65H447l-10 65q-4 11-16 11l-162-11q-12-3-14-13l-5-69z"/><path d="M483 600c3 34 55 34 58 0v-86c-3-34-55-34-58 0z"/><circle cx="725" cy="526" r="90"/><circle cx="299" cy="526" r="90"/></g><g fill="#414042"><circle cx="307" cy="532" r="60"/><circle cx="717" cy="532" r="60"/></g></g></svg>
|
After Width: | Height: | Size: 950 B |
37
icon.svg.import
Normal file
37
icon.svg.import
Normal file
|
@ -0,0 +1,37 @@
|
|||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://cn3dbt5jkbtfe"
|
||||
path="res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://icon.svg"
|
||||
dest_files=["res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.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
|
28
project.godot
Normal file
28
project.godot
Normal file
|
@ -0,0 +1,28 @@
|
|||
; Engine configuration file.
|
||||
; It's best edited using the editor UI and not directly,
|
||||
; since the parameters that go here are not all obvious.
|
||||
;
|
||||
; Format:
|
||||
; [section] ; section goes between []
|
||||
; param=value ; assign values to parameters
|
||||
|
||||
config_version=5
|
||||
|
||||
[application]
|
||||
|
||||
config/name="gpml"
|
||||
run/main_scene="res://scene/calendar.tscn"
|
||||
config/features=PackedStringArray("4.2", "Forward Plus")
|
||||
config/icon="res://icon.svg"
|
||||
|
||||
[input]
|
||||
|
||||
shift_click={
|
||||
"deadzone": 0.5,
|
||||
"events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":true,"ctrl_pressed":false,"meta_pressed":false,"button_mask":1,"position":Vector2(669, 17),"global_position":Vector2(673, 58),"factor":1.0,"button_index":1,"canceled":false,"pressed":true,"double_click":false,"script":null)
|
||||
]
|
||||
}
|
||||
|
||||
[rendering]
|
||||
|
||||
environment/defaults/default_clear_color=Color(0.162066, 0.162066, 0.162066, 1)
|
43
scene/calendar.tscn
Normal file
43
scene/calendar.tscn
Normal file
|
@ -0,0 +1,43 @@
|
|||
[gd_scene load_steps=5 format=3 uid="uid://bkwvaljh0oj22"]
|
||||
|
||||
[ext_resource type="Theme" uid="uid://bu07nib41exqy" path="res://ui/theme.tres" id="1_jufjt"]
|
||||
[ext_resource type="Script" path="res://script/calendar.gd" id="1_nbpow"]
|
||||
[ext_resource type="PackedScene" uid="uid://x8u7mduga68y" path="res://scene/month.tscn" id="2_g4ut4"]
|
||||
[ext_resource type="Script" path="res://scene/periodmanager.gd" id="3_3jsi6"]
|
||||
|
||||
[node name="Calendar" type="Control"]
|
||||
layout_mode = 3
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme = ExtResource("1_jufjt")
|
||||
script = ExtResource("1_nbpow")
|
||||
month_scene = ExtResource("2_g4ut4")
|
||||
|
||||
[node name="CenterContainer" type="CenterContainer" parent="."]
|
||||
layout_mode = 1
|
||||
anchors_preset = 5
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
offset_left = -576.0
|
||||
offset_right = 576.0
|
||||
offset_bottom = 27.0
|
||||
grow_horizontal = 2
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="CenterContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="YearLabel" type="Label" parent="CenterContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 0
|
||||
theme_override_font_sizes/font_size = 96
|
||||
|
||||
[node name="Year" type="GridContainer" parent="CenterContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 4
|
||||
columns = 4
|
||||
|
||||
[node name="PeriodManager" type="Node" parent="."]
|
||||
script = ExtResource("3_3jsi6")
|
9
scene/day.tscn
Normal file
9
scene/day.tscn
Normal file
|
@ -0,0 +1,9 @@
|
|||
[gd_scene load_steps=2 format=3 uid="uid://dt5l2bunc1iru"]
|
||||
|
||||
[ext_resource type="Script" path="res://script/day.gd" id="1_jhrhj"]
|
||||
|
||||
[node name="Day" type="Button"]
|
||||
offset_right = 46.0
|
||||
offset_bottom = 40.0
|
||||
text = "12"
|
||||
script = ExtResource("1_jhrhj")
|
63
scene/month.tscn
Normal file
63
scene/month.tscn
Normal file
|
@ -0,0 +1,63 @@
|
|||
[gd_scene load_steps=3 format=3 uid="uid://x8u7mduga68y"]
|
||||
|
||||
[ext_resource type="Script" path="res://script/month.gd" id="1_tiy7h"]
|
||||
[ext_resource type="PackedScene" uid="uid://dt5l2bunc1iru" path="res://scene/day.tscn" id="2_5kdiw"]
|
||||
|
||||
[node name="Month" type="Control"]
|
||||
custom_minimum_size = Vector2(250, 250)
|
||||
layout_mode = 3
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
script = ExtResource("1_tiy7h")
|
||||
day_scene = ExtResource("2_5kdiw")
|
||||
|
||||
[node name="HBoxContainer" type="HBoxContainer" parent="."]
|
||||
layout_mode = 0
|
||||
offset_right = 40.0
|
||||
offset_bottom = 40.0
|
||||
|
||||
[node name="MonthLabel" type="Label" parent="HBoxContainer"]
|
||||
layout_mode = 2
|
||||
theme_override_font_sizes/font_size = 20
|
||||
|
||||
[node name="DaysGridContainer" type="GridContainer" parent="HBoxContainer"]
|
||||
layout_mode = 2
|
||||
columns = 7
|
||||
|
||||
[node name="Dimanche" type="Label" parent="HBoxContainer/DaysGridContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 4
|
||||
text = "D"
|
||||
|
||||
[node name="Lundi" type="Label" parent="HBoxContainer/DaysGridContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 4
|
||||
text = "L"
|
||||
|
||||
[node name="Mardi" type="Label" parent="HBoxContainer/DaysGridContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 4
|
||||
text = "M"
|
||||
|
||||
[node name="Mercredi" type="Label" parent="HBoxContainer/DaysGridContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 4
|
||||
text = "M"
|
||||
|
||||
[node name="Jeudi" type="Label" parent="HBoxContainer/DaysGridContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 4
|
||||
text = "J"
|
||||
|
||||
[node name="Vendredi" type="Label" parent="HBoxContainer/DaysGridContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 4
|
||||
text = "V"
|
||||
|
||||
[node name="Samedi" type="Label" parent="HBoxContainer/DaysGridContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 4
|
||||
text = "S"
|
25
scene/periodmanager.gd
Normal file
25
scene/periodmanager.gd
Normal file
|
@ -0,0 +1,25 @@
|
|||
extends Node
|
||||
|
||||
|
||||
var periods = []
|
||||
var last_period = null
|
||||
|
||||
|
||||
func add(date):
|
||||
if last_period != null:
|
||||
last_period.end = date
|
||||
last_period = null
|
||||
dump()
|
||||
return
|
||||
|
||||
# If no new period has begun
|
||||
var period = Period.new()
|
||||
period.begin = date
|
||||
periods.append(period)
|
||||
last_period = period
|
||||
dump()
|
||||
|
||||
|
||||
func dump():
|
||||
for period in periods:
|
||||
print("%s - %s" % [period.begin, period.end])
|
64
script/calendar.gd
Normal file
64
script/calendar.gd
Normal file
|
@ -0,0 +1,64 @@
|
|||
class_name Calendar
|
||||
extends Control
|
||||
|
||||
@export var month_scene: PackedScene
|
||||
|
||||
@onready var year_label = $CenterContainer/VBoxContainer/YearLabel
|
||||
@onready var year = $CenterContainer/VBoxContainer/Year
|
||||
@onready var period_manager = $PeriodManager
|
||||
|
||||
var last_focused_day = null
|
||||
var new_focused_day = null
|
||||
var all_days = []
|
||||
|
||||
# Called when the node enters the scene tree for the first time.
|
||||
func _ready():
|
||||
var current_year = Time.get_date_dict_from_system().year
|
||||
|
||||
year_label.text = "%s" % current_year
|
||||
|
||||
for i in range (1, 13):
|
||||
var month = month_scene.instantiate()
|
||||
month.year = current_year
|
||||
month.month = i
|
||||
month.day_toggled.connect(_on_day_toggled)
|
||||
month.fill_days.connect(_on_fill_days)
|
||||
year.add_child(month)
|
||||
|
||||
for element in month.days.get_children():
|
||||
if element is Day:
|
||||
all_days.append(element)
|
||||
|
||||
|
||||
func _on_day_toggled(date):
|
||||
# period_manager.add(date)
|
||||
|
||||
# Update last focused day.
|
||||
var focused_node = get_viewport().gui_get_focus_owner()
|
||||
if focused_node is Day:
|
||||
last_focused_day = focused_node
|
||||
|
||||
|
||||
func _on_fill_days(shift_clicked_day):
|
||||
# Toogle day from last focused day to current day.
|
||||
|
||||
# Assert that last focused day is different from date.
|
||||
if last_focused_day == null:
|
||||
return
|
||||
|
||||
if shift_clicked_day == last_focused_day:
|
||||
return
|
||||
|
||||
# Determine if date is before or after the last focused day.
|
||||
var first_day = last_focused_day if last_focused_day.is_before(shift_clicked_day) else shift_clicked_day
|
||||
var last_day = shift_clicked_day if first_day == last_focused_day else last_focused_day
|
||||
|
||||
# Toggle days between the two days.
|
||||
var toggle = false
|
||||
for day in all_days:
|
||||
if first_day == day:
|
||||
toggle = true
|
||||
if toggle:
|
||||
day.set_pressed_no_signal(true)
|
||||
if last_day == day:
|
||||
return
|
39
script/day.gd
Normal file
39
script/day.gd
Normal file
|
@ -0,0 +1,39 @@
|
|||
class_name Day
|
||||
extends Button
|
||||
|
||||
|
||||
signal day_toggled(date)
|
||||
signal fill_days(date)
|
||||
|
||||
var date = {}
|
||||
|
||||
|
||||
func _ready():
|
||||
set_toggle_mode(true);
|
||||
toggled.connect(self._on_day_toggled)
|
||||
|
||||
|
||||
func _gui_input(event):
|
||||
if event.is_action_pressed("shift_click"):
|
||||
fill_days.emit(self)
|
||||
accept_event()
|
||||
|
||||
|
||||
func _on_day_toggled(_toggled_on):
|
||||
day_toggled.emit(date)
|
||||
|
||||
|
||||
func set_date(year, month, day):
|
||||
date = {"year": year, "month": month, "day": day}
|
||||
|
||||
|
||||
func is_before(other_day):
|
||||
var day_unix_time = Time.get_unix_time_from_datetime_dict(date)
|
||||
var other_day_unix_time = Time.get_unix_time_from_datetime_dict(other_day.date)
|
||||
|
||||
if day_unix_time < other_day_unix_time:
|
||||
return true
|
||||
return false
|
||||
|
||||
func dump():
|
||||
print("%s - %s - %s" % [date.year, date.month, date.day])
|
55
script/month.gd
Normal file
55
script/month.gd
Normal file
|
@ -0,0 +1,55 @@
|
|||
class_name Month
|
||||
extends Control
|
||||
|
||||
|
||||
signal day_toggled(date)
|
||||
signal fill_days(date)
|
||||
|
||||
const DAYS_IN_MONTH = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
|
||||
|
||||
@export var day_scene: PackedScene
|
||||
var year: int
|
||||
var month: int
|
||||
|
||||
@onready var month_label = $HBoxContainer/MonthLabel
|
||||
@onready var days = $HBoxContainer/DaysGridContainer
|
||||
|
||||
|
||||
# Called when the node enters the scene tree for the first time.
|
||||
func _ready():
|
||||
month_label.text = "%s" % month
|
||||
|
||||
var days_in_month = find_days_in_month(year, month)
|
||||
var date_string = "%s-%s-%s" % [year, month, 1]
|
||||
var first_day = Time.get_datetime_dict_from_datetime_string(date_string, true)
|
||||
|
||||
# Fill the container with number corresponding to days
|
||||
for i in range(first_day.weekday):
|
||||
var empty_label = Label.new()
|
||||
days.add_child(empty_label)
|
||||
for i in range(1, days_in_month + 1):
|
||||
var day = day_scene.instantiate()
|
||||
day.set_date(year, month, i)
|
||||
day.text = "%s" % [i]
|
||||
day.day_toggled.connect(_on_day_toggled)
|
||||
day.fill_days.connect(_on_fill_days)
|
||||
days.add_child(day)
|
||||
|
||||
|
||||
func _on_day_toggled(date):
|
||||
day_toggled.emit(date)
|
||||
|
||||
|
||||
func _on_fill_days(day):
|
||||
fill_days.emit(day)
|
||||
|
||||
|
||||
func find_days_in_month(year: int, month: int):
|
||||
assert(month >= 1 and month <= 12)
|
||||
if (month == 2 and is_leap_year(year)):
|
||||
return 29
|
||||
return DAYS_IN_MONTH[month - 1]
|
||||
|
||||
|
||||
func is_leap_year(year: int):
|
||||
return year % 4 == 0 and (year % 100 != 0 or year % 400 == 0)
|
5
script/period.gd
Normal file
5
script/period.gd
Normal file
|
@ -0,0 +1,5 @@
|
|||
class_name Period
|
||||
extends Node
|
||||
|
||||
var begin = {}
|
||||
var end = {}
|
BIN
ui/Sniglet-ExtraBold.ttf
Normal file
BIN
ui/Sniglet-ExtraBold.ttf
Normal file
Binary file not shown.
33
ui/Sniglet-ExtraBold.ttf.import
Normal file
33
ui/Sniglet-ExtraBold.ttf.import
Normal file
|
@ -0,0 +1,33 @@
|
|||
[remap]
|
||||
|
||||
importer="font_data_dynamic"
|
||||
type="FontFile"
|
||||
uid="uid://dkdwwfrrrxsv6"
|
||||
path="res://.godot/imported/Sniglet-ExtraBold.ttf-e7d97d8b5ada3d87451c1bbbfe8eb998.fontdata"
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://ui/Sniglet-ExtraBold.ttf"
|
||||
dest_files=["res://.godot/imported/Sniglet-ExtraBold.ttf-e7d97d8b5ada3d87451c1bbbfe8eb998.fontdata"]
|
||||
|
||||
[params]
|
||||
|
||||
Rendering=null
|
||||
antialiasing=1
|
||||
generate_mipmaps=false
|
||||
multichannel_signed_distance_field=false
|
||||
msdf_pixel_range=8
|
||||
msdf_size=48
|
||||
allow_system_fallback=true
|
||||
force_autohinter=false
|
||||
hinting=1
|
||||
subpixel_positioning=1
|
||||
oversampling=0.0
|
||||
Fallbacks=null
|
||||
fallbacks=[]
|
||||
Compress=null
|
||||
compress=true
|
||||
preload=[]
|
||||
language_support={}
|
||||
script_support={}
|
||||
opentype_features={}
|
BIN
ui/Sniglet-Regular.ttf
Normal file
BIN
ui/Sniglet-Regular.ttf
Normal file
Binary file not shown.
33
ui/Sniglet-Regular.ttf.import
Normal file
33
ui/Sniglet-Regular.ttf.import
Normal file
|
@ -0,0 +1,33 @@
|
|||
[remap]
|
||||
|
||||
importer="font_data_dynamic"
|
||||
type="FontFile"
|
||||
uid="uid://bqpsg4cosm86c"
|
||||
path="res://.godot/imported/Sniglet-Regular.ttf-a388ba5acd2b2b968e010f49c0098b80.fontdata"
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://ui/Sniglet-Regular.ttf"
|
||||
dest_files=["res://.godot/imported/Sniglet-Regular.ttf-a388ba5acd2b2b968e010f49c0098b80.fontdata"]
|
||||
|
||||
[params]
|
||||
|
||||
Rendering=null
|
||||
antialiasing=1
|
||||
generate_mipmaps=false
|
||||
multichannel_signed_distance_field=false
|
||||
msdf_pixel_range=8
|
||||
msdf_size=48
|
||||
allow_system_fallback=true
|
||||
force_autohinter=false
|
||||
hinting=1
|
||||
subpixel_positioning=1
|
||||
oversampling=0.0
|
||||
Fallbacks=null
|
||||
fallbacks=[]
|
||||
Compress=null
|
||||
compress=true
|
||||
preload=[]
|
||||
language_support={}
|
||||
script_support={}
|
||||
opentype_features={}
|
44
ui/theme.tres
Normal file
44
ui/theme.tres
Normal file
|
@ -0,0 +1,44 @@
|
|||
[gd_resource type="Theme" load_steps=4 format=3 uid="uid://bu07nib41exqy"]
|
||||
|
||||
[ext_resource type="FontFile" uid="uid://bqpsg4cosm86c" path="res://ui/Sniglet-Regular.ttf" id="1_8evya"]
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_jjd3u"]
|
||||
content_margin_left = 4.0
|
||||
content_margin_top = 4.0
|
||||
content_margin_right = 4.0
|
||||
content_margin_bottom = 4.0
|
||||
bg_color = Color(0.1, 0.1, 0.1, 0.6)
|
||||
border_width_left = 3
|
||||
border_width_top = 3
|
||||
border_width_right = 3
|
||||
border_width_bottom = 3
|
||||
border_color = Color(0.677521, 0.850448, 0.731593, 1)
|
||||
corner_radius_top_left = 3
|
||||
corner_radius_top_right = 3
|
||||
corner_radius_bottom_right = 3
|
||||
corner_radius_bottom_left = 3
|
||||
corner_detail = 5
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_fxaw6"]
|
||||
content_margin_left = 4.0
|
||||
content_margin_top = 4.0
|
||||
content_margin_right = 4.0
|
||||
content_margin_bottom = 4.0
|
||||
bg_color = Color(0.826838, 0.64006, 0.825632, 0.6)
|
||||
border_width_left = 3
|
||||
border_width_top = 3
|
||||
border_width_right = 3
|
||||
border_width_bottom = 3
|
||||
border_color = Color(0.678431, 0.85098, 0.733333, 1)
|
||||
corner_radius_top_left = 3
|
||||
corner_radius_top_right = 3
|
||||
corner_radius_bottom_right = 3
|
||||
corner_radius_bottom_left = 3
|
||||
corner_detail = 5
|
||||
|
||||
[resource]
|
||||
default_font = ExtResource("1_8evya")
|
||||
default_font_size = 16
|
||||
Button/styles/normal = SubResource("StyleBoxFlat_jjd3u")
|
||||
Button/styles/pressed = SubResource("StyleBoxFlat_fxaw6")
|
||||
Label/colors/font_color = Color(0.800791, 0.644553, 0.798944, 1)
|
Loading…
Reference in a new issue