package ui import ( "fmt" "strconv" "git.kirsle.net/go/render" ) // Pager is a frame with Pagers for paginated UI. type Pager struct { BaseWidget // Config settings. NOTE: these are copied in the constructor, // be sure to update it there too if you add a new option! Name string // totally optional name Page int // default 1 Pages int PerPage int // default 20 MaxPageButtons int // max no. of individual pages to show, 0 = no limit Font render.Text OnChange func(page, perPage int) supervisor *Supervisor child Widget buttons []Widget page string // radio button value of Page // Private options. hovering bool clicked bool } // NewPager creates a new Pager. func NewPager(config Pager) *Pager { w := &Pager{ Page: config.Page, Pages: config.Pages, PerPage: config.PerPage, MaxPageButtons: config.MaxPageButtons, Font: config.Font, OnChange: config.OnChange, buttons: []Widget{}, } // default settings if w.Page == 0 { w.Page = 1 } if w.PerPage == 0 { w.PerPage = 20 } w.IDFunc(func() string { return fmt.Sprintf("Pager<%d of %d>", w.Page, w.PerPage) }) w.child = w.setup() return w } // Supervise the pager to make its buttons work. func (w *Pager) Supervise(s *Supervisor) { w.supervisor = s for _, btn := range w.buttons { w.supervisor.Add(btn) } } // setup the frame func (w *Pager) setup() *Frame { frame := NewFrame("Pager Frame") frame.SetParent(w) if w.Pages == 0 { return frame } w.buttons = []Widget{} w.page = fmt.Sprintf("%d", w.Page) // Previous Page Button prev := NewButton("Previous", NewLabel(Label{ Text: "<", Font: w.Font, })) w.buttons = append(w.buttons, prev) prev.Handle(Click, func(ed EventData) error { return w.next(-1) }) frame.Pack(prev, Pack{ Side: W, }) // Draw the numbered buttons. for i := 1; i <= w.Pages; i++ { page := fmt.Sprintf("%d", i) if w.MaxPageButtons > 0 { if i > w.MaxPageButtons { break } // The final button shown; make this one always reflect the // current page IF the current page is greater than this one. if w.Page >= i && w.Page != i { continue } } btn := NewRadioButton( "Page "+page, &w.page, page, NewLabel(Label{ Text: page, Font: w.Font, })) w.buttons = append(w.buttons, btn) btn.Handle(Click, func(ed EventData) error { if w.OnChange != nil { page, _ := strconv.Atoi(w.page) w.OnChange(page, w.PerPage) } return nil }) if w.supervisor != nil { w.supervisor.Add(btn) } frame.Pack(btn, Pack{ Side: W, }) } // Next Page Button next := NewButton("Next", NewLabel(Label{ Text: ">", Font: w.Font, })) w.buttons = append(w.buttons, next) next.Handle(Click, func(ed EventData) error { return w.next(1) }) frame.Pack(next, Pack{ Side: W, }) return frame } // next (1) or previous (-1) button func (w *Pager) next(value int) error { fmt.Printf("next(%d)\n", value) intvalue, _ := strconv.Atoi(w.page) intvalue += value if intvalue < 1 { intvalue = 1 } else if intvalue > w.Pages { intvalue = w.Pages } w.page = fmt.Sprintf("%d", intvalue) if w.OnChange != nil { w.OnChange(intvalue, w.PerPage) } return nil } // Compute the size of the Pager. func (w *Pager) Compute(e render.Engine) { // Compute the size of the inner widget first. w.child.Compute(e) // Auto-resize only if we haven't been given a fixed size. if !w.FixedSize() { size := w.child.Size() w.Resize(render.Rect{ W: size.W + w.BoxThickness(2), H: size.H + w.BoxThickness(2), }) } w.BaseWidget.Compute(e) } // Present the Pager. func (w *Pager) Present(e render.Engine, P render.Point) { if w.Hidden() { return } w.Compute(e) var ( S = w.Size() ChildSize = w.child.Size() ) // Draw the widget's border and everything. w.DrawBox(e, P) // Offset further if we are currently sunken. var clickOffset int if w.clicked { clickOffset++ } // Where to place the child widget. moveTo := render.Point{ X: P.X + w.BoxThickness(1) + clickOffset, Y: P.Y + w.BoxThickness(1) + clickOffset, } // If we're bigger than we need to be, center the child widget. if S.Bigger(ChildSize) { moveTo.X = P.X + (S.W / 2) - (ChildSize.W / 2) } // Draw the text label inside. w.child.Present(e, moveTo) w.BaseWidget.Present(e, P) }