193 lines
4.8 KiB
Go
193 lines
4.8 KiB
Go
package drw
|
||
|
||
import (
|
||
"strconv"
|
||
"time"
|
||
|
||
"github.com/gdamore/tcell/v2"
|
||
|
||
"gitlab.com/tvrdosrz/ck/util"
|
||
)
|
||
|
||
const (
|
||
dayWidth = 2
|
||
smallGap = 1
|
||
largeGap = 3
|
||
maxMonthWidth = 7*dayWidth + 6*smallGap
|
||
maxMonthHeight = (31+6+(7-1))/7 + 2
|
||
/* maxMonthHeight is the height of a 31-day month starting on Sunday (month
|
||
name and weekdays included) */
|
||
|
||
titleHeight = smallGap + 1
|
||
)
|
||
|
||
var (
|
||
Wall tcell.Screen
|
||
|
||
monthsWide int
|
||
monthsHigh int
|
||
monthsDrawn int
|
||
)
|
||
|
||
func offset(m time.Month) int {
|
||
return (int(util.Date(util.SelTime.Year(), m, 1).Weekday()) + 6) % 7
|
||
|
||
}
|
||
|
||
func lastDay(m time.Month) time.Time {
|
||
return util.Date(util.SelTime.Year(), m+1, 0)
|
||
}
|
||
|
||
func monthHeight(m time.Month) int {
|
||
return (offset(m) + lastDay(m).Day() - 1) / 7
|
||
}
|
||
|
||
func bottomOfMonth(m time.Month, w time.Weekday) (time time.Time) {
|
||
last := lastDay(m)
|
||
|
||
day := last.Day()
|
||
if w > last.Weekday() {
|
||
day -= 7
|
||
}
|
||
|
||
day += int(w - last.Weekday())
|
||
|
||
time = util.Date(util.SelTime.Year(), m, day)
|
||
return
|
||
}
|
||
|
||
func topOfMonth(m time.Month, w time.Weekday) (time time.Time) {
|
||
first := util.Date(util.SelTime.Year(), m, 1)
|
||
day := 1
|
||
|
||
if w < first.Weekday() {
|
||
day += 7
|
||
}
|
||
|
||
day += int(w - first.Weekday())
|
||
|
||
time = util.Date(util.SelTime.Year(), m, day)
|
||
return
|
||
}
|
||
|
||
func rowInMonth(m time.Month, day int) int {
|
||
return (day + offset(m) - 1) / 7
|
||
}
|
||
|
||
func leftmostInRow(m time.Month, row int) time.Time {
|
||
if row == 0 {
|
||
return util.Date(util.SelTime.Year(), m, 1)
|
||
}
|
||
if row > monthHeight(m) {
|
||
row = monthHeight(m)
|
||
}
|
||
|
||
day := row*7 + 1 - offset(m)
|
||
|
||
return util.Date(util.SelTime.Year(), m, day)
|
||
}
|
||
|
||
func rightmostInRow(m time.Month, row int) time.Time {
|
||
if row >= monthHeight(m) {
|
||
return lastDay(m)
|
||
}
|
||
|
||
day := row*7 + 7 - offset(m)
|
||
|
||
return util.Date(util.SelTime.Year(), m, day)
|
||
}
|
||
|
||
func MoveUp() {
|
||
weekday := util.SelTime.Weekday()
|
||
newTime := util.SelTime.AddDate(0, 0, -7)
|
||
if newTime.Month() == util.SelTime.Month() {
|
||
util.SelTime = newTime
|
||
} else if int(util.SelTime.Month())-monthsWide >= 1 {
|
||
newMonth := util.SelTime.Month() - time.Month(monthsWide)
|
||
util.SelTime = bottomOfMonth(newMonth, weekday)
|
||
}
|
||
}
|
||
|
||
func MoveDown() {
|
||
weekday := util.SelTime.Weekday()
|
||
newTime := util.SelTime.AddDate(0, 0, +7)
|
||
if newTime.Month() == util.SelTime.Month() {
|
||
util.SelTime = newTime
|
||
} else if int(util.SelTime.Month())+monthsWide <= 12 {
|
||
newMonth := util.SelTime.Month() + time.Month(monthsWide)
|
||
util.SelTime = topOfMonth(newMonth, weekday)
|
||
}
|
||
}
|
||
|
||
func MoveRight() {
|
||
if util.SelTime.Weekday() != time.Sunday && util.SelTime.Day() != lastDay(util.SelTime.Month()).Day() {
|
||
util.SelTime = util.SelTime.AddDate(0, 0, 1)
|
||
} else if int(util.SelTime.Month())%monthsWide != 0 && util.SelTime.Month() != time.December {
|
||
util.SelTime = leftmostInRow(util.SelTime.Month()+1, rowInMonth(util.SelTime.Month(), util.SelTime.Day()))
|
||
}
|
||
}
|
||
|
||
func MoveLeft() {
|
||
if util.SelTime.Weekday() != time.Monday && util.SelTime.Day() != 1 {
|
||
util.SelTime = util.SelTime.AddDate(0, 0, -1)
|
||
} else if int(util.SelTime.Month())%monthsWide != 1 && monthsWide != 1 { // special case, if monthsWide
|
||
// is 1, (x%monthsWide) is 0
|
||
util.SelTime = rightmostInRow(util.SelTime.Month()-1, rowInMonth(util.SelTime.Month(), util.SelTime.Day()))
|
||
}
|
||
}
|
||
|
||
func drawMonth(m time.Month, x, y int) {
|
||
centeredText(months[m], x, y, maxMonthWidth, Wall, DefStyle)
|
||
|
||
for i := 1; i <= 7; i++ {
|
||
centeredText(weekdays[i%7], x+(i-1)*(dayWidth+smallGap), y+1, dayWidth, Wall, DefStyle)
|
||
}
|
||
|
||
dayNum := util.Date(util.SelTime.Year(), m+1, 0).Day()
|
||
for i := 1; i <= dayNum; i++ {
|
||
weekday := int(util.Date(util.SelTime.Year(), m, i).Weekday())
|
||
style := DefStyle
|
||
if util.Today.Day() == i && util.Today.Month() == m {
|
||
style = TodayStyle
|
||
} else if util.SelTime.Day() == i && util.SelTime.Month() == m {
|
||
style = SelStyle
|
||
}
|
||
centeredText(
|
||
strconv.Itoa(i),
|
||
x+((weekday-1+7)%7)*(dayWidth+smallGap),
|
||
y+2,
|
||
2,
|
||
Wall,
|
||
style)
|
||
if weekday == 0 {
|
||
y++
|
||
}
|
||
}
|
||
}
|
||
|
||
func DrawWall() {
|
||
Wall.Clear()
|
||
w, h := Wall.Size()
|
||
if w < maxMonthWidth+2*smallGap || h < maxMonthHeight+2*smallGap+titleHeight {
|
||
wrappedText("Екран је премали за календар.", Wall, DefStyle) // The screen is too small for the calender
|
||
return
|
||
}
|
||
monthsWide = (w - 2*smallGap + largeGap) / (maxMonthWidth + largeGap)
|
||
monthsHigh = (h - smallGap - titleHeight) / (maxMonthHeight + smallGap)
|
||
monthsDrawn = util.Min(monthsHigh*monthsWide, 12)
|
||
|
||
startingMonth := time.Month((int(util.SelTime.Month())-1)/monthsDrawn*monthsDrawn + 1)
|
||
endingMonth := time.Month(util.Min(12, int(startingMonth)+monthsDrawn-1))
|
||
|
||
centerVert := (w - monthsWide*maxMonthWidth - (monthsWide-1)*largeGap) / 2
|
||
for i, m := 0, startingMonth; i < monthsHigh; i++ {
|
||
for j := 0; j < monthsWide; j++ {
|
||
drawMonth(m, centerVert+j*(maxMonthWidth+largeGap), titleHeight+smallGap+i*(maxMonthHeight+smallGap))
|
||
if m >= endingMonth {
|
||
return
|
||
}
|
||
m++
|
||
}
|
||
}
|
||
}
|