From 904859ff6e78f0ac3e597c359d3e3726da984b6b Mon Sep 17 00:00:00 2001 From: anoshenko Date: Sun, 14 May 2023 17:53:26 +0300 Subject: [PATCH] Added ReloadCell and ReloadTableViewCell functions --- CHANGELOG.md | 2 + README-ru.md | 12 ++++ README.md | 12 ++++ tableView.go | 166 ++++++++++++++++++++++++++++++++-------------- tableViewUtils.go | 20 ++++++ tabsLayout.go | 52 ++++++++++----- 6 files changed, 200 insertions(+), 64 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7fe4f7a..5d3c98b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,8 @@ # v0.13.0 * Added ViewIndex function to ViewsContainer interface +* Added ReloadCell function to TableView interface +* Added ReloadTableViewCell function * Added "tooltip" property and GetTooltip function * Added "outline-offset" property and GetOutlineOffset function * Changed the main event listener format for "drop-down-event", "edit-text-changed", diff --git a/README-ru.md b/README-ru.md index ea6ac7b..8b8fe05 100644 --- a/README-ru.md +++ b/README-ru.md @@ -3800,6 +3800,18 @@ Cell(row, column int) возвращает содержимое ячейки т [][]any и [][]string при присвоении преобразуются к TableAdapter. +Если элементы таблицы меняются в ходе работы, то для обновления содержимого таблицы необходимо вызвать один +из двух методов интерфейса TableView + +* ReloadTableData() +* ReloadCell(row, column int) + +Метод ReloadTableData обновляет таблицу целиком, а ReloadCell обновляет содержимое только конкретной ячейки таблицы. +Для вызова методов ReloadTableData и ReloadCell могут использоваться глобальные функции + + func ReloadTableViewData(view View, subviewID ...string) bool + func ReloadTableViewCell(row, column int, view View, subviewID ...string) bool + ### Свойство "cell-style" Свойство "cell-style" (константа CellStyle) предназначено для настройки оформления ячейки таблицы. Данному свойству diff --git a/README.md b/README.md index 0e91275..9b26347 100644 --- a/README.md +++ b/README.md @@ -3763,6 +3763,18 @@ The "content" property can also be assigned the following data types [][]any and [][]string are converted to a TableAdapter when assigned. +If the elements of the table change during operation, then to update the contents of the table, +you must call one of the two methods of the TableView interface + +* ReloadTableData() +* ReloadCell(row, column int) + +The ReloadTableData method updates the entire table, while ReloadCell updates the contents of only a specific table cell. +Global functions can be used to call the ReloadTableData and ReloadCell methods + + func ReloadTableViewData(view View, subviewID ...string) bool + func ReloadTableViewCell(row, column int, view View, subviewID ...string) bool + ### "cell-style" property The "cell-style" property (CellStyle constant) is used to customize the appearance of a table cell. diff --git a/tableView.go b/tableView.go index 750f9d9..01fcdc1 100644 --- a/tableView.go +++ b/tableView.go @@ -220,6 +220,7 @@ type TableView interface { View ParentView ReloadTableData() + ReloadCell(row, column int) CellFrame(row, column int) Frame content() TableAdapter @@ -880,7 +881,7 @@ func (table *tableViewData) htmlSubviews(self View, buffer *strings.Builder) { vAlign := vAlignCss[vAlignValue] tableCSS := func(startRow, endRow int, cellTag string, cellBorder BorderProperty, cellPadding BoundsProperty) { - var namedColors []NamedColor = nil + //var namedColors []NamedColor = nil for row := startRow; row < endRow; row++ { cssBuilder.buffer.Reset() @@ -1042,57 +1043,60 @@ func (table *tableViewData) htmlSubviews(self View, buffer *strings.Builder) { } buffer.WriteRune('>') - switch value := adapter.Cell(row, column).(type) { - case string: - buffer.WriteString(value) + table.writeCellHtml(adapter, row, column, buffer) + /* + switch value := adapter.Cell(row, column).(type) { + case string: + buffer.WriteString(value) - case View: - viewHTML(value, buffer) - table.cellViews = append(table.cellViews, value) + case View: + viewHTML(value, buffer) + table.cellViews = append(table.cellViews, value) - case Color: - buffer.WriteString(`
    
`) - buffer.WriteString(value.String()) - if namedColors == nil { - namedColors = NamedColors() - } - for _, namedColor := range namedColors { - if namedColor.Color == value { - buffer.WriteString(" (") - buffer.WriteString(namedColor.Name) - buffer.WriteRune(')') - break + case Color: + buffer.WriteString(`
    
