package cviewimport ()// Configuration values.const (ScrollRow = iotaScrollColumn)// scrollItem holds layout options for one item.type scrollItem struct { Item Primitive// The item to be positioned. May be nil for an empty item. FixedSize int// The item's fixed size which may not be changed, 0 if it has no fixed size. Focus bool// Whether or not this item attracts the layout's focus.}// ScrollView is a basic implementation of the Scrollbox layout. The contained// primitives are arranged horizontally or vertically. The way they are// distributed along that dimension depends on their layout settings, which is// either a fixed length or a proportional length. See AddItem() for details.typeScrollViewstruct { *Box// The items to be positioned. items []*scrollItem// // ScrollRow or ScrollColumn. // direction int// If set to true, ScrollView will use the entire screen as its available space // instead its box dimensions. fullScreen bool// Visibility of the scroll bar. scrollBarVisibility ScrollBarVisibility// The scroll bar color. scrollBarColor tcell.Color// The number of characters to be skipped on each line (not in wrap mode). heightOffset intsync.RWMutex}// NewScrollView returns a new scrollbox layout container with no primitives and its// direction set to ScrollColumn. To add primitives to this layout, see AddItem().// To change the direction, see SetDirection().//// Note that ScrollView will have a transparent background by default so that any nil// scroll items will show primitives behind the ScrollView.// To disable this transparency://// scroll.SetBackgroundTransparent(false)func () *ScrollView { := &ScrollView{Box: NewBox(),scrollBarVisibility: ScrollBarAuto,scrollBarColor: Styles.ScrollBarColor, } .SetBackgroundTransparent(true) .focus = return}// SetScrollBarVisibility specifies the display of the scroll bar.func ( *ScrollView) ( ScrollBarVisibility) { .Lock()defer .Unlock() .scrollBarVisibility = }// SetScrollBarColor sets the color of the scroll bar.func ( *ScrollView) ( tcell.Color) { .Lock()defer .Unlock() .scrollBarColor = }// SetFullScreen sets the flag which, when true, causes the scroll layout to use// the entire screen space instead of whatever size it is currently assigned to.func ( *ScrollView) ( bool) { .Lock()defer .Unlock() .fullScreen = }// GetItems returns a slice of all items in the container.func ( *ScrollView) () []Primitive { .RLock()defer .RUnlock()var []Primitivefor , := range .items { = append(, .Item) }return}// AddItem adds a new item to the container. The "fixedSize" argument is a width// or height that may not be changed by the layout algorithm. A value of 0 means// that its size is scrollible and may be changed. The "proportion" argument// defines the relative size of the item compared to other scrollible-size items.// For example, items with a proportion of 2 will be twice as large as items// with a proportion of 1. The proportion must be at least 1 if fixedSize == 0// (ignored otherwise).//// If "focus" is set to true, the item will receive focus when the ScrollView// primitive receives focus. If multiple items have the "focus" flag set to// true, the first one will receive focus.//// A nil value for the primitive represents empty space.func ( *ScrollView) ( Primitive, int, bool) { .Lock()defer .Unlock()if == nil { = NewBox() .SetVisible(false) } .items = append(.items, &scrollItem{Item: , FixedSize: , Focus: })}// AddItemAtIndex adds an item to the scroll at a given index.// For more information see AddItem.func ( *ScrollView) ( int, Primitive, int, bool) { .Lock()defer .Unlock() := &scrollItem{Item: , FixedSize: , Focus: }if == 0 { .items = append([]*scrollItem{}, .items...) } else { .items = append(.items[:], append([]*scrollItem{}, .items[:]...)...) }}// RemoveItem removes all items for the given primitive from the container,// keeping the order of the remaining items intact.func ( *ScrollView) ( Primitive) { .Lock()defer .Unlock()for := len(.items) - 1; >= 0; -- {if .items[].Item == { .items = append(.items[:], .items[+1:]...) } }}// ResizeItem sets a new size for the item(s) with the given primitive. If there// are multiple ScrollView items with the same primitive, they will all receive the// same size. For details regarding the size parameters, see AddItem().func ( *ScrollView) ( Primitive, int) { .Lock()defer .Unlock()for , := range .items {if .Item == { .FixedSize = } }}// Draw draws this primitive onto the screen.func ( *ScrollView) ( tcell.Screen) {if !.GetVisible() {return } .Box.Draw() .Lock()defer .Unlock()// Calculate size and position of the items.// Do we use the entire screen?if .fullScreen { , := .Size() .SetRect(0, 0, , ) }// How much space can we distribute? , , , := .GetInnerRect()// How tall is the content? := 0for , := range .items { += .FixedSize }if > && +.heightOffset+ > + { .heightOffset = - } := .scrollBarVisibility == ScrollBarAlways || (.scrollBarVisibility == ScrollBarAuto && > )if > 0 && { -- // Subtract space for scroll bar. }// draw := := := -1// TODO scroll to focused one when not visiblefor , := range .items { := .FixedSize// scrolledif < +.heightOffset && { += continue }if == -1 { = } += .Item.SetRect(, , , ) += if .Item != nil {if .Item.GetFocusable().HasFocus() {defer .Item.Draw() } else { .Item.Draw() } } }// fill the remaining spaceif < + {for := ; < +; ++ {for := 0; < ; ++ { .SetContent(, , ' ', nil, tcell.StyleDefault.Background(Styles.PrimitiveBackgroundColor)) } } }if ! {return }// Draw scroll bar last.deferfunc() { := int(float64() * (float64(-) / float64(-)))if > { = }for := 0; < ; ++ {RenderScrollBar(, .scrollBarVisibility, +, +, , , , , .hasFocus, .scrollBarColor) } }()}// ScrollTo scrolls to the specified height and width (both starting with 0).func ( *ScrollView) (, int) { .Lock()defer .Unlock() .heightOffset = // t.columnOffset = column // t.trackEnd = false}// Focus is called when this primitive receives focus.func ( *ScrollView) ( func( Primitive)) { .Lock()for , := range .items {if .Item != nil && .Focus { .Unlock() (.Item)return } } .Unlock()}// HasFocus returns whether or not this primitive has focus.func ( *ScrollView) () bool { .RLock()defer .RUnlock()for , := range .items {if .Item != nil && .Item.GetFocusable().HasFocus() {returntrue } }returnfalse}// MouseHandler returns the mouse handler for this primitive.func ( *ScrollView) () func( MouseAction, *tcell.EventMouse, func( Primitive)) ( bool, Primitive) {return .WrapMouseHandler(func( MouseAction, *tcell.EventMouse, func( Primitive)) ( bool, Primitive) {if !.InRect(.Position()) {returnfalse, nil }switch {caseMouseScrollUp: .heightOffset--if .heightOffset < 0 { .heightOffset = 0 } = truecaseMouseScrollDown: .heightOffset++ = true }if {return }// Pass mouse events along to the first child item that takes it.for , := range .items {if .Item == nil {continue } , = .Item.MouseHandler()(, , )if {return } }return })}
The pages are generated with Goldsv0.8.2. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds.