Add support for rendering spoilers. Fixes #331
This commit is contained in:
parent
751a158fbf
commit
a5bdba204e
@ -10,6 +10,8 @@
|
||||
(thanks to [@tleb] in [#354]).
|
||||
* Added tab-completion support for `/toggle` options
|
||||
(thanks to [@n-peugnet] in [#362]).
|
||||
* Added initial support for rendering spoilers in messages.
|
||||
* Fixed mentions being lost when editing messages.
|
||||
* Fixed date change messages showing the wrong date.
|
||||
* Fixed some whitespace in HTML being rendered even when it shouldn't.
|
||||
|
||||
|
@ -34,7 +34,7 @@ import (
|
||||
)
|
||||
|
||||
type MessageRenderer interface {
|
||||
Draw(screen mauview.Screen)
|
||||
Draw(screen mauview.Screen, msg *UIMessage)
|
||||
NotificationContent() string
|
||||
PlainText() string
|
||||
CalculateBuffer(prefs config.UserPreferences, width int, msg *UIMessage)
|
||||
@ -324,7 +324,7 @@ func (msg *UIMessage) DrawReactions(screen mauview.Screen) {
|
||||
|
||||
func (msg *UIMessage) Draw(screen mauview.Screen) {
|
||||
proxyScreen := msg.DrawReply(screen)
|
||||
msg.Renderer.Draw(proxyScreen)
|
||||
msg.Renderer.Draw(proxyScreen, msg)
|
||||
msg.DrawReactions(proxyScreen)
|
||||
if msg.IsSelected {
|
||||
w, h := screen.Size()
|
||||
|
@ -83,7 +83,7 @@ func (msg *ExpandedTextMessage) Height() int {
|
||||
return len(msg.buffer)
|
||||
}
|
||||
|
||||
func (msg *ExpandedTextMessage) Draw(screen mauview.Screen) {
|
||||
func (msg *ExpandedTextMessage) Draw(screen mauview.Screen, _ *UIMessage) {
|
||||
for y, line := range msg.buffer {
|
||||
line.Draw(screen, 0, y)
|
||||
}
|
||||
|
@ -170,7 +170,7 @@ func (msg *FileMessage) Height() int {
|
||||
return len(msg.buffer)
|
||||
}
|
||||
|
||||
func (msg *FileMessage) Draw(screen mauview.Screen) {
|
||||
func (msg *FileMessage) Draw(screen mauview.Screen, _ *UIMessage) {
|
||||
for y, line := range msg.buffer {
|
||||
line.Draw(screen, 0, y)
|
||||
}
|
||||
|
@ -38,7 +38,7 @@ type BaseEntity struct {
|
||||
}
|
||||
|
||||
// AdjustStyle changes the style of this text entity.
|
||||
func (be *BaseEntity) AdjustStyle(fn AdjustStyleFunc) Entity {
|
||||
func (be *BaseEntity) AdjustStyle(fn AdjustStyleFunc, reason AdjustStyleReason) Entity {
|
||||
be.Style = fn(be.Style)
|
||||
return be
|
||||
}
|
||||
@ -87,7 +87,7 @@ func (be *BaseEntity) String() string {
|
||||
}
|
||||
|
||||
// CalculateBuffer prepares this entity for rendering with the given parameters.
|
||||
func (be *BaseEntity) CalculateBuffer(width, startX int, bare bool) int {
|
||||
func (be *BaseEntity) CalculateBuffer(width, startX int, ctx DrawContext) int {
|
||||
be.height = be.DefaultHeight
|
||||
be.startX = startX
|
||||
if be.Block {
|
||||
@ -96,6 +96,6 @@ func (be *BaseEntity) CalculateBuffer(width, startX int, bare bool) int {
|
||||
return be.startX
|
||||
}
|
||||
|
||||
func (be *BaseEntity) Draw(screen mauview.Screen) {
|
||||
func (be *BaseEntity) Draw(screen mauview.Screen, ctx DrawContext) {
|
||||
panic("Called Draw() of BaseEntity")
|
||||
}
|
||||
|
@ -40,8 +40,8 @@ func NewBlockquoteEntity(children []Entity) *BlockquoteEntity {
|
||||
}}
|
||||
}
|
||||
|
||||
func (be *BlockquoteEntity) AdjustStyle(fn AdjustStyleFunc) Entity {
|
||||
be.BaseEntity = be.BaseEntity.AdjustStyle(fn).(*BaseEntity)
|
||||
func (be *BlockquoteEntity) AdjustStyle(fn AdjustStyleFunc, reason AdjustStyleReason) Entity {
|
||||
be.BaseEntity = be.BaseEntity.AdjustStyle(fn, reason).(*BaseEntity)
|
||||
return be
|
||||
}
|
||||
|
||||
@ -49,8 +49,8 @@ func (be *BlockquoteEntity) Clone() Entity {
|
||||
return &BlockquoteEntity{ContainerEntity: be.ContainerEntity.Clone().(*ContainerEntity)}
|
||||
}
|
||||
|
||||
func (be *BlockquoteEntity) Draw(screen mauview.Screen) {
|
||||
be.ContainerEntity.Draw(screen)
|
||||
func (be *BlockquoteEntity) Draw(screen mauview.Screen, ctx DrawContext) {
|
||||
be.ContainerEntity.Draw(screen, ctx)
|
||||
for y := 0; y < be.height; y++ {
|
||||
screen.SetContent(0, y, BlockQuoteChar, nil, be.Style)
|
||||
}
|
||||
|
@ -32,8 +32,8 @@ func NewBreakEntity() *BreakEntity {
|
||||
}
|
||||
|
||||
// AdjustStyle changes the style of this text entity.
|
||||
func (be *BreakEntity) AdjustStyle(fn AdjustStyleFunc) Entity {
|
||||
be.BaseEntity = be.BaseEntity.AdjustStyle(fn).(*BaseEntity)
|
||||
func (be *BreakEntity) AdjustStyle(fn AdjustStyleFunc, reason AdjustStyleReason) Entity {
|
||||
be.BaseEntity = be.BaseEntity.AdjustStyle(fn, reason).(*BaseEntity)
|
||||
return be
|
||||
}
|
||||
|
||||
@ -49,6 +49,6 @@ func (be *BreakEntity) String() string {
|
||||
return "&html.BreakEntity{},\n"
|
||||
}
|
||||
|
||||
func (be *BreakEntity) Draw(screen mauview.Screen) {
|
||||
func (be *BreakEntity) Draw(screen mauview.Screen, ctx DrawContext) {
|
||||
// No-op, the logic happens in containers
|
||||
}
|
||||
|
@ -46,12 +46,14 @@ func (ce *CodeBlockEntity) Clone() Entity {
|
||||
}
|
||||
}
|
||||
|
||||
func (ce *CodeBlockEntity) Draw(screen mauview.Screen) {
|
||||
func (ce *CodeBlockEntity) Draw(screen mauview.Screen, ctx DrawContext) {
|
||||
screen.Fill(' ', ce.Background)
|
||||
ce.ContainerEntity.Draw(screen)
|
||||
ce.ContainerEntity.Draw(screen, ctx)
|
||||
}
|
||||
|
||||
func (ce *CodeBlockEntity) AdjustStyle(fn AdjustStyleFunc) Entity {
|
||||
// Don't allow adjusting code block style.
|
||||
func (ce *CodeBlockEntity) AdjustStyle(fn AdjustStyleFunc, reason AdjustStyleReason) Entity {
|
||||
if reason != AdjustStyleReasonNormal {
|
||||
ce.ContainerEntity.AdjustStyle(fn, reason)
|
||||
}
|
||||
return ce
|
||||
}
|
||||
|
@ -61,15 +61,15 @@ func (ce *ContainerEntity) PlainText() string {
|
||||
}
|
||||
|
||||
// AdjustStyle recursively changes the style of this entity and all its children.
|
||||
func (ce *ContainerEntity) AdjustStyle(fn AdjustStyleFunc) Entity {
|
||||
func (ce *ContainerEntity) AdjustStyle(fn AdjustStyleFunc, reason AdjustStyleReason) Entity {
|
||||
for _, child := range ce.Children {
|
||||
child.AdjustStyle(fn)
|
||||
child.AdjustStyle(fn, reason)
|
||||
}
|
||||
ce.Style = fn(ce.Style)
|
||||
return ce
|
||||
}
|
||||
|
||||
// clone creates a deep copy of this base entity.
|
||||
// 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 {
|
||||
@ -98,7 +98,7 @@ func (ce *ContainerEntity) String() string {
|
||||
}
|
||||
|
||||
// Draw draws this entity onto the given mauview Screen.
|
||||
func (ce *ContainerEntity) Draw(screen mauview.Screen) {
|
||||
func (ce *ContainerEntity) Draw(screen mauview.Screen, ctx DrawContext) {
|
||||
if len(ce.Children) == 0 {
|
||||
return
|
||||
}
|
||||
@ -110,7 +110,7 @@ func (ce *ContainerEntity) Draw(screen mauview.Screen) {
|
||||
proxyScreen.OffsetY++
|
||||
}
|
||||
proxyScreen.Height = entity.Height()
|
||||
entity.Draw(proxyScreen)
|
||||
entity.Draw(proxyScreen, ctx)
|
||||
proxyScreen.SetStyle(ce.Style)
|
||||
proxyScreen.OffsetY += entity.Height() - 1
|
||||
_, isBreak := entity.(*BreakEntity)
|
||||
@ -122,8 +122,8 @@ func (ce *ContainerEntity) Draw(screen mauview.Screen) {
|
||||
}
|
||||
|
||||
// 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)
|
||||
func (ce *ContainerEntity) CalculateBuffer(width, startX int, ctx DrawContext) int {
|
||||
ce.BaseEntity.CalculateBuffer(width, startX, ctx)
|
||||
if len(ce.Children) > 0 {
|
||||
ce.height = 0
|
||||
childStartX := ce.startX
|
||||
@ -132,7 +132,7 @@ func (ce *ContainerEntity) CalculateBuffer(width, startX int, bare bool) int {
|
||||
if entity.IsBlock() || childStartX == 0 || ce.height == 0 {
|
||||
ce.height++
|
||||
}
|
||||
childStartX = entity.CalculateBuffer(width-ce.Indent, childStartX, bare)
|
||||
childStartX = entity.CalculateBuffer(width-ce.Indent, childStartX, ctx)
|
||||
ce.height += entity.Height() - 1
|
||||
_, isBreak := entity.(*BreakEntity)
|
||||
if prevBreak && isBreak {
|
||||
|
@ -24,11 +24,23 @@ import (
|
||||
// AdjustStyleFunc is a lambda function type to edit an existing tcell Style.
|
||||
type AdjustStyleFunc func(tcell.Style) tcell.Style
|
||||
|
||||
type AdjustStyleReason int
|
||||
|
||||
const (
|
||||
AdjustStyleReasonNormal AdjustStyleReason = iota
|
||||
AdjustStyleReasonHideSpoiler
|
||||
)
|
||||
|
||||
type DrawContext struct {
|
||||
IsSelected bool
|
||||
BareMessages bool
|
||||
}
|
||||
|
||||
type Entity interface {
|
||||
// AdjustStyle recursively changes the style of the entity and all its children.
|
||||
AdjustStyle(AdjustStyleFunc) Entity
|
||||
AdjustStyle(AdjustStyleFunc, AdjustStyleReason) Entity
|
||||
// Draw draws the entity onto the given mauview Screen.
|
||||
Draw(screen mauview.Screen)
|
||||
Draw(screen mauview.Screen, ctx DrawContext)
|
||||
// IsBlock returns whether or not it's a block-type entity.
|
||||
IsBlock() bool
|
||||
// GetTag returns the HTML tag of the entity.
|
||||
@ -43,7 +55,7 @@ type Entity interface {
|
||||
// Height returns the render height of the entity.
|
||||
Height() int
|
||||
// CalculateBuffer prepares the entity and all its children for rendering with the given parameters
|
||||
CalculateBuffer(width, startX int, bare bool) int
|
||||
CalculateBuffer(width, startX int, ctx DrawContext) int
|
||||
|
||||
getStartX() int
|
||||
|
||||
|
@ -36,8 +36,8 @@ func NewHorizontalLineEntity() *HorizontalLineEntity {
|
||||
}}
|
||||
}
|
||||
|
||||
func (he *HorizontalLineEntity) AdjustStyle(fn AdjustStyleFunc) Entity {
|
||||
he.BaseEntity = he.BaseEntity.AdjustStyle(fn).(*BaseEntity)
|
||||
func (he *HorizontalLineEntity) AdjustStyle(fn AdjustStyleFunc, reason AdjustStyleReason) Entity {
|
||||
he.BaseEntity = he.BaseEntity.AdjustStyle(fn, reason).(*BaseEntity)
|
||||
return he
|
||||
}
|
||||
|
||||
@ -45,7 +45,7 @@ func (he *HorizontalLineEntity) Clone() Entity {
|
||||
return NewHorizontalLineEntity()
|
||||
}
|
||||
|
||||
func (he *HorizontalLineEntity) Draw(screen mauview.Screen) {
|
||||
func (he *HorizontalLineEntity) Draw(screen mauview.Screen, ctx DrawContext) {
|
||||
width, _ := screen.Size()
|
||||
for x := 0; x < width; x++ {
|
||||
screen.SetContent(x, 0, HorizontalLineChar, nil, he.Style)
|
||||
|
@ -59,8 +59,9 @@ func NewListEntity(ordered bool, start int, children []Entity) *ListEntity {
|
||||
return entity
|
||||
}
|
||||
|
||||
func (le *ListEntity) AdjustStyle(fn AdjustStyleFunc) Entity {
|
||||
le.BaseEntity = le.BaseEntity.AdjustStyle(fn).(*BaseEntity)
|
||||
func (le *ListEntity) AdjustStyle(fn AdjustStyleFunc, reason AdjustStyleReason) Entity {
|
||||
le.BaseEntity = le.BaseEntity.AdjustStyle(fn, reason).(*BaseEntity)
|
||||
le.ContainerEntity.AdjustStyle(fn, reason)
|
||||
return le
|
||||
}
|
||||
|
||||
@ -72,7 +73,7 @@ func (le *ListEntity) Clone() Entity {
|
||||
}
|
||||
}
|
||||
|
||||
func (le *ListEntity) Draw(screen mauview.Screen) {
|
||||
func (le *ListEntity) Draw(screen mauview.Screen, ctx DrawContext) {
|
||||
width, _ := screen.Size()
|
||||
|
||||
proxyScreen := &mauview.ProxyScreen{Parent: screen, OffsetX: le.Indent, Width: width - le.Indent, Style: le.Style}
|
||||
@ -85,7 +86,7 @@ func (le *ListEntity) Draw(screen mauview.Screen) {
|
||||
} else {
|
||||
screen.SetContent(0, proxyScreen.OffsetY, '●', nil, le.Style)
|
||||
}
|
||||
entity.Draw(proxyScreen)
|
||||
entity.Draw(proxyScreen, ctx)
|
||||
proxyScreen.SetStyle(le.Style)
|
||||
proxyScreen.OffsetY += entity.Height()
|
||||
}
|
||||
|
@ -75,22 +75,23 @@ func AdjustStyleBackgroundColor(color tcell.Color) func(tcell.Style) tcell.Style
|
||||
}
|
||||
}
|
||||
|
||||
func (parser *htmlParser) getAttribute(node *html.Node, attribute string) string {
|
||||
func (parser *htmlParser) maybeGetAttribute(node *html.Node, attribute string) (string, bool) {
|
||||
for _, attr := range node.Attr {
|
||||
if attr.Key == attribute {
|
||||
return attr.Val
|
||||
return attr.Val, true
|
||||
}
|
||||
}
|
||||
return ""
|
||||
return "", false
|
||||
}
|
||||
|
||||
func (parser *htmlParser) getAttribute(node *html.Node, attribute string) string {
|
||||
val, _ := parser.maybeGetAttribute(node, attribute)
|
||||
return val
|
||||
}
|
||||
|
||||
func (parser *htmlParser) hasAttribute(node *html.Node, attribute string) bool {
|
||||
for _, attr := range node.Attr {
|
||||
if attr.Key == attribute {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
_, ok := parser.maybeGetAttribute(node, attribute)
|
||||
return ok
|
||||
}
|
||||
|
||||
func (parser *htmlParser) listToEntity(node *html.Node) Entity {
|
||||
@ -124,21 +125,25 @@ func (parser *htmlParser) basicFormatToEntity(node *html.Node) Entity {
|
||||
}
|
||||
switch node.Data {
|
||||
case "b", "strong":
|
||||
entity.AdjustStyle(AdjustStyleBold)
|
||||
entity.AdjustStyle(AdjustStyleBold, AdjustStyleReasonNormal)
|
||||
case "i", "em":
|
||||
entity.AdjustStyle(AdjustStyleItalic)
|
||||
entity.AdjustStyle(AdjustStyleItalic, AdjustStyleReasonNormal)
|
||||
case "s", "del", "strike":
|
||||
entity.AdjustStyle(AdjustStyleStrikethrough)
|
||||
entity.AdjustStyle(AdjustStyleStrikethrough, AdjustStyleReasonNormal)
|
||||
case "u", "ins":
|
||||
entity.AdjustStyle(AdjustStyleUnderline)
|
||||
entity.AdjustStyle(AdjustStyleUnderline, AdjustStyleReasonNormal)
|
||||
case "font", "span":
|
||||
fgColor, ok := parser.parseColor(node, "data-mx-color", "color")
|
||||
if ok {
|
||||
entity.AdjustStyle(AdjustStyleTextColor(fgColor))
|
||||
entity.AdjustStyle(AdjustStyleTextColor(fgColor), AdjustStyleReasonNormal)
|
||||
}
|
||||
bgColor, ok := parser.parseColor(node, "data-mx-bg-color", "background-color")
|
||||
if ok {
|
||||
entity.AdjustStyle(AdjustStyleBackgroundColor(bgColor))
|
||||
entity.AdjustStyle(AdjustStyleBackgroundColor(bgColor), AdjustStyleReasonNormal)
|
||||
}
|
||||
spoilerReason, isSpoiler := parser.maybeGetAttribute(node, "data-mx-spoiler")
|
||||
if isSpoiler {
|
||||
return NewSpoilerEntity(entity, spoilerReason)
|
||||
}
|
||||
}
|
||||
return entity
|
||||
@ -175,7 +180,7 @@ func (parser *htmlParser) headerToEntity(node *html.Node) Entity {
|
||||
[]Entity{NewTextEntity(strings.Repeat("#", int(node.Data[1]-'0')) + " ")},
|
||||
parser.nodeToEntities(node.FirstChild)...,
|
||||
),
|
||||
}).AdjustStyle(AdjustStyleBold)
|
||||
}).AdjustStyle(AdjustStyleBold, AdjustStyleReasonNormal)
|
||||
}
|
||||
|
||||
func (parser *htmlParser) blockquoteToEntity(node *html.Node) Entity {
|
||||
@ -468,7 +473,7 @@ func Parse(prefs *config.UserPreferences, room *rooms.Room, content *event.Messa
|
||||
},
|
||||
Children: []Entity{
|
||||
NewTextEntity("* "),
|
||||
NewTextEntity(senderDisplayname).AdjustStyle(AdjustStyleTextColor(widget.GetHashColor(sender))),
|
||||
NewTextEntity(senderDisplayname).AdjustStyle(AdjustStyleTextColor(widget.GetHashColor(sender)), AdjustStyleReasonNormal),
|
||||
NewTextEntity(" "),
|
||||
root,
|
||||
},
|
||||
|
120
ui/messages/html/spoiler.go
Normal file
120
ui/messages/html/spoiler.go
Normal file
@ -0,0 +1,120 @@
|
||||
// gomuks - A terminal Matrix client written in Go.
|
||||
// Copyright (C) 2022 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"
|
||||
|
||||
"go.mau.fi/mauview"
|
||||
"go.mau.fi/tcell"
|
||||
)
|
||||
|
||||
type SpoilerEntity struct {
|
||||
reason string
|
||||
hidden *ContainerEntity
|
||||
visible *ContainerEntity
|
||||
}
|
||||
|
||||
const SpoilerColor = tcell.ColorYellow
|
||||
|
||||
func NewSpoilerEntity(visible *ContainerEntity, reason string) *SpoilerEntity {
|
||||
hidden := visible.Clone().(*ContainerEntity)
|
||||
hidden.AdjustStyle(func(style tcell.Style) tcell.Style {
|
||||
return style.Foreground(SpoilerColor).Background(SpoilerColor)
|
||||
}, AdjustStyleReasonHideSpoiler)
|
||||
if len(reason) > 0 {
|
||||
reasonEnt := NewTextEntity(fmt.Sprintf("(%s)", reason))
|
||||
hidden.Children = append([]Entity{reasonEnt}, hidden.Children...)
|
||||
visible.Children = append([]Entity{reasonEnt}, visible.Children...)
|
||||
}
|
||||
return &SpoilerEntity{
|
||||
reason: reason,
|
||||
hidden: hidden,
|
||||
visible: visible,
|
||||
}
|
||||
}
|
||||
|
||||
func (se *SpoilerEntity) Clone() Entity {
|
||||
return &SpoilerEntity{
|
||||
reason: se.reason,
|
||||
hidden: se.hidden.Clone().(*ContainerEntity),
|
||||
visible: se.visible.Clone().(*ContainerEntity),
|
||||
}
|
||||
}
|
||||
|
||||
func (se *SpoilerEntity) IsBlock() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (se *SpoilerEntity) GetTag() string {
|
||||
return "span"
|
||||
}
|
||||
|
||||
func (se *SpoilerEntity) Draw(screen mauview.Screen, ctx DrawContext) {
|
||||
if ctx.IsSelected {
|
||||
se.visible.Draw(screen, ctx)
|
||||
} else {
|
||||
se.hidden.Draw(screen, ctx)
|
||||
}
|
||||
}
|
||||
|
||||
func (se *SpoilerEntity) AdjustStyle(fn AdjustStyleFunc, reason AdjustStyleReason) Entity {
|
||||
if reason != AdjustStyleReasonHideSpoiler {
|
||||
se.hidden.AdjustStyle(func(style tcell.Style) tcell.Style {
|
||||
return fn(style).Foreground(SpoilerColor).Background(SpoilerColor)
|
||||
}, reason)
|
||||
se.visible.AdjustStyle(fn, reason)
|
||||
}
|
||||
return se
|
||||
}
|
||||
|
||||
func (se *SpoilerEntity) PlainText() string {
|
||||
if len(se.reason) > 0 {
|
||||
return fmt.Sprintf("spoiler: %s", se.reason)
|
||||
} else {
|
||||
return "spoiler"
|
||||
}
|
||||
}
|
||||
|
||||
func (se *SpoilerEntity) String() string {
|
||||
var buf strings.Builder
|
||||
_, _ = fmt.Fprintf(&buf, `&html.SpoilerEntity{reason=%s`, se.reason)
|
||||
buf.WriteString("\n visible=")
|
||||
buf.WriteString(strings.Join(strings.Split(strings.TrimRight(se.visible.String(), "\n"), "\n"), "\n "))
|
||||
buf.WriteString("\n hidden=")
|
||||
buf.WriteString(strings.Join(strings.Split(strings.TrimRight(se.hidden.String(), "\n"), "\n"), "\n "))
|
||||
buf.WriteString("\n]},")
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
func (se *SpoilerEntity) Height() int {
|
||||
return se.visible.Height()
|
||||
}
|
||||
|
||||
func (se *SpoilerEntity) CalculateBuffer(width, startX int, ctx DrawContext) int {
|
||||
se.hidden.CalculateBuffer(width, startX, ctx)
|
||||
return se.visible.CalculateBuffer(width, startX, ctx)
|
||||
}
|
||||
|
||||
func (se *SpoilerEntity) getStartX() int {
|
||||
return se.visible.getStartX()
|
||||
}
|
||||
|
||||
func (se *SpoilerEntity) IsEmpty() bool {
|
||||
return se.visible.IsEmpty()
|
||||
}
|
@ -49,8 +49,8 @@ func (te *TextEntity) IsEmpty() bool {
|
||||
return len(te.Text) == 0
|
||||
}
|
||||
|
||||
func (te *TextEntity) AdjustStyle(fn AdjustStyleFunc) Entity {
|
||||
te.BaseEntity = te.BaseEntity.AdjustStyle(fn).(*BaseEntity)
|
||||
func (te *TextEntity) AdjustStyle(fn AdjustStyleFunc, reason AdjustStyleReason) Entity {
|
||||
te.BaseEntity = te.BaseEntity.AdjustStyle(fn, reason).(*BaseEntity)
|
||||
return te
|
||||
}
|
||||
|
||||
@ -69,7 +69,7 @@ func (te *TextEntity) String() string {
|
||||
return fmt.Sprintf("&html.TextEntity{Text=%s, Base=%s},\n", te.Text, te.BaseEntity)
|
||||
}
|
||||
|
||||
func (te *TextEntity) Draw(screen mauview.Screen) {
|
||||
func (te *TextEntity) Draw(screen mauview.Screen, ctx DrawContext) {
|
||||
width, _ := screen.Size()
|
||||
x := te.startX
|
||||
for y, line := range te.buffer {
|
||||
@ -78,8 +78,8 @@ func (te *TextEntity) Draw(screen mauview.Screen) {
|
||||
}
|
||||
}
|
||||
|
||||
func (te *TextEntity) CalculateBuffer(width, startX int, bare bool) int {
|
||||
te.BaseEntity.CalculateBuffer(width, startX, bare)
|
||||
func (te *TextEntity) CalculateBuffer(width, startX int, ctx DrawContext) int {
|
||||
te.BaseEntity.CalculateBuffer(width, startX, ctx)
|
||||
if len(te.Text) == 0 {
|
||||
return te.startX
|
||||
}
|
||||
@ -94,7 +94,7 @@ func (te *TextEntity) CalculateBuffer(width, startX int, bare bool) int {
|
||||
for {
|
||||
// TODO add option no wrap and character wrap options
|
||||
extract := runewidth.Truncate(text, width-textStartX, "")
|
||||
extract, wordWrapped := trim(extract, text, bare)
|
||||
extract, wordWrapped := trim(extract, text, ctx.BareMessages)
|
||||
if !wordWrapped && textStartX > 0 {
|
||||
if bufPtr < len(te.buffer) {
|
||||
te.buffer[bufPtr] = ""
|
||||
|
@ -28,9 +28,7 @@ import (
|
||||
|
||||
type HTMLMessage struct {
|
||||
Root html.Entity
|
||||
FocusedBg tcell.Color
|
||||
TextColor tcell.Color
|
||||
focused bool
|
||||
}
|
||||
|
||||
func NewHTMLMessage(evt *muksevt.Event, displayname string, root html.Entity) *UIMessage {
|
||||
@ -42,14 +40,10 @@ func NewHTMLMessage(evt *muksevt.Event, displayname string, root html.Entity) *U
|
||||
func (hw *HTMLMessage) Clone() MessageRenderer {
|
||||
return &HTMLMessage{
|
||||
Root: hw.Root.Clone(),
|
||||
FocusedBg: hw.FocusedBg,
|
||||
}
|
||||
}
|
||||
|
||||
func (hw *HTMLMessage) Draw(screen mauview.Screen) {
|
||||
if hw.focused {
|
||||
screen.SetStyle(tcell.StyleDefault.Background(hw.FocusedBg).Foreground(hw.TextColor))
|
||||
}
|
||||
func (hw *HTMLMessage) Draw(screen mauview.Screen, msg *UIMessage) {
|
||||
if hw.TextColor != tcell.ColorDefault {
|
||||
hw.Root.AdjustStyle(func(style tcell.Style) tcell.Style {
|
||||
fg, _, _ := style.Decompose()
|
||||
@ -57,18 +51,10 @@ func (hw *HTMLMessage) Draw(screen mauview.Screen) {
|
||||
return style.Foreground(hw.TextColor)
|
||||
}
|
||||
return style
|
||||
})
|
||||
}, html.AdjustStyleReasonNormal)
|
||||
}
|
||||
screen.Clear()
|
||||
hw.Root.Draw(screen)
|
||||
}
|
||||
|
||||
func (hw *HTMLMessage) Focus() {
|
||||
hw.focused = true
|
||||
}
|
||||
|
||||
func (hw *HTMLMessage) Blur() {
|
||||
hw.focused = false
|
||||
hw.Root.Draw(screen, html.DrawContext{IsSelected: msg.IsSelected})
|
||||
}
|
||||
|
||||
func (hw *HTMLMessage) OnKeyEvent(event mauview.KeyEvent) bool {
|
||||
@ -90,7 +76,10 @@ func (hw *HTMLMessage) CalculateBuffer(preferences config.UserPreferences, width
|
||||
// TODO account for bare messages in initial startX
|
||||
startX := 0
|
||||
hw.TextColor = msg.TextColor()
|
||||
hw.Root.CalculateBuffer(width, startX, preferences.BareMessageView)
|
||||
hw.Root.CalculateBuffer(width, startX, html.DrawContext{
|
||||
IsSelected: msg.IsSelected,
|
||||
BareMessages: preferences.BareMessageView,
|
||||
})
|
||||
}
|
||||
|
||||
func (hw *HTMLMessage) Height() int {
|
||||
|
@ -59,7 +59,7 @@ const RedactionMaxWidth = 40
|
||||
|
||||
var RedactionStyle = tcell.StyleDefault.Foreground(tcell.NewRGBColor(50, 0, 0))
|
||||
|
||||
func (msg *RedactedMessage) Draw(screen mauview.Screen) {
|
||||
func (msg *RedactedMessage) Draw(screen mauview.Screen, _ *UIMessage) {
|
||||
w, _ := screen.Size()
|
||||
for x := 0; x < w && x < RedactionMaxWidth; x++ {
|
||||
screen.SetContent(x, 0, RedactionChar, nil, RedactionStyle)
|
||||
|
@ -21,9 +21,9 @@ import (
|
||||
"time"
|
||||
|
||||
"go.mau.fi/mauview"
|
||||
"maunium.net/go/gomuks/matrix/muksevt"
|
||||
|
||||
"maunium.net/go/gomuks/config"
|
||||
"maunium.net/go/gomuks/matrix/muksevt"
|
||||
"maunium.net/go/gomuks/ui/messages/tstring"
|
||||
)
|
||||
|
||||
@ -95,7 +95,7 @@ func (msg *TextMessage) Height() int {
|
||||
return len(msg.buffer)
|
||||
}
|
||||
|
||||
func (msg *TextMessage) Draw(screen mauview.Screen) {
|
||||
func (msg *TextMessage) Draw(screen mauview.Screen, _ *UIMessage) {
|
||||
for y, line := range msg.buffer {
|
||||
line.Draw(screen, 0, y)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user