rui_orig/listLayout.go

284 lines
8.3 KiB
Go

package rui
import (
"strings"
)
// Constants which represent values of the "orientation" property of the [ListLayout]
const (
// TopDownOrientation - subviews are arranged from top to bottom. Synonym of VerticalOrientation
TopDownOrientation = 0
// StartToEndOrientation - subviews are arranged from left to right. Synonym of HorizontalOrientation
StartToEndOrientation = 1
// BottomUpOrientation - subviews are arranged from bottom to top
BottomUpOrientation = 2
// EndToStartOrientation - subviews are arranged from right to left
EndToStartOrientation = 3
)
// Constants which represent values of the "list-wrap" property of the [ListLayout]
const (
// ListWrapOff - subviews are scrolled and "true" if a new row/column starts
ListWrapOff = 0
// ListWrapOn - the new row/column starts at bottom/right
ListWrapOn = 1
// ListWrapReverse - the new row/column starts at top/left
ListWrapReverse = 2
)
// ListLayout represents a ListLayout view
type ListLayout interface {
ViewsContainer
// UpdateContent updates child Views if the "content" property value is set to ListAdapter,
// otherwise does nothing
UpdateContent()
}
type listLayoutData struct {
viewsContainerData
adapter ListAdapter
}
// NewListLayout create new ListLayout object and return it
func NewListLayout(session Session, params Params) ListLayout {
view := new(listLayoutData)
view.init(session)
setInitParams(view, params)
return view
}
func newListLayout(session Session) View {
//return NewListLayout(session, nil)
return new(listLayoutData)
}
// Init initialize fields of ViewsAlignContainer by default values
func (listLayout *listLayoutData) init(session Session) {
listLayout.viewsContainerData.init(session)
listLayout.tag = "ListLayout"
listLayout.systemClass = "ruiListLayout"
listLayout.normalize = normalizeListLayoutTag
listLayout.get = listLayout.getFunc
listLayout.set = listLayout.setFunc
listLayout.remove = listLayout.removeFunc
listLayout.changed = listLayout.propertyChanged
}
func normalizeListLayoutTag(tag PropertyName) PropertyName {
tag = defaultNormalize(tag)
switch tag {
case "wrap":
tag = ListWrap
case "row-gap":
return ListRowGap
case ColumnGap:
return ListColumnGap
}
return tag
}
func (listLayout *listLayoutData) getFunc(tag PropertyName) any {
switch tag {
case Gap:
if rowGap := GetListRowGap(listLayout); rowGap.Equal(GetListColumnGap(listLayout)) {
return rowGap
}
return AutoSize()
case Content:
if listLayout.adapter != nil {
return listLayout.adapter
}
}
return listLayout.viewsContainerData.getFunc(tag)
}
func (listLayout *listLayoutData) removeFunc(tag PropertyName) []PropertyName {
switch tag {
case Gap:
result := []PropertyName{}
for _, tag := range []PropertyName{ListRowGap, ListColumnGap} {
if listLayout.getRaw(tag) != nil {
listLayout.setRaw(tag, nil)
result = append(result, tag)
}
}
return result
case Content:
listLayout.viewsContainerData.removeFunc(Content)
listLayout.adapter = nil
return []PropertyName{Content}
}
return listLayout.viewsContainerData.removeFunc(tag)
}
func (listLayout *listLayoutData) setFunc(tag PropertyName, value any) []PropertyName {
switch tag {
case Gap:
result := listLayout.setFunc(ListRowGap, value)
if result != nil {
if gap := listLayout.getRaw(ListRowGap); gap != nil {
listLayout.setRaw(ListColumnGap, gap)
result = append(result, ListColumnGap)
}
}
return result
case Content:
if adapter, ok := value.(ListAdapter); ok {
listLayout.adapter = adapter
listLayout.createContent()
} else if listLayout.setContent(value) {
listLayout.adapter = nil
} else {
return nil
}
return []PropertyName{Content}
}
return listLayout.viewsContainerData.setFunc(tag, value)
}
func (listLayout *listLayoutData) propertyChanged(tag PropertyName) {
switch tag {
case Orientation, ListWrap, HorizontalAlign, VerticalAlign:
updateCSSStyle(listLayout.htmlID(), listLayout.Session())
default:
listLayout.viewsContainerData.propertyChanged(tag)
}
}
func (listLayout *listLayoutData) htmlSubviews(self View, buffer *strings.Builder) {
if listLayout.views != nil {
for _, view := range listLayout.views {
view.addToCSSStyle(map[string]string{`flex`: `0 0 auto`})
viewHTML(view, buffer, "")
}
}
}
func (listLayout *listLayoutData) createContent() bool {
if adapter := listLayout.adapter; adapter != nil {
listLayout.views = []View{}
session := listLayout.session
htmlID := listLayout.htmlID()
isDisabled := IsDisabled(listLayout)
count := adapter.ListSize()
for i := 0; i < count; i++ {
if view := adapter.ListItem(i, session); view != nil {
view.setParentID(htmlID)
if isDisabled {
view.Set(Disabled, true)
}
listLayout.views = append(listLayout.views, view)
}
}
return true
}
return false
}
func (listLayout *listLayoutData) UpdateContent() {
if listLayout.createContent() {
if listLayout.created {
updateInnerHTML(listLayout.htmlID(), listLayout.session)
}
if listener, ok := listLayout.changeListener[Content]; ok {
listener(listLayout, Content)
}
}
}
// GetListVerticalAlign returns the vertical align of a ListLayout or ListView sibview:
// TopAlign (0), BottomAlign (1), CenterAlign (2), or StretchAlign (3)
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
func GetListVerticalAlign(view View, subviewID ...string) int {
return enumStyledProperty(view, subviewID, VerticalAlign, TopAlign, false)
}
// GetListHorizontalAlign returns the vertical align of a ListLayout or ListView subview:
// LeftAlign (0), RightAlign (1), CenterAlign (2), or StretchAlign (3)
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
func GetListHorizontalAlign(view View, subviewID ...string) int {
return enumStyledProperty(view, subviewID, HorizontalAlign, LeftAlign, false)
}
// GetListOrientation returns the orientation of a ListLayout or ListView subview:
// TopDownOrientation (0), StartToEndOrientation (1), BottomUpOrientation (2), or EndToStartOrientation (3)
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
func GetListOrientation(view View, subviewID ...string) int {
if len(subviewID) > 0 && subviewID[0] != "" {
view = ViewByID(view, subviewID[0])
}
if view != nil {
if orientation, ok := valueToOrientation(view.Get(Orientation), view.Session()); ok {
return orientation
}
if value := valueFromStyle(view, Orientation); value != nil {
if orientation, ok := valueToOrientation(value, view.Session()); ok {
return orientation
}
}
}
return 0
}
// GetListWrap returns the wrap type of a ListLayout or ListView subview:
// ListWrapOff (0), ListWrapOn (1), or ListWrapReverse (2)
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
func GetListWrap(view View, subviewID ...string) int {
return enumStyledProperty(view, subviewID, ListWrap, ListWrapOff, false)
}
// GetListRowGap returns the gap between ListLayout or ListView rows.
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
func GetListRowGap(view View, subviewID ...string) SizeUnit {
return sizeStyledProperty(view, subviewID, ListRowGap, false)
}
// GetListColumnGap returns the gap between ListLayout or ListView columns.
// If the second argument (subviewID) is not specified or it is "" then a value from the first argument (view) is returned.
func GetListColumnGap(view View, subviewID ...string) SizeUnit {
return sizeStyledProperty(view, subviewID, ListColumnGap, false)
}
// UpdateContent updates child Views of ListLayout/GridLayout subview if the "content" property value is set to ListAdapter/GridAdapter,
// otherwise does nothing.
// If the second argument (subviewID) is not specified or it is "" then the first argument (view) updates.
func UpdateContent(view View, subviewID ...string) {
if len(subviewID) > 0 && subviewID[0] != "" {
view = ViewByID(view, subviewID[0])
}
if view != nil {
switch view := view.(type) {
case GridLayout:
view.UpdateGridContent()
case ListLayout:
view.UpdateContent()
case ListView:
view.ReloadListViewData()
}
}
}