diff --git a/ui/ui.go b/ui/ui.go index a8e78a6..46d39b4 100644 --- a/ui/ui.go +++ b/ui/ui.go @@ -2825,19 +2825,19 @@ func Build() (*gowid.App, error) { maxViewPath = []interface{}{2, 0} // list, structure or hex - whichever one is selected mainviewPaths = [][]interface{}{ - {2, 0}, // packet list - {4}, // packet structure - {6}, // packet hex + {2}, // packet list + {4}, // packet structure + {6}, // packet hex } altview1Paths = [][]interface{}{ - {2, 0, 0, 0}, // packet list - {2, 0, 2}, // packet structure - {2, 2}, // packet hex + {2, 0, 0}, // packet list + {2, 0, 2}, // packet structure + {2, 2}, // packet hex } altview2Paths = [][]interface{}{ - {2, 0, 0}, // packet list + {2, 0}, // packet list {2, 2, 0}, // packet structure {2, 2, 2}, // packet hex } diff --git a/widgets/withscrollbar/withscrollbar.go b/widgets/withscrollbar/withscrollbar.go index 596e599..1447fe9 100644 --- a/widgets/withscrollbar/withscrollbar.go +++ b/widgets/withscrollbar/withscrollbar.go @@ -15,11 +15,18 @@ import ( //====================================================================== type Widget struct { - *columns.Widget + always *columns.Widget // use if scrollbar is to be shown w IScrollSubWidget sb *vscroll.Widget goUpDown int // positive means down pgUpDown int // positive means down + opt Options +} + +var _ gowid.IWidget = (*Widget)(nil) + +type Options struct { + HideIfContentFits bool } type IScrollValues interface { @@ -27,19 +34,33 @@ type IScrollValues interface { ScrollLength() int } -type IScrollSubWidget interface { - gowid.IWidget - IScrollValues +// Implemented by widgets that can scroll +type IScrollOneLine interface { Up(lines int, size gowid.IRenderSize, app gowid.IApp) Down(lines int, size gowid.IRenderSize, app gowid.IApp) +} + +type IScrollOnePage interface { UpPage(num int, size gowid.IRenderSize, app gowid.IApp) DownPage(num int, size gowid.IRenderSize, app gowid.IApp) } -func New(w IScrollSubWidget) *Widget { +type IScrollSubWidget interface { + gowid.IWidget + IScrollValues + IScrollOneLine + IScrollOnePage +} + +func New(w IScrollSubWidget, opts ...Options) *Widget { + var opt Options + if len(opts) > 0 { + opt = opts[0] + } + sb := vscroll.NewExt(vscroll.VerticalScrollbarUnicodeRunes) res := &Widget{ - Widget: columns.New([]gowid.IContainerWidget{ + always: columns.New([]gowid.IContainerWidget{ &gowid.ContainerWidget{ IWidget: w, D: gowid.RenderWithWeight{W: 1}, @@ -55,6 +76,7 @@ func New(w IScrollSubWidget) *Widget { sb: sb, goUpDown: 0, pgUpDown: 0, + opt: opt, } sb.OnClickAbove(gowid.MakeWidgetCallback("cb", res.clickUp)) sb.OnClickBelow(gowid.MakeWidgetCallback("cb", res.clickDown)) @@ -84,7 +106,19 @@ func CalculateMenuRows(vals IScrollValues, rows int, focus gowid.Selector, app g return vals.ScrollPosition(), 1, vals.ScrollLength() - (vals.ScrollPosition() + 1) } +func (w *Widget) contentFits(size gowid.IRenderSize) bool { + res := true + if rower, ok := size.(gowid.IRows); ok { + res = (w.w.ScrollLength() <= rower.Rows()) + } + return res +} + func (w *Widget) UserInput(ev interface{}, size gowid.IRenderSize, focus gowid.Selector, app gowid.IApp) bool { + if w.opt.HideIfContentFits && w.contentFits(size) { + return w.w.UserInput(ev, size, focus, app) + } + box, ok := size.(gowid.IRenderBox) if !ok { panic(gowid.WidgetSizeError{Widget: w, Size: size, Required: "gowid.IRenderBox"}) @@ -96,14 +130,18 @@ func (w *Widget) UserInput(ev interface{}, size gowid.IRenderSize, focus gowid.S w.sb.Middle = y w.sb.Bottom = z - res := w.Widget.UserInput(ev, size, focus, app) + res := w.always.UserInput(ev, size, focus, app) if res { - w.Widget.SetFocus(app, 0) + w.always.SetFocus(app, 0) } return res } func (w *Widget) Render(size gowid.IRenderSize, focus gowid.Selector, app gowid.IApp) gowid.ICanvas { + if w.opt.HideIfContentFits && w.contentFits(size) { + return w.w.Render(size, focus, app) + } + box, ok := size.(gowid.IRenderBox) if !ok { panic(gowid.WidgetSizeError{Widget: w, Size: size, Required: "gowid.IRenderBox"}) @@ -136,11 +174,23 @@ func (w *Widget) Render(size gowid.IRenderSize, focus gowid.Selector, app gowid. w.sb.Middle = y w.sb.Bottom = z - canvas := w.Widget.Render(size, focus, app) + canvas := w.always.Render(size, focus, app) return canvas } +func (w *Widget) RenderSize(size gowid.IRenderSize, focus gowid.Selector, app gowid.IApp) gowid.IRenderBox { + if w.opt.HideIfContentFits && w.contentFits(size) { + return w.w.RenderSize(size, focus, app) + } + + return w.always.RenderSize(size, focus, app) +} + +func (w *Widget) Selectable() bool { + return w.w.Selectable() +} + //====================================================================== // Local Variables: // mode: Go diff --git a/widgets/withscrollbar/withscrollbar_test.go b/widgets/withscrollbar/withscrollbar_test.go new file mode 100644 index 0000000..aa7ec2b --- /dev/null +++ b/widgets/withscrollbar/withscrollbar_test.go @@ -0,0 +1,82 @@ +package withscrollbar + +import ( + "fmt" + "strings" + "testing" + + "github.com/gcla/gowid" + "github.com/gcla/gowid/gwtest" + "github.com/gcla/gowid/widgets/button" + "github.com/gcla/gowid/widgets/list" + "github.com/gcla/gowid/widgets/text" + "github.com/stretchr/testify/assert" +) + +type scrollingListBox struct { + *list.Widget +} + +func (t *scrollingListBox) Up(lines int, size gowid.IRenderSize, app gowid.IApp) {} +func (t *scrollingListBox) Down(lines int, size gowid.IRenderSize, app gowid.IApp) {} +func (t *scrollingListBox) UpPage(num int, size gowid.IRenderSize, app gowid.IApp) {} +func (t *scrollingListBox) DownPage(num int, size gowid.IRenderSize, app gowid.IApp) {} + +func (t *scrollingListBox) ScrollLength() int { + return 8 +} + +func (t *scrollingListBox) ScrollPosition() int { + return 0 +} + +func Test1(t *testing.T) { + bws := make([]gowid.IWidget, 8) + for i := 0; i < len(bws); i++ { + bws[i] = button.NewBare(text.New(fmt.Sprintf("%03d", i))) + } + + walker := list.NewSimpleListWalker(bws) + lbox := &scrollingListBox{Widget: list.New(walker)} + sbox := New(lbox) + + canvas1 := sbox.Render(gowid.MakeRenderBox(4, 8), gowid.NotSelected, gwtest.D) + res := strings.Join([]string{ + "000▲", + "001█", + "002 ", + "003 ", + "004 ", + "005 ", + "006 ", + "007▼", + }, "\n") + assert.Equal(t, res, canvas1.String()) + + sbox = New(lbox, Options{ + HideIfContentFits: true, + }) + + canvas1 = sbox.Render(gowid.MakeRenderBox(4, 8), gowid.NotSelected, gwtest.D) + res = strings.Join([]string{ + "000 ", + "001 ", + "002 ", + "003 ", + "004 ", + "005 ", + "006 ", + "007 ", + }, "\n") + assert.Equal(t, res, canvas1.String()) + + canvas1 = sbox.Render(gowid.MakeRenderBox(4, 5), gowid.NotSelected, gwtest.D) + res = strings.Join([]string{ + "000▲", + "001█", + "002 ", + "003 ", + "004▼", + }, "\n") + assert.Equal(t, res, canvas1.String()) +}