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
					
				
					 1 changed files with 120 additions and 2 deletions
				
			
		
							
								
								
									
										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…
	
	Add table
		
		Reference in a new issue
	
	 Petar Kapriš
						Petar Kapriš