package cviewimport ()// Configuration values.const (FlexRow = iotaFlexColumn)// flexItem holds layout options for one item.type flexItem 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. Proportion int// The item's proportion. Focus bool// Whether or not this item attracts the layout's focus.}// Flex is a basic implementation of the Flexbox 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.typeFlexstruct { *Box// The items to be positioned. items []*flexItem// FlexRow or FlexColumn. direction int// If set to true, Flex will use the entire screen as its available space // instead its box dimensions. fullScreen boolsync.RWMutex}// NewFlex returns a new flexbox layout container with no primitives and its// direction set to FlexColumn. To add primitives to this layout, see AddItem().// To change the direction, see SetDirection().//// Note that Flex will have a transparent background by default so that any nil// flex items will show primitives behind the Flex.// To disable this transparency://// flex.SetBackgroundTransparent(false)func () *Flex { := &Flex{Box: NewBox(),direction: FlexColumn, } .SetBackgroundTransparent(true) .focus = return}// GetDirection returns the direction in which the contained primitives are// distributed. This can be either FlexColumn (default) or FlexRow.func ( *Flex) () int { .RLock()defer .RUnlock()return .direction}// SetDirection sets the direction in which the contained primitives are// distributed. This can be either FlexColumn (default) or FlexRow.func ( *Flex) ( int) { .Lock()defer .Unlock() .direction = }// SetFullScreen sets the flag which, when true, causes the flex layout to use// the entire screen space instead of whatever size it is currently assigned to.func ( *Flex) ( bool) { .Lock()defer .Unlock() .fullScreen = }// 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 flexible and may be changed. The "proportion" argument// defines the relative size of the item compared to other flexible-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 Flex// 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 ( *Flex) ( Primitive, , int, bool) { .Lock()defer .Unlock()if == nil { = NewBox() .SetVisible(false) } .items = append(.items, &flexItem{Item: , FixedSize: , Proportion: , Focus: })}// AddItemAtIndex adds an item to the flex at a given index.// For more information see AddItem.func ( *Flex) ( int, Primitive, , int, bool) { .Lock()defer .Unlock() := &flexItem{Item: , FixedSize: , Proportion: , Focus: }if == 0 { .items = append([]*flexItem{}, .items...) } else { .items = append(.items[:], append([]*flexItem{}, .items[:]...)...) }}// RemoveItem removes all items for the given primitive from the container,// keeping the order of the remaining items intact.func ( *Flex) ( 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 Flex items with the same primitive, they will all receive the// same size. For details regarding the size parameters, see AddItem().func ( *Flex) ( Primitive, , int) { .Lock()defer .Unlock()for , := range .items {if .Item == { .FixedSize = .Proportion = } }}// Draw draws this primitive onto the screen.func ( *Flex) ( 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()varint := if .direction == FlexRow { = }for , := range .items {if .FixedSize > 0 { -= .FixedSize } else { += .Proportion } }// Calculate positions and draw items. := if .direction == FlexRow { = }for , := range .items { := .FixedSizeif <= 0 {if > 0 { = * .Proportion / -= -= .Proportion } else { = 0 } }if .Item != nil {if .direction == FlexColumn { .Item.SetRect(, , , ) } else { .Item.SetRect(, , , ) } } += if .Item != nil {if .Item.GetFocusable().HasFocus() {defer .Item.Draw() } else { .Item.Draw() } } }}// Focus is called when this primitive receives focus.func ( *Flex) ( func( Primitive)) { .Lock()for , := range .items {if .Item != nil && .Focus { .Unlock() (.Item)return } } .Unlock()}// HasFocus returns whether or not this primitive has focus.func ( *Flex) () bool { .RLock()defer .RUnlock()for , := range .items {if .Item != nil && .Item.GetFocusable().HasFocus() {returntrue } }returnfalse}// MouseHandler returns the mouse handler for this primitive.func ( *Flex) () func( MouseAction, *tcell.EventMouse, func( Primitive)) ( bool, Primitive) {return .WrapMouseHandler(func( MouseAction, *tcell.EventMouse, func( Primitive)) ( bool, Primitive) {if !.InRect(.Position()) {returnfalse, nil }// 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.