rui_orig/tabsLayout.go

896 lines
26 KiB
Go
Raw Permalink Normal View History

2021-09-07 17:36:50 +03:00
package rui
import (
"strconv"
"strings"
)
2024-11-13 12:56:39 +03:00
// Constants for [TabsLayout] specific view and events
2021-09-07 17:36:50 +03:00
const (
2021-11-17 12:32:37 +03:00
// CurrentTabChangedEvent is the constant for "current-tab-changed" property tag.
//
// Used by `TabsLayout`.
// Occur when the new tab becomes active.
//
// General listener format:
// `func(tabsLayout rui.TabsLayout, newTab, oldTab int)`.
//
// where:
// tabsLayout - Interface of a tabs layout which generated this event,
// newTab - Index of a new active tab,
// oldTab - Index of an old active tab.
//
// Allowed listener formats:
// `func(tabsLayout rui.TabsLayout, newTab int)`,
// `func(newTab, oldTab int)`,
// `func(newTab int)`,
// `func()`.
2024-11-13 12:56:39 +03:00
CurrentTabChangedEvent PropertyName = "current-tab-changed"
2021-11-17 12:32:37 +03:00
// Icon is the constant for "icon" property tag.
//
// Used by `TabsLayout`.
// Defines the icon name that is displayed in the tab. The property is set for the child view of `TabsLayout`.
//
// Supported types: `string`.
2021-11-17 12:32:37 +03:00
Icon = "icon"
// TabCloseButton is the constant for "tab-close-button" property tag.
//
// Used by `TabsLayout`.
2024-09-25 13:45:47 +03:00
// Controls whether to add close button to a tab(s). This property can be set separately for each child view or for tabs
// layout itself. Property set for child view takes precedence over the value set for tabs layout. Default value is
// `false`.
//
// Supported types: `bool`, `int`, `string`.
//
// Values:
// `true` or `1` or "true", "yes", "on", "1" - Tab(s) has close button.
// `false` or `0` or "false", "no", "off", "0" - No close button in tab(s).
2024-11-13 12:56:39 +03:00
TabCloseButton PropertyName = "tab-close-button"
2021-11-17 12:32:37 +03:00
// TabCloseEvent is the constant for "tab-close-event" property tag.
//
// Used by `TabsLayout`.
// Occurs when the user clicks on the tab close button.
//
// General listener format:
// `func(tabsLayout rui.TabsLayout, tab int)`.
//
// where:
// tabsLayout - Interface of a tabs layout which generated this event,
// tab - Index of the tab.
//
// Allowed listener formats:
// `func(tab int)`,
// `func(tabsLayout rui.TabsLayout)`,
// `func()`.
2024-11-13 12:56:39 +03:00
TabCloseEvent PropertyName = "tab-close-event"
2021-11-17 12:32:37 +03:00
// Tabs is the constant for "tabs" property tag.
//
// Used by `TabsLayout`.
// Sets where the tabs are located. Default value is "top".
//
// Supported types: `int`, `string`.
//
// Values:
// `0`(`TopTabs`) or "top" - Tabs on the top.
// `1`(`BottomTabs`) or "bottom" - Tabs on the bottom.
// `2`(`LeftTabs`) or "left" - Tabs on the left. Each tab is rotated 90° counterclockwise.
// `3`(`RightTabs`) or "right" - Tabs located on the right. Each tab is rotated 90° clockwise.
// `4`(`LeftListTabs`) or "left-list" - Tabs on the left. The tabs are displayed as a list.
// `5`(`RightListTabs`) or "right-list" - Tabs on the right. The tabs are displayed as a list.
// `6`(`HiddenTabs`) or "hidden" - Tabs are hidden.
2024-11-13 12:56:39 +03:00
Tabs PropertyName = "tabs"
2021-11-21 17:53:52 +03:00
// TabBarStyle is the constant for "tab-bar-style" property tag.
//
// Used by `TabsLayout`.
// Set the style for the display of the tab bar. The default value is "ruiTabBar".
//
// Supported types: `string`.
2024-11-13 12:56:39 +03:00
TabBarStyle PropertyName = "tab-bar-style"
2021-11-21 17:53:52 +03:00
// TabStyle is the constant for "tab-style" property tag.
//
// Used by `TabsLayout`.
// Set the style for the display of the tab. The default value is "ruiTab" or "ruiVerticalTab".
//
// Supported types: `string`.
2024-11-13 12:56:39 +03:00
TabStyle PropertyName = "tab-style"
2021-11-21 17:53:52 +03:00
// CurrentTabStyle is the constant for "current-tab-style" property tag.
//
// Used by `TabsLayout`.
2024-09-25 13:45:47 +03:00
// Set the style for the display of the current(selected) tab. The default value is "ruiCurrentTab" or
// "ruiCurrentVerticalTab".
//
// Supported types: `string`.
2024-11-13 12:56:39 +03:00
CurrentTabStyle PropertyName = "current-tab-style"
2021-11-21 17:53:52 +03:00
inactiveTabStyle = "data-inactiveTabStyle"
activeTabStyle = "data-activeTabStyle"
)
// Constants that are the values of the "tabs" property of a [TabsLayout]
const (
2021-09-07 17:36:50 +03:00
// TopTabs - tabs of TabsLayout are on the top
2021-11-17 12:32:37 +03:00
TopTabs = 0
2021-09-07 17:36:50 +03:00
// BottomTabs - tabs of TabsLayout are on the bottom
2021-11-17 12:32:37 +03:00
BottomTabs = 1
// LeftTabs - tabs of TabsLayout are on the left. Bookmarks are rotated counterclockwise 90 degrees.
LeftTabs = 2
// RightTabs - tabs of TabsLayout are on the right. Bookmarks are rotated clockwise 90 degrees.
RightTabs = 3
2021-09-07 17:36:50 +03:00
// LeftListTabs - tabs of TabsLayout are on the left
2021-11-17 12:32:37 +03:00
LeftListTabs = 4
2021-09-07 17:36:50 +03:00
// RightListTabs - tabs of TabsLayout are on the right
2021-11-17 12:32:37 +03:00
RightListTabs = 5
// HiddenTabs - tabs of TabsLayout are hidden
HiddenTabs = 6
)
2021-09-07 17:36:50 +03:00
// TabsLayout represents a TabsLayout view
2021-09-07 17:36:50 +03:00
type TabsLayout interface {
ViewsContainer
2021-11-17 12:32:37 +03:00
ListAdapter
2021-09-07 17:36:50 +03:00
}
type tabsLayoutData struct {
viewsContainerData
}
// NewTabsLayout create new TabsLayout object and return it
2022-04-02 11:42:03 +03:00
func NewTabsLayout(session Session, params Params) TabsLayout {
2021-09-07 17:36:50 +03:00
view := new(tabsLayoutData)
view.init(session)
2022-04-02 11:42:03 +03:00
setInitParams(view, params)
2021-09-07 17:36:50 +03:00
return view
}
func newTabsLayout(session Session) View {
2024-11-13 12:56:39 +03:00
//return NewTabsLayout(session, nil)
return new(tabsLayoutData)
2021-09-07 17:36:50 +03:00
}
// Init initialize fields of ViewsContainer by default values
func (tabsLayout *tabsLayoutData) init(session Session) {
tabsLayout.viewsContainerData.init(session)
2021-09-07 17:36:50 +03:00
tabsLayout.tag = "TabsLayout"
tabsLayout.systemClass = "ruiTabsLayout"
2024-11-13 12:56:39 +03:00
tabsLayout.set = tabsLayout.setFunc
tabsLayout.changed = tabsLayout.propertyChanged
2021-09-07 17:36:50 +03:00
}
2024-11-13 12:56:39 +03:00
func tabsLayoutCurrent(view View, defaultValue int) int {
result, _ := intProperty(view, Current, view.Session(), defaultValue)
2021-09-07 17:36:50 +03:00
return result
}
func (tabsLayout *tabsLayoutData) setFunc(tag PropertyName, value any) []PropertyName {
2021-11-17 12:32:37 +03:00
switch tag {
case CurrentTabChangedEvent:
return setTwoArgEventListener[TabsLayout, int](tabsLayout, tag, value)
2021-11-17 12:32:37 +03:00
case TabCloseEvent:
return setOneArgEventListener[TabsLayout, int](tabsLayout, tag, value)
2021-11-17 12:32:37 +03:00
case Current:
tabsLayout.setRaw("old-current", tabsLayoutCurrent(tabsLayout, -1))
2021-11-17 12:32:37 +03:00
2024-11-13 12:56:39 +03:00
if current, ok := value.(int); ok && current < 0 {
tabsLayout.setRaw(Current, nil)
2024-11-13 12:56:39 +03:00
return []PropertyName{tag}
2021-11-17 12:32:37 +03:00
}
return setIntProperty(tabsLayout, Current, value)
2021-11-17 12:32:37 +03:00
2024-11-13 12:56:39 +03:00
case TabStyle, CurrentTabStyle, TabBarStyle:
if text, ok := value.(string); ok {
return setStringPropertyValue(tabsLayout, tag, text)
2021-11-17 12:32:37 +03:00
}
2024-11-13 12:56:39 +03:00
notCompatibleType(tag, value)
return nil
2021-11-17 12:32:37 +03:00
}
return tabsLayout.viewsContainerData.setFunc(tag, value)
2021-11-17 12:32:37 +03:00
}
func (tabsLayout *tabsLayoutData) propertyChanged(tag PropertyName) {
2021-09-07 17:36:50 +03:00
switch tag {
case Current:
session := tabsLayout.Session()
current := GetCurrent(tabsLayout)
session.callFunc("activateTab", tabsLayout.htmlID(), current)
2021-09-07 17:36:50 +03:00
if listeners := getTwoArgEventListeners[TabsLayout, int](tabsLayout, nil, CurrentTabChangedEvent); len(listeners) > 0 {
oldCurrent, _ := intProperty(tabsLayout, "old-current", session, -1)
2024-11-13 12:56:39 +03:00
for _, listener := range listeners {
listener(tabsLayout, current, oldCurrent)
2021-09-07 17:36:50 +03:00
}
}
case Tabs:
htmlID := tabsLayout.htmlID()
session := tabsLayout.Session()
session.updateProperty(htmlID, inactiveTabStyle, tabsLayoutInactiveTabStyle(tabsLayout))
session.updateProperty(htmlID, activeTabStyle, tabsLayoutActiveTabStyle(tabsLayout))
2024-11-13 12:56:39 +03:00
updateCSSStyle(htmlID, session)
updateInnerHTML(htmlID, session)
2021-09-07 17:36:50 +03:00
2022-05-26 12:01:49 +03:00
case TabStyle, CurrentTabStyle, TabBarStyle:
htmlID := tabsLayout.htmlID()
session := tabsLayout.Session()
session.updateProperty(htmlID, inactiveTabStyle, tabsLayoutInactiveTabStyle(tabsLayout))
session.updateProperty(htmlID, activeTabStyle, tabsLayoutActiveTabStyle(tabsLayout))
2024-11-13 12:56:39 +03:00
updateInnerHTML(htmlID, session)
2021-09-07 17:36:50 +03:00
2021-11-17 12:32:37 +03:00
case TabCloseButton:
updateInnerHTML(tabsLayout.htmlID(), tabsLayout.Session())
2021-11-17 12:32:37 +03:00
2021-09-07 17:36:50 +03:00
default:
tabsLayout.viewsContainerData.propertyChanged(tag)
2021-09-07 17:36:50 +03:00
}
}
2024-11-13 12:56:39 +03:00
/*
func (tabsLayout *tabsLayoutData) valueToTabListeners(value any) []func(TabsLayout, int, int) {
if value == nil {
return []func(TabsLayout, int, int){}
2021-11-17 12:32:37 +03:00
}
2024-11-13 12:56:39 +03:00
switch value := value.(type) {
case func(TabsLayout, int, int):
return []func(TabsLayout, int, int){value}
2021-11-17 12:32:37 +03:00
2024-11-13 12:56:39 +03:00
case func(TabsLayout, int):
fn := func(view TabsLayout, current, _ int) {
value(view, current)
2021-11-17 12:32:37 +03:00
}
2024-11-13 12:56:39 +03:00
return []func(TabsLayout, int, int){fn}
2021-11-17 12:32:37 +03:00
2024-11-13 12:56:39 +03:00
case func(TabsLayout):
fn := func(view TabsLayout, _, _ int) {
value(view)
2021-11-17 12:32:37 +03:00
}
2024-11-13 12:56:39 +03:00
return []func(TabsLayout, int, int){fn}
2021-11-17 12:32:37 +03:00
2024-11-13 12:56:39 +03:00
case func(int, int):
fn := func(_ TabsLayout, current, old int) {
value(current, old)
2021-11-17 12:32:37 +03:00
}
2024-11-13 12:56:39 +03:00
return []func(TabsLayout, int, int){fn}
2021-11-17 12:32:37 +03:00
2024-11-13 12:56:39 +03:00
case func(int):
fn := func(_ TabsLayout, current, _ int) {
value(current)
2021-11-17 12:32:37 +03:00
}
2024-11-13 12:56:39 +03:00
return []func(TabsLayout, int, int){fn}
2021-11-17 12:32:37 +03:00
2024-11-13 12:56:39 +03:00
case func():
fn := func(TabsLayout, int, int) {
value()
2021-11-17 12:32:37 +03:00
}
2024-11-13 12:56:39 +03:00
return []func(TabsLayout, int, int){fn}
2021-11-17 12:32:37 +03:00
2024-11-13 12:56:39 +03:00
case []func(TabsLayout, int, int):
return value
2021-11-17 12:32:37 +03:00
2024-11-13 12:56:39 +03:00
case []func(TabsLayout, int):
listeners := make([]func(TabsLayout, int, int), len(value))
for i, val := range value {
if val == nil {
return nil
}
2022-07-19 18:22:19 +03:00
listeners[i] = func(view TabsLayout, current, _ int) {
2021-11-17 12:32:37 +03:00
val(view, current)
}
2024-11-13 12:56:39 +03:00
}
return listeners
2021-11-17 12:32:37 +03:00
2024-11-13 12:56:39 +03:00
case []func(TabsLayout):
listeners := make([]func(TabsLayout, int, int), len(value))
for i, val := range value {
if val == nil {
return nil
}
2022-07-19 18:22:19 +03:00
listeners[i] = func(view TabsLayout, _, _ int) {
2021-11-17 12:32:37 +03:00
val(view)
}
2024-11-13 12:56:39 +03:00
}
return listeners
2021-11-17 12:32:37 +03:00
2024-11-13 12:56:39 +03:00
case []func(int, int):
listeners := make([]func(TabsLayout, int, int), len(value))
for i, val := range value {
if val == nil {
return nil
}
2022-07-19 18:22:19 +03:00
listeners[i] = func(_ TabsLayout, current, old int) {
2021-11-17 12:32:37 +03:00
val(current, old)
}
2024-11-13 12:56:39 +03:00
}
return listeners
2021-11-17 12:32:37 +03:00
2024-11-13 12:56:39 +03:00
case []func(int):
listeners := make([]func(TabsLayout, int, int), len(value))
for i, val := range value {
if val == nil {
return nil
}
2022-07-19 18:22:19 +03:00
listeners[i] = func(_ TabsLayout, current, _ int) {
2021-11-17 12:32:37 +03:00
val(current)
}
2024-11-13 12:56:39 +03:00
}
return listeners
2021-11-17 12:32:37 +03:00
2024-11-13 12:56:39 +03:00
case []func():
listeners := make([]func(TabsLayout, int, int), len(value))
for i, val := range value {
if val == nil {
return nil
}
2022-07-19 18:22:19 +03:00
listeners[i] = func(TabsLayout, int, int) {
2021-11-17 12:32:37 +03:00
val()
}
2024-11-13 12:56:39 +03:00
}
return listeners
case []any:
listeners := make([]func(TabsLayout, int, int), len(value))
for i, val := range value {
if val == nil {
return nil
}
switch val := val.(type) {
case func(TabsLayout, int, int):
listeners[i] = val
case func(TabsLayout, int):
listeners[i] = func(view TabsLayout, current, _ int) {
val(view, current)
}
case func(TabsLayout):
listeners[i] = func(view TabsLayout, _, _ int) {
val(view)
}
2021-11-17 12:32:37 +03:00
2024-11-13 12:56:39 +03:00
case func(int, int):
listeners[i] = func(_ TabsLayout, current, old int) {
val(current, old)
}
case func(int):
listeners[i] = func(_ TabsLayout, current, _ int) {
val(current)
}
case func():
listeners[i] = func(TabsLayout, int, int) {
val()
}
default:
return nil
}
2021-11-17 12:32:37 +03:00
}
2024-11-13 12:56:39 +03:00
return listeners
2021-11-17 12:32:37 +03:00
}
2024-11-13 12:56:39 +03:00
return nil
}
*/
2021-11-17 12:32:37 +03:00
2021-09-07 17:36:50 +03:00
func (tabsLayout *tabsLayoutData) tabsLocation() int {
tabs, _ := enumProperty(tabsLayout, Tabs, tabsLayout.session, 0)
return tabs
}
2021-11-21 17:53:52 +03:00
func (tabsLayout *tabsLayoutData) tabBarStyle() string {
if style, ok := stringProperty(tabsLayout, TabBarStyle, tabsLayout.session); ok {
return style
}
if value := valueFromStyle(tabsLayout, TabBarStyle); value != nil {
if style, ok := value.(string); ok {
if style, ok = tabsLayout.session.resolveConstants(style); ok {
return style
}
}
}
2021-11-21 17:53:52 +03:00
return "ruiTabBar"
}
2024-11-13 12:56:39 +03:00
func tabsLayoutInactiveTabStyle(view View) string {
session := view.Session()
if style, ok := stringProperty(view, TabStyle, session); ok {
2021-09-07 17:36:50 +03:00
return style
}
2024-11-13 12:56:39 +03:00
if value := valueFromStyle(view, TabStyle); value != nil {
if style, ok := value.(string); ok {
2024-11-13 12:56:39 +03:00
if style, ok = session.resolveConstants(style); ok {
return style
}
}
}
2024-11-13 12:56:39 +03:00
tabs, _ := enumProperty(view, Tabs, session, 0)
switch tabs {
2021-09-07 17:36:50 +03:00
case LeftTabs, RightTabs:
2021-11-21 17:53:52 +03:00
return "ruiVerticalTab"
2021-09-07 17:36:50 +03:00
}
2021-11-21 17:53:52 +03:00
return "ruiTab"
2021-09-07 17:36:50 +03:00
}
2024-11-13 12:56:39 +03:00
func tabsLayoutActiveTabStyle(view View) string {
session := view.Session()
if style, ok := stringProperty(view, CurrentTabStyle, session); ok {
2021-09-07 17:36:50 +03:00
return style
}
2024-11-13 12:56:39 +03:00
if value := valueFromStyle(view, CurrentTabStyle); value != nil {
if style, ok := value.(string); ok {
2024-11-13 12:56:39 +03:00
if style, ok = session.resolveConstants(style); ok {
return style
}
}
}
2024-11-13 12:56:39 +03:00
tabs, _ := enumProperty(view, Tabs, session, 0)
switch tabs {
2021-09-07 17:36:50 +03:00
case LeftTabs, RightTabs:
2021-11-21 17:53:52 +03:00
return "ruiCurrentVerticalTab"
2021-09-07 17:36:50 +03:00
}
2021-11-21 17:53:52 +03:00
return "ruiCurrentTab"
2021-09-07 17:36:50 +03:00
}
2021-11-17 12:32:37 +03:00
func (tabsLayout *tabsLayoutData) ListSize() int {
if tabsLayout.views == nil {
tabsLayout.views = []View{}
}
return len(tabsLayout.views)
2021-09-07 17:36:50 +03:00
}
2021-11-17 12:32:37 +03:00
func (tabsLayout *tabsLayoutData) ListItem(index int, session Session) View {
if tabsLayout.views == nil {
tabsLayout.views = []View{}
}
2021-09-07 17:36:50 +03:00
2021-11-17 12:32:37 +03:00
if index < 0 || index >= len(tabsLayout.views) {
return NewTextView(session, Params{
Text: "Invalid index",
})
}
2021-09-07 17:36:50 +03:00
2021-11-17 12:32:37 +03:00
views := []View{}
page := tabsLayout.views[index]
2022-06-20 15:33:46 +03:00
if icon, ok := imageProperty(page, Icon, session); ok && icon != "" {
2021-11-17 12:32:37 +03:00
views = append(views, NewImageView(session, Params{
Source: icon,
Row: 0,
Column: 0,
}))
}
title, ok := stringProperty(page, Title, session)
if !ok || title == "" {
title = "No title"
}
if !GetNotTranslate(tabsLayout) {
2021-11-17 12:32:37 +03:00
title, _ = tabsLayout.Session().GetString(title)
}
views = append(views, NewTextView(session, Params{
Text: title,
Row: 0,
Column: 1,
}))
closeButton, _ := boolProperty(tabsLayout, TabCloseButton, tabsLayout.session)
if close, ok := boolProperty(page, TabCloseButton, tabsLayout.session); ok {
closeButton = close
2021-09-07 17:36:50 +03:00
}
2021-11-17 12:32:37 +03:00
if closeButton {
views = append(views, NewGridLayout(session, Params{
Style: "ruiTabCloseButton",
Row: 0,
Column: 2,
Content: "✕",
ClickEvent: func() {
for _, listener := range getOneArgEventListeners[TabsLayout, int](tabsLayout, nil, TabCloseEvent) {
2021-11-17 12:32:37 +03:00
listener(tabsLayout, index)
}
},
}))
}
tabsHeight, _ := sizeConstant(session, "ruiTabHeight")
return NewGridLayout(session, Params{
Height: tabsHeight,
CellWidth: []SizeUnit{AutoSize(), Fr(1), AutoSize()},
CellVerticalAlign: CenterAlign,
GridRowGap: Px(8),
Content: views,
})
}
func (tabsLayout *tabsLayoutData) IsListItemEnabled(index int) bool {
return true
2021-09-07 17:36:50 +03:00
}
2024-11-13 12:56:39 +03:00
func (tabsLayout *tabsLayoutData) updateTitle(view View, tag PropertyName) {
session := tabsLayout.session
title, _ := stringProperty(view, Title, session)
if !GetNotTranslate(tabsLayout) {
title, _ = session.GetString(title)
}
session.updateInnerHTML(view.htmlID()+"-title", title)
}
2024-11-13 12:56:39 +03:00
func (tabsLayout *tabsLayoutData) updateIcon(view View, tag PropertyName) {
session := tabsLayout.session
icon, _ := stringProperty(view, Icon, session)
session.updateProperty(view.htmlID()+"-icon", "src", icon)
}
2024-11-13 12:56:39 +03:00
func (tabsLayout *tabsLayoutData) updateTabCloseButton(view View, tag PropertyName) {
updateInnerHTML(tabsLayout.htmlID(), tabsLayout.session)
}
2021-09-07 17:36:50 +03:00
// Append appends view to the end of view list
func (tabsLayout *tabsLayoutData) Append(view View) {
if tabsLayout.views == nil {
tabsLayout.views = []View{}
}
2021-11-17 12:32:37 +03:00
if view != nil {
tabsLayout.viewsContainerData.Append(view)
view.SetChangeListener(Title, tabsLayout.updateTitle)
view.SetChangeListener(Icon, tabsLayout.updateIcon)
view.SetChangeListener(TabCloseButton, tabsLayout.updateTabCloseButton)
2021-11-17 12:32:37 +03:00
if len(tabsLayout.views) == 1 {
2024-11-13 12:56:39 +03:00
tabsLayout.setRaw(Current, nil)
tabsLayout.Set(Current, 0)
2021-09-07 17:36:50 +03:00
}
}
}
// Insert inserts view to the "index" position in view list
func (tabsLayout *tabsLayoutData) Insert(view View, index int) {
2021-09-07 17:36:50 +03:00
if tabsLayout.views == nil {
tabsLayout.views = []View{}
}
2021-11-17 12:32:37 +03:00
if view != nil {
2024-11-13 12:56:39 +03:00
if current := GetCurrent(tabsLayout); current >= index {
tabsLayout.setRaw(Current, current+1)
defer tabsLayout.currentChanged(current+1, current)
2021-11-17 12:32:37 +03:00
}
tabsLayout.viewsContainerData.Insert(view, index)
view.SetChangeListener(Title, tabsLayout.updateTitle)
view.SetChangeListener(Icon, tabsLayout.updateIcon)
view.SetChangeListener(TabCloseButton, tabsLayout.updateTabCloseButton)
2021-09-07 17:36:50 +03:00
}
}
func (tabsLayout *tabsLayoutData) currentChanged(newCurrent, oldCurrent int) {
for _, listener := range getTwoArgEventListeners[TabsLayout, int](tabsLayout, nil, CurrentTabChangedEvent) {
listener(tabsLayout, newCurrent, oldCurrent)
}
2024-11-13 12:56:39 +03:00
if listener, ok := tabsLayout.changeListener[Current]; ok {
listener(tabsLayout, Current)
}
}
2021-09-07 17:36:50 +03:00
// Remove removes view from list and return it
func (tabsLayout *tabsLayoutData) RemoveView(index int) View {
2024-11-13 12:56:39 +03:00
if index < 0 || index >= len(tabsLayout.views) {
2021-09-07 17:36:50 +03:00
return nil
}
2022-05-17 10:46:00 +03:00
2024-11-13 12:56:39 +03:00
oldCurrent := GetCurrent(tabsLayout)
newCurrent := oldCurrent
if index < oldCurrent || (index == oldCurrent && oldCurrent > 0) {
newCurrent--
2021-09-07 17:36:50 +03:00
}
2024-11-13 12:56:39 +03:00
if view := tabsLayout.viewsContainerData.RemoveView(index); view != nil {
view.SetChangeListener(Title, nil)
view.SetChangeListener(Icon, nil)
view.SetChangeListener(TabCloseButton, nil)
2021-09-07 17:36:50 +03:00
2024-11-13 12:56:39 +03:00
if newCurrent != oldCurrent {
tabsLayout.setRaw(Current, newCurrent)
tabsLayout.currentChanged(newCurrent, oldCurrent)
2024-11-13 12:56:39 +03:00
}
2022-05-17 10:46:00 +03:00
}
2024-11-13 12:56:39 +03:00
return nil
2022-05-17 10:46:00 +03:00
2024-11-13 12:56:39 +03:00
/*
if tabsLayout.views == nil {
tabsLayout.views = []View{}
return nil
}
2021-09-07 17:36:50 +03:00
2024-11-13 12:56:39 +03:00
count := len(tabsLayout.views)
if index < 0 || index >= count {
return nil
}
2022-05-17 10:46:00 +03:00
2024-11-13 12:56:39 +03:00
view := tabsLayout.views[index]
view.setParentID("")
view.SetChangeListener(Title, nil)
view.SetChangeListener(Icon, nil)
view.SetChangeListener(TabCloseButton, nil)
current := GetCurrent(tabsLayout)
if index < current || (index == current && current > 0) {
current--
}
if len(tabsLayout.views) == 1 {
tabsLayout.views = []View{}
current = -1
} else if index == 0 {
tabsLayout.views = tabsLayout.views[1:]
} else if index == count-1 {
tabsLayout.views = tabsLayout.views[:index]
} else {
tabsLayout.views = append(tabsLayout.views[:index], tabsLayout.views[index+1:]...)
}
updateInnerHTML(tabsLayout.parentHTMLID(), tabsLayout.session)
tabsLayout.propertyChangedEvent(Content)
delete(tabsLayout.view, Current)
tabsLayout.Set(Current, current)
return view
*/
2021-09-07 17:36:50 +03:00
}
func (tabsLayout *tabsLayoutData) htmlProperties(self View, buffer *strings.Builder) {
tabsLayout.viewsContainerData.htmlProperties(self, buffer)
buffer.WriteString(` data-inactiveTabStyle="`)
2024-11-13 12:56:39 +03:00
buffer.WriteString(tabsLayoutInactiveTabStyle(tabsLayout))
2021-09-07 17:36:50 +03:00
buffer.WriteString(`" data-activeTabStyle="`)
2024-11-13 12:56:39 +03:00
buffer.WriteString(tabsLayoutActiveTabStyle(tabsLayout))
2021-09-07 17:36:50 +03:00
buffer.WriteString(`" data-current="`)
2024-11-13 12:56:39 +03:00
buffer.WriteString(strconv.Itoa(GetCurrent(tabsLayout)))
2021-09-07 17:36:50 +03:00
buffer.WriteRune('"')
}
func (tabsLayout *tabsLayoutData) cssStyle(self View, builder cssBuilder) {
tabsLayout.viewsContainerData.cssStyle(self, builder)
switch tabsLayout.tabsLocation() {
case TopTabs:
builder.add(`grid-template-rows`, `auto 1fr`)
case BottomTabs:
builder.add(`grid-template-rows`, `1fr auto`)
case LeftTabs, LeftListTabs:
builder.add(`grid-template-columns`, `auto 1fr`)
case RightTabs, RightListTabs:
builder.add(`grid-template-columns`, `1fr auto`)
}
}
func (tabsLayout *tabsLayoutData) htmlSubviews(self View, buffer *strings.Builder) {
if tabsLayout.views == nil {
return
}
2024-11-13 12:56:39 +03:00
current := GetCurrent(tabsLayout)
2021-09-07 17:36:50 +03:00
location := tabsLayout.tabsLocation()
tabsLayoutID := tabsLayout.htmlID()
if location != HiddenTabs {
2021-11-21 17:53:52 +03:00
buffer.WriteString(`<div class="`)
buffer.WriteString(tabsLayout.tabBarStyle())
buffer.WriteString(`" style="display: flex;`)
2021-09-07 17:36:50 +03:00
switch location {
case LeftTabs, LeftListTabs, TopTabs:
buffer.WriteString(` grid-row-start: 1; grid-row-end: 2; grid-column-start: 1; grid-column-end: 2;`)
case RightTabs, RightListTabs:
buffer.WriteString(` grid-row-start: 1; grid-row-end: 2; grid-column-start: 2; grid-column-end: 3;`)
case BottomTabs:
buffer.WriteString(` grid-row-start: 2; grid-row-end: 3; grid-column-start: 1; grid-column-end: 2;`)
}
buffer.WriteString(` flex-flow: `)
switch location {
case LeftTabs, LeftListTabs, RightTabs, RightListTabs:
buffer.WriteString(`column nowrap; justify-content: flex-start; align-items: stretch;`)
default:
buffer.WriteString(`row nowrap; justify-content: flex-start; align-items: stretch;`)
}
buffer.WriteString(`">`)
2024-11-13 12:56:39 +03:00
inactiveStyle := tabsLayoutInactiveTabStyle(tabsLayout)
activeStyle := tabsLayoutActiveTabStyle(tabsLayout)
2021-09-07 17:36:50 +03:00
notTranslate := GetNotTranslate(tabsLayout)
2021-11-17 12:32:37 +03:00
closeButton, _ := boolProperty(tabsLayout, TabCloseButton, tabsLayout.session)
var tabStyle, titleStyle string
2021-11-17 12:32:37 +03:00
switch location {
case LeftTabs, RightTabs:
tabStyle = `display: grid; grid-template-rows: auto 1fr auto; align-items: center; justify-items: center; grid-row-gap: 8px;`
case LeftListTabs, RightListTabs:
2021-11-21 17:53:52 +03:00
tabStyle = `display: grid; grid-template-columns: auto 1fr auto; align-items: center; justify-items: start; grid-column-gap: 8px;`
2021-11-17 12:32:37 +03:00
default:
tabStyle = `display: grid; grid-template-columns: auto 1fr auto; align-items: center; justify-items: center; grid-column-gap: 8px;`
}
switch location {
case LeftTabs:
titleStyle = ` style="writing-mode: vertical-lr; transform: rotate(180deg); grid-row-start: 2; grid-row-end: 3; grid-column-start: 1; grid-column-end: 2;">`
2021-11-17 12:32:37 +03:00
case RightTabs:
titleStyle = ` style="writing-mode: vertical-lr; grid-row-start: 2; grid-row-end: 3; grid-column-start: 1; grid-column-end: 2;">`
2021-11-17 12:32:37 +03:00
default:
titleStyle = ` style="grid-row-start: 1; grid-row-end: 2; grid-column-start: 2; grid-column-end: 3;">`
2021-11-17 12:32:37 +03:00
}
2021-09-07 17:36:50 +03:00
for n, view := range tabsLayout.views {
2022-06-20 15:33:46 +03:00
icon, _ := imageProperty(view, Icon, tabsLayout.session)
2021-11-17 12:32:37 +03:00
title, _ := stringProperty(view, Title, tabsLayout.session)
2021-09-07 17:36:50 +03:00
if !notTranslate {
title, _ = tabsLayout.Session().GetString(title)
}
buffer.WriteString(`<div id="`)
buffer.WriteString(tabsLayoutID)
buffer.WriteByte('-')
buffer.WriteString(strconv.Itoa(n))
buffer.WriteString(`" class="`)
if n == current {
buffer.WriteString(activeStyle)
} else {
buffer.WriteString(inactiveStyle)
}
2022-10-29 20:48:03 +03:00
buffer.WriteString(`" tabindex="0" onclick="tabClickEvent(this, '`)
2021-09-07 17:36:50 +03:00
buffer.WriteString(tabsLayoutID)
2022-10-29 20:48:03 +03:00
buffer.WriteString(`', `)
2021-09-07 17:36:50 +03:00
buffer.WriteString(strconv.Itoa(n))
2022-10-29 20:48:03 +03:00
buffer.WriteString(`, event)" onkeydown="tabKeyClickEvent('`)
2021-09-07 17:36:50 +03:00
buffer.WriteString(tabsLayoutID)
2022-10-29 20:48:03 +03:00
buffer.WriteString(`', `)
2021-09-07 17:36:50 +03:00
buffer.WriteString(strconv.Itoa(n))
2021-11-17 12:32:37 +03:00
buffer.WriteString(`, event)" style="`)
buffer.WriteString(tabStyle)
2021-09-07 17:36:50 +03:00
buffer.WriteString(`" data-container="`)
buffer.WriteString(tabsLayoutID)
buffer.WriteString(`" data-view="`)
buffer.WriteString(tabsLayoutID)
buffer.WriteString(`-page`)
buffer.WriteString(strconv.Itoa(n))
2021-11-17 12:32:37 +03:00
buffer.WriteString(`">`)
2021-09-07 17:36:50 +03:00
2021-11-17 12:32:37 +03:00
if icon != "" {
buffer.WriteString(`<img id="`)
buffer.WriteString(view.htmlID())
2021-11-17 12:32:37 +03:00
switch location {
case LeftTabs:
buffer.WriteString(`-icon" style="grid-row-start: 3; grid-row-end: 4; grid-column-start: 1; grid-column-end: 2;" src="`)
2021-09-07 17:36:50 +03:00
2021-11-17 12:32:37 +03:00
case RightTabs:
buffer.WriteString(`-icon" style="grid-row-start: 1; grid-row-end: 2; grid-column-start: 1; grid-column-end: 2;" src="`)
2021-09-07 17:36:50 +03:00
2021-11-17 12:32:37 +03:00
default:
buffer.WriteString(`-icon" style="grid-row-start: 1; grid-row-end: 2; grid-column-start: 1; grid-column-end: 2;" src="`)
2021-11-17 12:32:37 +03:00
}
buffer.WriteString(icon)
buffer.WriteString(`">`)
2021-09-07 17:36:50 +03:00
}
2021-11-17 12:32:37 +03:00
buffer.WriteString(`<div id="`)
buffer.WriteString(view.htmlID())
buffer.WriteString(`-title"`)
buffer.WriteString(titleStyle)
2021-09-07 17:36:50 +03:00
buffer.WriteString(title)
2021-11-17 12:32:37 +03:00
buffer.WriteString(`</div>`)
close, ok := boolProperty(view, TabCloseButton, tabsLayout.session)
if !ok {
close = closeButton
}
if close {
2022-10-29 20:48:03 +03:00
buffer.WriteString(`<div class="ruiTabCloseButton" tabindex="0" onclick="tabCloseClickEvent(this, '`)
2021-11-21 18:16:22 +03:00
buffer.WriteString(tabsLayoutID)
2022-10-29 20:48:03 +03:00
buffer.WriteString(`', `)
2021-11-21 18:16:22 +03:00
buffer.WriteString(strconv.Itoa(n))
2022-10-29 20:48:03 +03:00
buffer.WriteString(`, event)" onkeydown="tabCloseKeyClickEvent('`)
2021-11-17 12:32:37 +03:00
buffer.WriteString(tabsLayoutID)
2022-10-29 20:48:03 +03:00
buffer.WriteString(`', `)
2021-11-17 12:32:37 +03:00
buffer.WriteString(strconv.Itoa(n))
buffer.WriteString(`, event)" style="display: grid; `)
2021-11-17 12:32:37 +03:00
switch location {
case LeftTabs:
buffer.WriteString(`grid-row-start: 1; grid-row-end: 2; grid-column-start: 1; grid-column-end: 2;">`)
case RightTabs:
buffer.WriteString(`grid-row-start: 3; grid-row-end: 4; grid-column-start: 1; grid-column-end: 2;">`)
default:
buffer.WriteString(`grid-row-start: 1; grid-row-end: 2; grid-column-start: 3; grid-column-end: 4;">`)
}
buffer.WriteString(`✕</div>`)
}
buffer.WriteString(`</div>`)
2021-09-07 17:36:50 +03:00
}
buffer.WriteString(`</div>`)
}
for n, view := range tabsLayout.views {
buffer.WriteString(`<div id="`)
buffer.WriteString(tabsLayoutID)
buffer.WriteString(`-page`)
buffer.WriteString(strconv.Itoa(n))
2024-09-25 13:45:47 +03:00
if current != n {
buffer.WriteString(`" style="display: grid; align-items: stretch; justify-items: stretch; visibility: hidden; `)
} else {
buffer.WriteString(`" style="display: grid; align-items: stretch; justify-items: stretch; `)
}
2021-09-07 17:36:50 +03:00
switch location {
case LeftTabs, LeftListTabs:
2024-09-25 13:45:47 +03:00
buffer.WriteString(`grid-row-start: 1; grid-row-end: 2; grid-column-start: 2; grid-column-end: 3;">`)
2021-09-07 17:36:50 +03:00
case TopTabs:
2024-09-25 13:45:47 +03:00
buffer.WriteString(`grid-row-start: 2; grid-row-end: 3; grid-column-start: 1; grid-column-end: 2;">`)
2021-09-07 17:36:50 +03:00
default:
2024-09-25 13:45:47 +03:00
buffer.WriteString(`grid-row-start: 1; grid-row-end: 2; grid-column-start: 1; grid-column-end: 2;">`)
2021-09-07 17:36:50 +03:00
}
2024-11-21 09:25:46 +03:00
viewHTML(view, buffer, "")
2021-09-07 17:36:50 +03:00
buffer.WriteString(`</div>`)
}
}
2024-11-13 12:56:39 +03:00
func (tabsLayout *tabsLayoutData) handleCommand(self View, command PropertyName, data DataObject) bool {
2021-09-07 17:36:50 +03:00
switch command {
case "tabClick":
if numberText, ok := data.PropertyValue("number"); ok {
if number, err := strconv.Atoi(numberText); err == nil {
2024-11-13 12:56:39 +03:00
current := GetCurrent(tabsLayout)
2021-09-07 17:36:50 +03:00
if current != number {
2024-11-13 12:56:39 +03:00
tabsLayout.setRaw(Current, number)
tabsLayout.currentChanged(number, current)
2021-09-07 17:36:50 +03:00
}
}
}
return true
2021-11-17 12:32:37 +03:00
case "tabCloseClick":
if numberText, ok := data.PropertyValue("number"); ok {
if number, err := strconv.Atoi(numberText); err == nil {
for _, listener := range getOneArgEventListeners[TabsLayout, int](tabsLayout, nil, TabCloseEvent) {
2021-11-17 12:32:37 +03:00
listener(tabsLayout, number)
}
}
}
return true
2021-09-07 17:36:50 +03:00
}
return tabsLayout.viewsContainerData.handleCommand(self, command, data)
}