`) + buffer.WriteString(value.String()) + if namedColors == nil { + namedColors = NamedColors() + } + for _, namedColor := range namedColors { + if namedColor.Color == value { + buffer.WriteString(" (") + buffer.WriteString(namedColor.Name) + buffer.WriteRune(')') + break + } + } + + case fmt.Stringer: + buffer.WriteString(value.String()) + + case rune: + buffer.WriteString(string(value)) + + case float32: + buffer.WriteString(fmt.Sprintf("%g", float64(value))) + + case float64: + buffer.WriteString(fmt.Sprintf("%g", value)) + + case bool: + if value { + buffer.WriteString(session.checkboxOnImage()) + } else { + buffer.WriteString(session.checkboxOffImage()) + } + + default: + if n, ok := isInt(value); ok { + buffer.WriteString(fmt.Sprintf("%d", n)) + } else { + buffer.WriteString("") } } - - case fmt.Stringer: - buffer.WriteString(value.String()) - - case rune: - buffer.WriteString(string(value)) - - case float32: - buffer.WriteString(fmt.Sprintf("%g", float64(value))) - - case float64: - buffer.WriteString(fmt.Sprintf("%g", value)) - - case bool: - if value { - buffer.WriteString(session.checkboxOnImage()) - } else { - buffer.WriteString(session.checkboxOffImage()) - } - - default: - if n, ok := isInt(value); ok { - buffer.WriteString(fmt.Sprintf("%d", n)) - } else { - buffer.WriteString("") - } - } + */ buffer.WriteString(`     `) + buffer.WriteString(value.String()) + + namedColors := NamedColors() + for _, namedColor := range namedColors { + if namedColor.Color == value { + buffer.WriteString(" (") + buffer.WriteString(namedColor.Name) + buffer.WriteRune(')') + break + } + } + + case fmt.Stringer: + buffer.WriteString(value.String()) + + case rune: + buffer.WriteString(string(value)) + + case float32: + buffer.WriteString(fmt.Sprintf("%g", float64(value))) + + case float64: + buffer.WriteString(fmt.Sprintf("%g", value)) + + case bool: + if value { + buffer.WriteString(table.Session().checkboxOnImage()) + } else { + buffer.WriteString(table.Session().checkboxOffImage()) + } + + default: + if n, ok := isInt(value); ok { + buffer.WriteString(fmt.Sprintf("%d", n)) + } else { + buffer.WriteString("") + } + } +} + func (table *tableViewData) cellBorderFromStyle(style string) BorderProperty { if value := table.Session().styleProperty(style, CellBorder); value != nil { if border, ok := value.(BorderProperty); ok { @@ -1395,6 +1452,19 @@ func (table *tableViewData) CellFrame(row, column int) Frame { return Frame{} } +func (table *tableViewData) ReloadCell(row, column int) { + adapter := table.content() + if adapter == nil { + return + } + + buffer := allocStringBuilder() + defer freeStringBuilder(buffer) + + table.writeCellHtml(adapter, row, column, buffer) + table.session.updateInnerHTML(table.cellID(row, column), buffer.String()) +} + func (table *tableViewData) Views() []View { return table.cellViews } diff --git a/tableViewUtils.go b/tableViewUtils.go index d8e46f3..9385d12 100644 --- a/tableViewUtils.go +++ b/tableViewUtils.go @@ -182,6 +182,7 @@ func GetTableRowSelectedListeners(view View, subviewID ...string) []func(TableVi } // ReloadTableViewData updates TableView +// If the second argument (subviewID) is not specified or it is "" then updates the first argument (TableView). func ReloadTableViewData(view View, subviewID ...string) bool { var tableView TableView if len(subviewID) > 0 && subviewID[0] != "" { @@ -198,3 +199,22 @@ func ReloadTableViewData(view View, subviewID ...string) bool { tableView.ReloadTableData() return true } + +// ReloadTableViewCell updates the given table cell. +// If the last argument (subviewID) is not specified or it is "" then updates the cell of the first argument (TableView). +func ReloadTableViewCell(row, column int, view View, subviewID ...string) bool { + var tableView TableView + if len(subviewID) > 0 && subviewID[0] != "" { + if tableView = TableViewByID(view, subviewID[0]); tableView == nil { + return false + } + } else { + var ok bool + if tableView, ok = view.(TableView); !ok { + return false + } + } + + tableView.ReloadCell(row, column) + return true +} diff --git a/tabsLayout.go b/tabsLayout.go index e880aa7..881f485 100644 --- a/tabsLayout.go +++ b/tabsLayout.go @@ -566,7 +566,22 @@ func (tabsLayout *tabsLayoutData) IsListItemEnabled(index int) bool { return true } -func (tabsLayout *tabsLayoutData) updateContent(view View, tag string) { +func (tabsLayout *tabsLayoutData) updateTitle(view View, tag string) { + session := tabsLayout.session + title, _ := stringProperty(view, Title, session) + if !GetNotTranslate(tabsLayout) { + title, _ = session.GetString(title) + } + session.updateInnerHTML(view.htmlID()+"-title", title) +} + +func (tabsLayout *tabsLayoutData) updateIcon(view View, tag string) { + session := tabsLayout.session + icon, _ := stringProperty(view, Icon, session) + session.updateProperty(view.htmlID()+"-icon", "src", icon) +} + +func (tabsLayout *tabsLayoutData) updateTabCloseButton(view View, tag string) { updateInnerHTML(tabsLayout.htmlID(), tabsLayout.session) } @@ -577,9 +592,9 @@ func (tabsLayout *tabsLayoutData) Append(view View) { } if view != nil { tabsLayout.viewsContainerData.Append(view) - view.SetChangeListener(Title, tabsLayout.updateContent) - view.SetChangeListener(Icon, tabsLayout.updateContent) - view.SetChangeListener(TabCloseButton, tabsLayout.updateContent) + view.SetChangeListener(Title, tabsLayout.updateTitle) + view.SetChangeListener(Icon, tabsLayout.updateIcon) + view.SetChangeListener(TabCloseButton, tabsLayout.updateTabCloseButton) if len(tabsLayout.views) == 1 { tabsLayout.properties[Current] = 0 for _, listener := range tabsLayout.tabListener { @@ -601,9 +616,9 @@ func (tabsLayout *tabsLayoutData) Insert(view View, index int) { defer tabsLayout.propertyChangedEvent(Current) } tabsLayout.viewsContainerData.Insert(view, index) - view.SetChangeListener(Title, tabsLayout.updateContent) - view.SetChangeListener(Icon, tabsLayout.updateContent) - view.SetChangeListener(TabCloseButton, tabsLayout.updateContent) + view.SetChangeListener(Title, tabsLayout.updateTitle) + view.SetChangeListener(Icon, tabsLayout.updateIcon) + view.SetChangeListener(TabCloseButton, tabsLayout.updateTabCloseButton) } } @@ -721,7 +736,7 @@ func (tabsLayout *tabsLayoutData) htmlSubviews(self View, buffer *strings.Builde notTranslate := GetNotTranslate(tabsLayout) closeButton, _ := boolProperty(tabsLayout, TabCloseButton, tabsLayout.session) - var tabStyle, titleDiv string + var tabStyle, titleStyle string switch location { case LeftTabs, RightTabs: tabStyle = `display: grid; grid-template-rows: auto 1fr auto; align-items: center; justify-items: center; grid-row-gap: 8px;` @@ -735,13 +750,13 @@ func (tabsLayout *tabsLayoutData) htmlSubviews(self View, buffer *strings.Builde switch location { case LeftTabs: - titleDiv = `
` + 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;">` case RightTabs: - titleDiv = `
` + titleStyle = ` style="writing-mode: vertical-lr; grid-row-start: 2; grid-row-end: 3; grid-column-start: 1; grid-column-end: 2;">` default: - titleDiv = `
` + titleStyle = ` style="grid-row-start: 1; grid-row-end: 2; grid-column-start: 2; grid-column-end: 3;">` } for n, view := range tabsLayout.views { @@ -780,21 +795,26 @@ func (tabsLayout *tabsLayoutData) htmlSubviews(self View, buffer *strings.Builde buffer.WriteString(`">`) if icon != "" { + buffer.WriteString(``) } - buffer.WriteString(titleDiv) + buffer.WriteString(`
`) @@ -811,7 +831,7 @@ func (tabsLayout *tabsLayoutData) htmlSubviews(self View, buffer *strings.Builde buffer.WriteString(tabsLayoutID) buffer.WriteString(`', `) buffer.WriteString(strconv.Itoa(n)) - buffer.WriteString(`, event)" style="display: grid; `) + buffer.WriteString(`, event)" style="display: grid; `) switch location { case LeftTabs: