208 lines
4.2 KiB
Go
208 lines
4.2 KiB
Go
package main
|
|
|
|
import "fmt"
|
|
import "time"
|
|
import "bytes"
|
|
import "image"
|
|
import _ "embed"
|
|
import _ "image/png"
|
|
import "git.tebibyte.media/sashakoshka/stone"
|
|
import _ "git.tebibyte.media/sashakoshka/stone/backends/x"
|
|
|
|
//go:embed icon/icon64.png
|
|
var iconBytes []byte
|
|
|
|
var application = &stone.Application { }
|
|
|
|
var now time.Time
|
|
var viewingMonth int
|
|
var columns, rows int
|
|
|
|
var shortMonthNames = []string {
|
|
"",
|
|
"Jan",
|
|
"Feb",
|
|
"Mar",
|
|
"Apr",
|
|
"May",
|
|
"Jun",
|
|
"Jul",
|
|
"Aug",
|
|
"Sep",
|
|
"Oct",
|
|
"Nov",
|
|
"Dec",
|
|
}
|
|
|
|
func main () {
|
|
application.SetTitle("Calendar")
|
|
application.SetSize(20, 8)
|
|
|
|
icon, _, err := image.Decode(bytes.NewReader(iconBytes))
|
|
if err != nil { panic(err) }
|
|
application.SetIcon([]image.Image { icon })
|
|
|
|
application.OnStart(onStart)
|
|
application.OnResize(redraw)
|
|
application.OnPress(onPress)
|
|
application.OnScroll(onScroll)
|
|
|
|
err = application.Run()
|
|
if err != nil { panic(err) }
|
|
}
|
|
|
|
func onScroll (x, y int) {
|
|
viewingMonth += y * columns
|
|
application.Clear()
|
|
redraw()
|
|
application.Draw()
|
|
}
|
|
|
|
func onPress (button stone.Button, modifiers stone.Modifiers) {
|
|
switch button {
|
|
case stone.KeyUp:
|
|
viewingMonth -= columns
|
|
application.Clear()
|
|
redraw()
|
|
application.Draw()
|
|
case stone.KeyDown:
|
|
viewingMonth += columns
|
|
application.Clear()
|
|
redraw()
|
|
application.Draw()
|
|
case stone.KeyPageUp:
|
|
viewingMonth -= columns * rows
|
|
application.Clear()
|
|
redraw()
|
|
application.Draw()
|
|
case stone.KeyPageDown:
|
|
viewingMonth += columns * rows
|
|
application.Clear()
|
|
redraw()
|
|
application.Draw()
|
|
}
|
|
}
|
|
|
|
func onStart () {
|
|
now = time.Now()
|
|
viewingMonth = int(now.Month() - 1) + now.Year() * 12
|
|
redraw()
|
|
}
|
|
|
|
func redraw () {
|
|
width, height := application.Size()
|
|
|
|
monthIter := viewingMonth
|
|
rows = 0
|
|
columns = (width - 20) / 23 + 1
|
|
xOffset := (width - columns * 23) / 2 + 1
|
|
for y := 0; y < height; y += 10 {
|
|
for x := 0; x < width - 19; x += 23 {
|
|
drawMonth (
|
|
x + xOffset, y,
|
|
monthIter / 12,
|
|
time.Month(wrap(monthIter, 12) + 1))
|
|
monthIter ++
|
|
}
|
|
rows ++
|
|
}
|
|
}
|
|
|
|
func wrap (value, around int) (wrapped int) {
|
|
wrapped = value % around
|
|
if wrapped < 0 {
|
|
wrapped += around
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
func drawMonth (xOffset, yOffset, year int, month time.Month) {
|
|
current := month == now.Month() && year == now.Year()
|
|
|
|
bce := year < 0
|
|
if bce { year *= -1 }
|
|
|
|
var dateString string
|
|
dateString = fmt.Sprintf("%d ", year)
|
|
if bce { dateString += "BCE " }
|
|
dateString += month.String()
|
|
application.SetDot(xOffset + (20 - len(dateString)) / 2, yOffset)
|
|
fmt.Fprint(application, dateString)
|
|
|
|
var headerColor stone.Color
|
|
if current {
|
|
headerColor = stone.ColorRed
|
|
} else {
|
|
headerColor = stone.ColorForeground
|
|
}
|
|
for x := xOffset; x < 20 + xOffset; x ++ {
|
|
application.SetColor(x, yOffset, headerColor)
|
|
}
|
|
|
|
application.SetDot(xOffset, yOffset + 2)
|
|
fmt.Fprint (
|
|
application,
|
|
"S M T W Þ F S\n")
|
|
application.SetColor(xOffset, yOffset + 2, stone.ColorDim)
|
|
application.SetColor(xOffset + 18, yOffset + 2, stone.ColorDim)
|
|
|
|
dayIter := 0 - int(firstOfMonth(year, month).Weekday())
|
|
if dayIter <= -6 {
|
|
dayIter = 1
|
|
}
|
|
x, y, weekday := xOffset, yOffset + 3, 0
|
|
totalDays := daysInMonth(year, month)
|
|
for ; dayIter <= totalDays; dayIter ++ {
|
|
if dayIter > 0 {
|
|
application.SetDot(x, y)
|
|
fmt.Fprint(application, dayIter)
|
|
}
|
|
|
|
if current && dayIter == int(now.Day()) {
|
|
application.SetColor(x, y, stone.ColorRed)
|
|
application.SetColor(x + 1, y, stone.ColorRed)
|
|
} else if weekday == 0 || weekday == 6 {
|
|
application.SetColor(x, y, stone.ColorDim)
|
|
application.SetColor(x + 1, y, stone.ColorDim)
|
|
}
|
|
|
|
weekday = (weekday + 1) % 7
|
|
x += 3
|
|
if x > xOffset + 20 {
|
|
x = xOffset
|
|
y ++
|
|
}
|
|
}
|
|
}
|
|
|
|
func firstOfMonth (year int, month time.Month) (day time.Time) {
|
|
day = time.Date(year, month, 0, 0, 0, 0, 0, time.Local)
|
|
return
|
|
}
|
|
|
|
func daysInMonth (year int, month time.Month) (days int) {
|
|
switch month {
|
|
case 1: days = 31
|
|
case 2:
|
|
// betcha didn't know this about leap years
|
|
if year % 4 == 0 && (year % 100 != 0 || year % 400 == 0) {
|
|
days = 29
|
|
} else {
|
|
days = 28
|
|
}
|
|
case 3: days = 31
|
|
case 4: days = 30
|
|
case 5: days = 31
|
|
case 6: days = 30
|
|
case 7: days = 31
|
|
case 8: days = 31
|
|
case 9: days = 30
|
|
case 10: days = 31
|
|
case 11: days = 30
|
|
case 12: days = 31
|
|
}
|
|
|
|
return
|
|
}
|