Enable motion with HJKL keys
This commit will enable the user of the program to navigate the dates within a given year, using vi-like keybindings. The movement between months should act intuitively across different sizes of the terminal.
This commit is contained in:
parent
394c8f9b9d
commit
ce66ae9f21
122
Main.go
122
Main.go
|
@ -63,6 +63,14 @@ func date(year int, month time.Month, day int) time.Time {
|
||||||
return time.Date(year, month, day, 0, 0, 0, 0, time.Local)
|
return time.Date(year, month, day, 0, 0, 0, 0, time.Local)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func lastDay(m time.Month) time.Time {
|
||||||
|
return date(selTime.Year(), m+1, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func monthHeight(m time.Month) int {
|
||||||
|
return (offset(m) + lastDay(m).Day() - 1) / 7
|
||||||
|
}
|
||||||
|
|
||||||
func centeredText(s string, x, y, width int, scr tcell.Screen, style tcell.Style) {
|
func centeredText(s string, x, y, width int, scr tcell.Screen, style tcell.Style) {
|
||||||
start := x + max((width-utf8.RuneCountInString(s))/2, 0)
|
start := x + max((width-utf8.RuneCountInString(s))/2, 0)
|
||||||
i := 0
|
i := 0
|
||||||
|
@ -93,6 +101,105 @@ func wrappedText(s string, scr tcell.Screen, style tcell.Style) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 = date(selTime.Year(), m, day)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func topOfMonth(m time.Month, w time.Weekday) (time time.Time) {
|
||||||
|
first := date(selTime.Year(), m, 1)
|
||||||
|
day := 1
|
||||||
|
|
||||||
|
if w < first.Weekday() {
|
||||||
|
day += 7
|
||||||
|
}
|
||||||
|
|
||||||
|
day += int(w - first.Weekday())
|
||||||
|
|
||||||
|
time = date(selTime.Year(), m, day)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func moveUp() {
|
||||||
|
weekday := selTime.Weekday()
|
||||||
|
newTime := selTime.AddDate(0, 0, -7)
|
||||||
|
if newTime.Month() == selTime.Month() {
|
||||||
|
selTime = newTime
|
||||||
|
} else if int(selTime.Month()) > monthsWide {
|
||||||
|
newMonth := selTime.Month() - time.Month(monthsWide)
|
||||||
|
selTime = bottomOfMonth(newMonth, weekday)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func moveDown() {
|
||||||
|
weekday := selTime.Weekday()
|
||||||
|
newTime := selTime.AddDate(0, 0, +7)
|
||||||
|
if newTime.Month() == selTime.Month() {
|
||||||
|
selTime = newTime
|
||||||
|
} else if int(selTime.Month()) <= (12-1)/monthsWide*monthsWide {
|
||||||
|
newMonth := selTime.Month() + time.Month(monthsWide)
|
||||||
|
selTime = topOfMonth(newMonth, weekday)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func offset(m time.Month) int {
|
||||||
|
return (int(date(selTime.Year(), m, 1).Weekday()) + 6) % 7
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
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 date(selTime.Year(), m, 1)
|
||||||
|
}
|
||||||
|
if row > monthHeight(m) {
|
||||||
|
row = monthHeight(m)
|
||||||
|
}
|
||||||
|
|
||||||
|
day := row*7 + 1 - offset(m)
|
||||||
|
|
||||||
|
return date(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 date(selTime.Year(), m, day)
|
||||||
|
}
|
||||||
|
|
||||||
|
func moveRight() {
|
||||||
|
if selTime.Weekday() != time.Sunday && selTime.Day() != lastDay(selTime.Month()).Day() {
|
||||||
|
selTime = selTime.AddDate(0, 0, 1)
|
||||||
|
} else if int(selTime.Month())%monthsWide != 0 {
|
||||||
|
selTime = leftmostInRow(selTime.Month()+1, rowInMonth(selTime.Month(), selTime.Day()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func moveLeft() {
|
||||||
|
if selTime.Weekday() != time.Monday && selTime.Day() != 1 {
|
||||||
|
selTime = selTime.AddDate(0, 0, -1)
|
||||||
|
} else if int(selTime.Month())%monthsWide != 1 && monthsWide != 1 { // special case, if monthsWide
|
||||||
|
// is 1, (x%monthsWide) is 0
|
||||||
|
selTime = rightmostInRow(selTime.Month()-1, rowInMonth(selTime.Month(), selTime.Day()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func drawMonth(m time.Month, x, y int) {
|
func drawMonth(m time.Month, x, y int) {
|
||||||
centeredText(months[m], x, y, maxMonthWidth, wall, defStyle)
|
centeredText(months[m], x, y, maxMonthWidth, wall, defStyle)
|
||||||
|
|
||||||
|
@ -181,13 +288,24 @@ func main() {
|
||||||
// Process event
|
// Process event
|
||||||
switch ev := ev.(type) {
|
switch ev := ev.(type) {
|
||||||
case *tcell.EventResize:
|
case *tcell.EventResize:
|
||||||
drawWall()
|
|
||||||
wall.Sync()
|
|
||||||
case *tcell.EventKey:
|
case *tcell.EventKey:
|
||||||
if ev.Key() == tcell.KeyEscape || ev.Key() == tcell.KeyCtrlC ||
|
if ev.Key() == tcell.KeyEscape || ev.Key() == tcell.KeyCtrlC ||
|
||||||
ev.Rune() == 'Q' || ev.Rune() == 'q' {
|
ev.Rune() == 'Q' || ev.Rune() == 'q' {
|
||||||
quit()
|
quit()
|
||||||
}
|
}
|
||||||
|
switch ev.Rune() {
|
||||||
|
case 'h':
|
||||||
|
moveLeft()
|
||||||
|
case 'j':
|
||||||
|
moveDown()
|
||||||
|
case 'k':
|
||||||
|
moveUp()
|
||||||
|
case 'l':
|
||||||
|
moveRight()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
drawWall()
|
||||||
|
wall.Sync()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue