aboutsummaryrefslogtreecommitdiff
path: root/ui/messages/html/container.go
diff options
context:
space:
mode:
Diffstat (limited to 'ui/messages/html/container.go')
-rw-r--r--ui/messages/html/container.go144
1 files changed, 144 insertions, 0 deletions
diff --git a/ui/messages/html/container.go b/ui/messages/html/container.go
new file mode 100644
index 0000000..b17bc1f
--- /dev/null
+++ b/ui/messages/html/container.go
@@ -0,0 +1,144 @@
+// gomuks - A terminal Matrix client written in Go.
+// Copyright (C) 2019 Tulir Asokan
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+package html
+
+import (
+ "fmt"
+ "strings"
+
+ "maunium.net/go/mauview"
+)
+
+type ContainerEntity struct {
+ *BaseEntity
+
+ // The children of this container entity.
+ Children []Entity
+ // Number of cells to indent children.
+ Indent int
+}
+
+// PlainText returns the plaintext content in this entity and all its children.
+func (ce *ContainerEntity) PlainText() string {
+ if len(ce.Children) == 0 {
+ return ""
+ }
+ var buf strings.Builder
+ newlined := false
+ for _, child := range ce.Children {
+ text := child.PlainText()
+ if !strings.HasPrefix(text, "\n") && child.IsBlock() && !newlined {
+ buf.WriteRune('\n')
+ }
+ newlined = false
+ buf.WriteString(text)
+ if child.IsBlock() {
+ if !strings.HasSuffix(text, "\n") {
+ buf.WriteRune('\n')
+ }
+ newlined = true
+ }
+ }
+ return strings.TrimSpace(buf.String())
+}
+
+// AdjustStyle recursively changes the style of this entity and all its children.
+func (ce *ContainerEntity) AdjustStyle(fn AdjustStyleFunc) Entity {
+ for _, child := range ce.Children {
+ child.AdjustStyle(fn)
+ }
+ ce.Style = fn(ce.Style)
+ return ce
+}
+
+// clone creates a deep copy of this base entity.
+func (ce *ContainerEntity) Clone() Entity {
+ children := make([]Entity, len(ce.Children))
+ for i, child := range ce.Children {
+ children[i] = child.Clone()
+ }
+ return &ContainerEntity{
+ BaseEntity: ce.BaseEntity.Clone().(*BaseEntity),
+ Children: children,
+ Indent: ce.Indent,
+ }
+}
+
+// String returns a textual representation of this BaseEntity struct.
+func (ce *ContainerEntity) String() string {
+ if len(ce.Children) == 0 {
+ return fmt.Sprintf(`&html.ContainerEntity{Base=%s, Indent=%d, Children=[]}`, ce.BaseEntity, ce.Indent)
+ }
+ var buf strings.Builder
+ _, _ = fmt.Fprintf(&buf, `&html.ContainerEntity{Base=%s, Indent=%d, Children=[`, ce.BaseEntity, ce.Indent)
+ for _, child := range ce.Children {
+ buf.WriteString("\n ")
+ buf.WriteString(strings.Join(strings.Split(strings.TrimRight(child.String(), "\n"), "\n"), "\n "))
+ }
+ buf.WriteString("\n]}\n,")
+ return buf.String()
+}
+
+// Draw draws this entity onto the given mauview Screen.
+func (ce *ContainerEntity) Draw(screen mauview.Screen) {
+ if len(ce.Children) == 0 {
+ return
+ }
+ width, _ := screen.Size()
+ prevBreak := false
+ proxyScreen := &mauview.ProxyScreen{Parent: screen, OffsetX: ce.Indent, Width: width - ce.Indent, Style: ce.Style}
+ for i, entity := range ce.Children {
+ if i != 0 && entity.getStartX() == 0 {
+ proxyScreen.OffsetY++
+ }
+ proxyScreen.Height = entity.Height()
+ entity.Draw(proxyScreen)
+ proxyScreen.SetStyle(ce.Style)
+ proxyScreen.OffsetY += entity.Height() - 1
+ _, isBreak := entity.(*BreakEntity)
+ if prevBreak && isBreak {
+ proxyScreen.OffsetY++
+ }
+ prevBreak = isBreak
+ }
+}
+
+// CalculateBuffer prepares this entity and all its children for rendering with the given parameters
+func (ce *ContainerEntity) CalculateBuffer(width, startX int, bare bool) int {
+ ce.BaseEntity.CalculateBuffer(width, startX, bare)
+ if len(ce.Children) > 0 {
+ ce.height = 0
+ childStartX := ce.startX
+ prevBreak := false
+ for _, entity := range ce.Children {
+ if entity.IsBlock() || childStartX == 0 || ce.height == 0 {
+ ce.height++
+ }
+ childStartX = entity.CalculateBuffer(width-ce.Indent, childStartX, bare)
+ ce.height += entity.Height() - 1
+ _, isBreak := entity.(*BreakEntity)
+ if prevBreak && isBreak {
+ ce.height++
+ }
+ prevBreak = isBreak
+ }
+ if !ce.Block {
+ return childStartX
+ }
+ }
+ return ce.startX
+}