Split into category packages; module github.com/ZacharyZhang-NY/MujicaUI
This commit is contained in:
1822 files changed
+24568
-21314
No files matched your search
@@ -0,0 +1,169 @@
|
||||
package datetime
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/egoist/mygo/ui"
|
||||
|
||||
"github.com/ZacharyZhang-NY/MujicaUI/core"
|
||||
"github.com/ZacharyZhang-NY/MujicaUI/internal"
|
||||
"github.com/ZacharyZhang-NY/MujicaUI/theme"
|
||||
)
|
||||
|
||||
// YearViewOptions configure a YearView.
|
||||
type YearViewOptions struct {
|
||||
// Location is the zone days are cut in; required.
|
||||
Location *time.Location
|
||||
// Version must change when events change in place.
|
||||
Version int
|
||||
WeekStart WeekStart
|
||||
// Today is marked; zero uses the system clock.
|
||||
Today core.Date
|
||||
Disabled bool
|
||||
Label string
|
||||
}
|
||||
|
||||
// YearView shows twelve months with busy-day dots.
|
||||
func YearView(c *ui.Context, year *int, events []CalendarEvent, opts YearViewOptions) CalendarViewResult {
|
||||
loc := eventLocation("YearView", opts.Location)
|
||||
if *year < 1 {
|
||||
panic(fmt.Sprintf("mujica: YearView year %d is not valid", *year))
|
||||
}
|
||||
eventsCheck("YearView", events)
|
||||
d := core.Density(c)
|
||||
today := core.DatetimeToday(c, opts.Today)
|
||||
first := core.Date{Year: *year, Month: time.January, Day: 1}
|
||||
label := opts.Label
|
||||
if label == "" {
|
||||
label = strconv.Itoa(*year)
|
||||
}
|
||||
r := CalendarViewResult{}
|
||||
root := ui.Column(c).Gap(d.Unit() * 3).Role(ui.RoleGroup).Label(label).Disabled(opts.Disabled)
|
||||
r.Element = root
|
||||
counts := eventsDerived(root, "year-view-counts", events, opts.Version, eventDayStart(first, loc), eventDayStart(first.AddMonths(12), loc),
|
||||
func(hits []int) map[core.Date]int {
|
||||
m := map[core.Date]int{}
|
||||
for _, h := range hits {
|
||||
ev := events[h]
|
||||
for day := core.DateOf(ev.Start.In(loc)); eventDayStart(day, loc).Before(ev.End); day = day.AddDays(1) {
|
||||
m[day]++
|
||||
}
|
||||
}
|
||||
return m
|
||||
})
|
||||
cursor := ui.Local(root, "year-view-cursor", func() core.Date { return core.Date{} })
|
||||
if cursor.Year != *year {
|
||||
*cursor = core.Date{Year: *year, Month: today.Month, Day: min(today.Day, 28)}
|
||||
}
|
||||
root.Children(func() {
|
||||
calendarViewHeader(c, strconv.Itoa(*year), core.Msg(c, "calendar.prev_year"), core.Msg(c, "calendar.next_year"), func(dir int) {
|
||||
*year += dir
|
||||
})
|
||||
grid := ui.Row(c).Wrap().AlignItems(ui.Start).Gap(d.Unit() * 4).FocusGroup(ui.Horizontal | ui.Vertical)
|
||||
moved := false
|
||||
if !grid.IsDisabled() {
|
||||
for key, days := range map[ui.Key]int{ui.KeyLeft: -1, ui.KeyRight: 1, ui.KeyUp: -7, ui.KeyDown: 7} {
|
||||
if grid.Shortcut(0, key) {
|
||||
*cursor, moved = cursor.AddDays(days), true
|
||||
}
|
||||
}
|
||||
for key, months := range map[ui.Key]int{ui.KeyPageUp: -1, ui.KeyPageDown: 1} {
|
||||
if grid.Shortcut(0, key) {
|
||||
*cursor, moved = cursor.AddMonths(months), true
|
||||
}
|
||||
}
|
||||
if moved && cursor.Year != *year {
|
||||
*year = cursor.Year
|
||||
}
|
||||
}
|
||||
grid.Children(func() {
|
||||
for m := time.January; m <= time.December; m++ {
|
||||
if day, ok := yearMonth(c, *year, m, counts, today, *cursor, moved, opts.WeekStart); ok && !grid.IsDisabled() {
|
||||
r.day, *cursor = day, day
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
return r
|
||||
}
|
||||
|
||||
// yearMonth draws one small month and reports a day clicked.
|
||||
func yearMonth(c *ui.Context, year int, m time.Month, counts map[core.Date]int, today, cursor core.Date, focus bool, ws WeekStart) (core.Date, bool) {
|
||||
k := core.Tokens(c)
|
||||
cell := theme.MinHitSize
|
||||
first := CalendarFirstWeekday(c, ws)
|
||||
start := core.Date{Year: year, Month: m, Day: 1}
|
||||
lead := (int(start.Weekday()) - int(first) + 7) % 7
|
||||
var picked core.Date
|
||||
ui.Column(c).Width(cell * 7).Gap(2).Children(func() {
|
||||
ui.Text(c, core.DatetimeMonthName(c, m)).Font(theme.SerifFont).TextColor(k.Text).Bold()
|
||||
ui.Row(c).Children(func() {
|
||||
for i := range 7 {
|
||||
wd := (int(first) + i) % 7
|
||||
ui.Text(c, core.Msg(c, "calendar.weekday_"+strconv.Itoa(wd))).Width(cell).TextAlign(ui.Center).
|
||||
FontSize(core.FontSize(c, theme.CaptionSize)).TextColor(k.TextMuted)
|
||||
}
|
||||
})
|
||||
last := start.AddMonths(1).AddDays(-1).Day
|
||||
for w := 0; w*7 < lead+last; w++ {
|
||||
ui.Row(c).Children(func() {
|
||||
for i := range 7 {
|
||||
n := w*7 + i - lead + 1
|
||||
if n < 1 || n > last {
|
||||
ui.Box(c).Size(cell, cell)
|
||||
continue
|
||||
}
|
||||
day := core.Date{Year: year, Month: m, Day: n}
|
||||
busy := counts[day]
|
||||
text := core.DatetimeDayLabel(c, day)
|
||||
if busy > 0 {
|
||||
text += ", " + core.CalendarCount(c, "year_view.events", busy)
|
||||
}
|
||||
b := ui.ButtonBase(c).Size(cell, cell).Radius(theme.ControlRadius).Label(text).Column()
|
||||
internal.Ring(b, k.Focus, theme.ControlRadius)
|
||||
if day == cursor && focus {
|
||||
b.Focus()
|
||||
}
|
||||
switch {
|
||||
case day == today:
|
||||
b.Background(k.Selection)
|
||||
case b.Hovered():
|
||||
b.Background(k.SurfaceHover)
|
||||
}
|
||||
dots := yearDots(busy)
|
||||
b.Draw(func(p *ui.Painter, r ui.Rect) {
|
||||
x0 := r.X + r.W/2 - float32(dots*5-2)/2
|
||||
for j := range dots {
|
||||
p.Fill(ui.Rect{X: x0 + float32(j)*5, Y: r.Y + r.H - 6, W: 3, H: 3}, k.AccentText, 1.5)
|
||||
}
|
||||
})
|
||||
b.Children(func() {
|
||||
t := ui.Text(c, strconv.Itoa(n)).FontSize(core.FontSize(c, theme.CaptionSize)).TextColor(k.Text).FontFeatures("tnum")
|
||||
if day == today {
|
||||
t.Bold().TextColor(k.AccentText)
|
||||
}
|
||||
})
|
||||
if b.Clicked() {
|
||||
picked = day
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
return picked, !picked.IsZero()
|
||||
}
|
||||
|
||||
// yearDots maps an event count to one to three dots.
|
||||
func yearDots(n int) int {
|
||||
switch {
|
||||
case n == 0:
|
||||
return 0
|
||||
case n <= 2:
|
||||
return 1
|
||||
case n <= 5:
|
||||
return 2
|
||||
}
|
||||
return 3
|
||||
}
|
||||
Reference in new issue
Block a user