Add bare mode and fix terminal resize bug. Fixes #48

This commit is contained in:
Tulir Asokan 2018-05-22 22:06:48 +03:00
parent 4849ef08b8
commit 14903e0cdc
13 changed files with 158 additions and 86 deletions

View File

@ -43,5 +43,6 @@ type MatrixContainer interface {
GetRoom(roomID string) *rooms.Room GetRoom(roomID string) *rooms.Room
Download(mxcURL string) ([]byte, string, string, error) Download(mxcURL string) ([]byte, string, string, error)
GetDownloadURL(homeserver, fileID string) string
GetCachePath(homeserver, fileID string) string GetCachePath(homeserver, fileID string) string
} }

View File

@ -579,12 +579,15 @@ func (c *Container) Download(mxcURL string) (data []byte, hs, id string, err err
return return
} }
func (c *Container) download(hs, id, cacheFile string) (data []byte, err error) { func (c *Container) GetDownloadURL(hs, id string) string {
dlURL, _ := url.Parse(c.client.HomeserverURL.String()) dlURL, _ := url.Parse(c.client.HomeserverURL.String())
dlURL.Path = path.Join(dlURL.Path, "/_matrix/media/v1/download", hs, id) dlURL.Path = path.Join(dlURL.Path, "/_matrix/media/v1/download", hs, id)
return dlURL.String()
}
func (c *Container) download(hs, id, cacheFile string) (data []byte, err error) {
var resp *http.Response var resp *http.Response
resp, err = c.client.Client.Get(dlURL.String()) resp, err = c.client.Client.Get(c.GetDownloadURL(hs, id))
if err != nil { if err != nil {
return return
} }

View File

@ -50,6 +50,7 @@ type MessageView struct {
prevWidth int prevWidth int
prevHeight int prevHeight int
prevMsgCount int prevMsgCount int
prevBareMode bool
messageIDs map[string]messages.UIMessage messageIDs map[string]messages.UIMessage
messages []messages.UIMessage messages []messages.UIMessage
@ -76,6 +77,7 @@ func NewMessageView(parent *RoomView) *MessageView {
prevWidth: -1, prevWidth: -1,
prevHeight: -1, prevHeight: -1,
prevMsgCount: -1, prevMsgCount: -1,
prevBareMode: false,
} }
} }
@ -168,9 +170,12 @@ func (view *MessageView) AddMessage(ifcMessage ifc.Message, direction ifc.Messag
view.updateWidestSender(message.Sender()) view.updateWidestSender(message.Sender())
_, _, width, _ := view.GetInnerRect() _, _, width, _ := view.GetRect()
bare := view.parent.parent.bareDisplay
if !bare {
width -= view.TimestampWidth + TimestampSenderGap + view.widestSender + SenderMessageGap width -= view.TimestampWidth + TimestampSenderGap + view.widestSender + SenderMessageGap
message.CalculateBuffer(width) }
message.CalculateBuffer(bare, width)
if direction == ifc.AppendMessage { if direction == ifc.AppendMessage {
if view.ScrollOffset > 0 { if view.ScrollOffset > 0 {
@ -258,11 +263,13 @@ func (view *MessageView) replaceBuffer(original messages.UIMessage, new messages
} }
func (view *MessageView) recalculateBuffers() { func (view *MessageView) recalculateBuffers() {
_, _, width, height := view.GetInnerRect() _, _, width, height := view.GetRect()
bareMode := view.parent.parent.bareDisplay
if !bareMode {
width -= view.TimestampWidth + TimestampSenderGap + view.widestSender + SenderMessageGap width -= view.TimestampWidth + TimestampSenderGap + view.widestSender + SenderMessageGap
recalculateMessageBuffers := width != view.prevWidth }
if height != view.prevHeight || recalculateMessageBuffers || len(view.messages) != view.prevMsgCount { recalculateMessageBuffers := width != view.prevWidth || bareMode != view.prevBareMode
if recalculateMessageBuffers || len(view.messages) != view.prevMsgCount {
view.textBuffer = []tstring.TString{} view.textBuffer = []tstring.TString{}
view.metaBuffer = []ifc.MessageMeta{} view.metaBuffer = []ifc.MessageMeta{}
view.prevMsgCount = 0 view.prevMsgCount = 0
@ -272,13 +279,14 @@ func (view *MessageView) recalculateBuffers() {
break break
} }
if recalculateMessageBuffers { if recalculateMessageBuffers {
message.CalculateBuffer(width) message.CalculateBuffer(bareMode, width)
} }
view.appendBuffer(message) view.appendBuffer(message)
} }
}
view.prevHeight = height view.prevHeight = height
view.prevWidth = width view.prevWidth = width
} view.prevBareMode = bareMode
} }
func (view *MessageView) handleMessageClick(message ifc.MessageMeta) bool { func (view *MessageView) handleMessageClick(message ifc.MessageMeta) bool {
@ -362,7 +370,7 @@ func (view *MessageView) HandleClick(x, y int, button tcell.ButtonMask) bool {
const PaddingAtTop = 5 const PaddingAtTop = 5
func (view *MessageView) AddScrollOffset(diff int) { func (view *MessageView) AddScrollOffset(diff int) {
_, _, _, height := view.GetInnerRect() _, _, _, height := view.GetRect()
totalHeight := view.TotalHeight() totalHeight := view.TotalHeight()
if diff >= 0 && view.ScrollOffset+diff >= totalHeight-height+PaddingAtTop { if diff >= 0 && view.ScrollOffset+diff >= totalHeight-height+PaddingAtTop {
@ -380,7 +388,7 @@ func (view *MessageView) AddScrollOffset(diff int) {
} }
func (view *MessageView) Height() int { func (view *MessageView) Height() int {
_, _, _, height := view.GetInnerRect() _, _, _, height := view.GetRect()
return height return height
} }
@ -389,7 +397,7 @@ func (view *MessageView) TotalHeight() int {
} }
func (view *MessageView) IsAtTop() bool { func (view *MessageView) IsAtTop() bool {
_, _, _, height := view.GetInnerRect() _, _, _, height := view.GetRect()
totalHeight := len(view.textBuffer) totalHeight := len(view.textBuffer)
return view.ScrollOffset >= totalHeight-height+PaddingAtTop return view.ScrollOffset >= totalHeight-height+PaddingAtTop
} }
@ -442,14 +450,14 @@ func (view *MessageView) getIndexOffset(screen tcell.Screen, height, messageX in
if view.LoadingMessages { if view.LoadingMessages {
message = "Loading more messages..." message = "Loading more messages..."
} }
_, y, _, _ := view.GetInnerRect() _, y, _, _ := view.GetRect()
widget.WriteLineSimpleColor(screen, message, messageX, y, tcell.ColorGreen) widget.WriteLineSimpleColor(screen, message, messageX, y, tcell.ColorGreen)
} }
return return
} }
func (view *MessageView) Draw(screen tcell.Screen) { func (view *MessageView) Draw(screen tcell.Screen) {
x, y, _, height := view.GetInnerRect() x, y, _, height := view.GetRect()
view.recalculateBuffers() view.recalculateBuffers()
if view.TotalHeight() == 0 { if view.TotalHeight() == 0 {
@ -461,6 +469,11 @@ func (view *MessageView) Draw(screen tcell.Screen) {
messageX := usernameX + view.widestSender + SenderMessageGap messageX := usernameX + view.widestSender + SenderMessageGap
separatorX := usernameX + view.widestSender + SenderSeparatorGap separatorX := usernameX + view.widestSender + SenderSeparatorGap
bareMode := view.parent.parent.bareDisplay
if bareMode {
messageX = 0
}
indexOffset := view.getIndexOffset(screen, height, messageX) indexOffset := view.getIndexOffset(screen, height, messageX)
if len(view.textBuffer) != len(view.metaBuffer) { if len(view.textBuffer) != len(view.metaBuffer) {
@ -491,14 +504,16 @@ func (view *MessageView) Draw(screen tcell.Screen) {
firstLine = false firstLine = false
if !bareMode {
screen.SetContent(separatorX, y+line, borderChar, nil, borderStyle) screen.SetContent(separatorX, y+line, borderChar, nil, borderStyle)
}
text, meta := view.textBuffer[index], view.metaBuffer[index] text, meta := view.textBuffer[index], view.metaBuffer[index]
if meta != prevMeta { if meta != prevMeta {
if len(meta.FormatTime()) > 0 { if len(meta.FormatTime()) > 0 {
widget.WriteLineSimpleColor(screen, meta.FormatTime(), x, y+line, meta.TimestampColor()) widget.WriteLineSimpleColor(screen, meta.FormatTime(), x, y+line, meta.TimestampColor())
} }
if prevMeta == nil || meta.Sender() != prevMeta.Sender() { if !bareMode && (prevMeta == nil || meta.Sender() != prevMeta.Sender()) {
widget.WriteLineColor( widget.WriteLineColor(
screen, tview.AlignRight, meta.Sender(), screen, tview.AlignRight, meta.Sender(),
usernameX, y+line, view.widestSender, usernameX, y+line, view.widestSender,

View File

@ -41,7 +41,9 @@ type BaseMessage struct {
MsgIsHighlight bool MsgIsHighlight bool
MsgIsService bool MsgIsService bool
buffer []tstring.TString buffer []tstring.TString
plainBuffer []tstring.TString
prevBufferWidth int prevBufferWidth int
prevBareMode bool
} }
func newBaseMessage(id, sender, displayname, msgtype string, timestamp time.Time) BaseMessage { func newBaseMessage(id, sender, displayname, msgtype string, timestamp time.Time) BaseMessage {
@ -53,6 +55,7 @@ func newBaseMessage(id, sender, displayname, msgtype string, timestamp time.Time
MsgType: msgtype, MsgType: msgtype,
MsgID: id, MsgID: id,
prevBufferWidth: 0, prevBufferWidth: 0,
prevBareMode: false,
MsgState: ifc.MessageStateDefault, MsgState: ifc.MessageStateDefault,
MsgIsHighlight: false, MsgIsHighlight: false,
MsgIsService: false, MsgIsService: false,

View File

@ -28,14 +28,14 @@ func init() {
} }
type ExpandedTextMessage struct { type ExpandedTextMessage struct {
BaseTextMessage BaseMessage
MsgText tstring.TString MsgText tstring.TString
} }
// NewExpandedTextMessage creates a new ExpandedTextMessage object with the provided values and the default state. // NewExpandedTextMessage creates a new ExpandedTextMessage object with the provided values and the default state.
func NewExpandedTextMessage(id, sender, displayname, msgtype string, text tstring.TString, timestamp time.Time) UIMessage { func NewExpandedTextMessage(id, sender, displayname, msgtype string, text tstring.TString, timestamp time.Time) UIMessage {
return &ExpandedTextMessage{ return &ExpandedTextMessage{
BaseTextMessage: newBaseTextMessage(id, sender, displayname, msgtype, timestamp), BaseMessage: newBaseMessage(id, sender, displayname, msgtype, timestamp),
MsgText: text, MsgText: text,
} }
} }
@ -48,11 +48,15 @@ func (msg *ExpandedTextMessage) NotificationContent() string {
return msg.MsgText.String() return msg.MsgText.String()
} }
func (msg *ExpandedTextMessage) CalculateBuffer(width int) { func (msg *ExpandedTextMessage) PlainText() string {
msg.BaseTextMessage.calculateBufferWithText(msg.MsgText, width) return msg.MsgText.String()
}
func (msg *ExpandedTextMessage) CalculateBuffer(bare bool, width int) {
msg.calculateBufferWithText(bare, msg.MsgText, width)
} }
// RecalculateBuffer calculates the buffer again with the previously provided width. // RecalculateBuffer calculates the buffer again with the previously provided width.
func (msg *ExpandedTextMessage) RecalculateBuffer() { func (msg *ExpandedTextMessage) RecalculateBuffer() {
msg.CalculateBuffer(msg.prevBufferWidth) msg.CalculateBuffer(msg.prevBareMode, msg.prevBufferWidth)
} }

View File

@ -37,6 +37,7 @@ func init() {
type ImageMessage struct { type ImageMessage struct {
BaseMessage BaseMessage
Body string
Homeserver string Homeserver string
FileID string FileID string
data []byte data []byte
@ -45,9 +46,10 @@ type ImageMessage struct {
} }
// NewImageMessage creates a new ImageMessage object with the provided values and the default state. // NewImageMessage creates a new ImageMessage object with the provided values and the default state.
func NewImageMessage(matrix ifc.MatrixContainer, id, sender, displayname, msgtype, homeserver, fileID string, data []byte, timestamp time.Time) UIMessage { func NewImageMessage(matrix ifc.MatrixContainer, id, sender, displayname, msgtype, body, homeserver, fileID string, data []byte, timestamp time.Time) UIMessage {
return &ImageMessage{ return &ImageMessage{
newBaseMessage(id, sender, displayname, msgtype, timestamp), newBaseMessage(id, sender, displayname, msgtype, timestamp),
body,
homeserver, homeserver,
fileID, fileID,
data, data,
@ -67,6 +69,10 @@ func (msg *ImageMessage) NotificationContent() string {
return "Sent an image" return "Sent an image"
} }
func (msg *ImageMessage) PlainText() string {
return fmt.Sprintf("%s: %s", msg.Body, msg.matrix.GetDownloadURL(msg.Homeserver, msg.FileID))
}
func (msg *ImageMessage) updateData() { func (msg *ImageMessage) updateData() {
defer debug.Recover() defer debug.Recover()
debug.Print("Loading image:", msg.Homeserver, msg.FileID) debug.Print("Loading image:", msg.Homeserver, msg.FileID)
@ -86,11 +92,16 @@ func (msg *ImageMessage) Path() string {
// CalculateBuffer generates the internal buffer for this message that consists // CalculateBuffer generates the internal buffer for this message that consists
// of the text of this message split into lines at most as wide as the width // of the text of this message split into lines at most as wide as the width
// parameter. // parameter.
func (msg *ImageMessage) CalculateBuffer(width int) { func (msg *ImageMessage) CalculateBuffer(bare bool, width int) {
if width < 2 { if width < 2 {
return return
} }
if bare {
msg.calculateBufferWithText(bare, tstring.NewTString(msg.PlainText()), width)
return
}
image, err := ansimage.NewScaledFromReader(bytes.NewReader(msg.data), 0, width, color.Black) image, err := ansimage.NewScaledFromReader(bytes.NewReader(msg.data), 0, width, color.Black)
if err != nil { if err != nil {
msg.buffer = []tstring.TString{tstring.NewColorTString("Failed to display image", tcell.ColorRed)} msg.buffer = []tstring.TString{tstring.NewColorTString("Failed to display image", tcell.ColorRed)}
@ -100,9 +111,10 @@ func (msg *ImageMessage) CalculateBuffer(width int) {
msg.buffer = image.Render() msg.buffer = image.Render()
msg.prevBufferWidth = width msg.prevBufferWidth = width
msg.prevBareMode = false
} }
// RecalculateBuffer calculates the buffer again with the previously provided width. // RecalculateBuffer calculates the buffer again with the previously provided width.
func (msg *ImageMessage) RecalculateBuffer() { func (msg *ImageMessage) RecalculateBuffer() {
msg.CalculateBuffer(msg.prevBufferWidth) msg.CalculateBuffer(msg.prevBareMode, msg.prevBufferWidth)
} }

View File

@ -25,7 +25,7 @@ import (
type UIMessage interface { type UIMessage interface {
ifc.Message ifc.Message
CalculateBuffer(width int) CalculateBuffer(bare bool, width int)
RecalculateBuffer() RecalculateBuffer()
Buffer() []tstring.TString Buffer() []tstring.TString
Height() int Height() int

View File

@ -56,6 +56,7 @@ func ParseMessage(matrix ifc.MatrixContainer, room *rooms.Room, evt *gomatrix.Ev
displayname = member.DisplayName displayname = member.DisplayName
} }
msgtype, _ := evt.Content["msgtype"].(string) msgtype, _ := evt.Content["msgtype"].(string)
text, _ := evt.Content["body"].(string)
ts := unixToTime(evt.Timestamp) ts := unixToTime(evt.Timestamp)
switch msgtype { switch msgtype {
case "m.text", "m.notice", "m.emote": case "m.text", "m.notice", "m.emote":
@ -64,7 +65,6 @@ func ParseMessage(matrix ifc.MatrixContainer, room *rooms.Room, evt *gomatrix.Ev
text := ParseHTMLMessage(room, evt, displayname) text := ParseHTMLMessage(room, evt, displayname)
return messages.NewExpandedTextMessage(evt.ID, evt.Sender, displayname, msgtype, text, ts) return messages.NewExpandedTextMessage(evt.ID, evt.Sender, displayname, msgtype, text, ts)
} }
text, _ := evt.Content["body"].(string)
text = strings.Replace(text, "\t", " ", -1) text = strings.Replace(text, "\t", " ", -1)
return messages.NewTextMessage(evt.ID, evt.Sender, displayname, msgtype, text, ts) return messages.NewTextMessage(evt.ID, evt.Sender, displayname, msgtype, text, ts)
case "m.image": case "m.image":
@ -73,7 +73,7 @@ func ParseMessage(matrix ifc.MatrixContainer, room *rooms.Room, evt *gomatrix.Ev
if err != nil { if err != nil {
debug.Printf("Failed to download %s: %v", url, err) debug.Printf("Failed to download %s: %v", url, err)
} }
return messages.NewImageMessage(matrix, evt.ID, evt.Sender, displayname, msgtype, hs, id, data, ts) return messages.NewImageMessage(matrix, evt.ID, evt.Sender, displayname, msgtype, text, hs, id, data, ts)
} }
return nil return nil
} }

View File

@ -17,35 +17,26 @@
package messages package messages
import ( import (
"encoding/gob"
"regexp" "regexp"
"time"
"maunium.net/go/gomuks/ui/messages/tstring" "maunium.net/go/gomuks/ui/messages/tstring"
"fmt"
) )
func init() {
gob.Register(BaseTextMessage{})
}
type BaseTextMessage struct {
BaseMessage
}
func newBaseTextMessage(id, sender, displayname, msgtype string, timestamp time.Time) BaseTextMessage {
return BaseTextMessage{newBaseMessage(id, sender, displayname, msgtype, timestamp)}
}
// Regular expressions used to split lines when calculating the buffer. // Regular expressions used to split lines when calculating the buffer.
// //
// From tview/textview.go // From tview/textview.go
var ( var (
boundaryPattern = regexp.MustCompile("([[:punct:]]\\s*|\\s+)") boundaryPattern = regexp.MustCompile(`([[:punct:]]\s*|\s+)`)
bareBoundaryPattern = regexp.MustCompile(`(\s+)`)
spacePattern = regexp.MustCompile(`\s+`) spacePattern = regexp.MustCompile(`\s+`)
) )
func matchBoundaryPattern(extract tstring.TString) tstring.TString { func matchBoundaryPattern(bare bool, extract tstring.TString) tstring.TString {
matches := boundaryPattern.FindAllStringIndex(extract.String(), -1) regex := boundaryPattern
if bare {
regex = bareBoundaryPattern
}
matches := regex.FindAllStringIndex(extract.String(), -1)
if len(matches) > 0 { if len(matches) > 0 {
if match := matches[len(matches)-1]; len(match) >= 2 { if match := matches[len(matches)-1]; len(match) >= 2 {
if until := match[1]; until < len(extract) { if until := match[1]; until < len(extract) {
@ -59,13 +50,20 @@ func matchBoundaryPattern(extract tstring.TString) tstring.TString {
// CalculateBuffer generates the internal buffer for this message that consists // CalculateBuffer generates the internal buffer for this message that consists
// of the text of this message split into lines at most as wide as the width // of the text of this message split into lines at most as wide as the width
// parameter. // parameter.
func (msg *BaseTextMessage) calculateBufferWithText(text tstring.TString, width int) { func (msg *BaseMessage) calculateBufferWithText(bare bool, text tstring.TString, width int) {
if width < 2 { if width < 2 {
return return
} }
msg.buffer = []tstring.TString{} msg.buffer = []tstring.TString{}
if bare {
text = tstring.
NewTString(msg.FormatTime()).
AppendTString(tstring.NewColorTString(fmt.Sprintf(" <%s> ", msg.Sender()), msg.SenderColor())).
AppendTString(text)
}
forcedLinebreaks := text.Split('\n') forcedLinebreaks := text.Split('\n')
newlines := 0 newlines := 0
for _, str := range forcedLinebreaks { for _, str := range forcedLinebreaks {
@ -82,11 +80,12 @@ func (msg *BaseTextMessage) calculateBufferWithText(text tstring.TString, width
if spaces := spacePattern.FindStringIndex(str[len(extract):].String()); spaces != nil && spaces[0] == 0 { if spaces := spacePattern.FindStringIndex(str[len(extract):].String()); spaces != nil && spaces[0] == 0 {
extract = str[:len(extract)+spaces[1]] extract = str[:len(extract)+spaces[1]]
} }
extract = matchBoundaryPattern(extract) extract = matchBoundaryPattern(bare, extract)
} }
msg.buffer = append(msg.buffer, extract) msg.buffer = append(msg.buffer, extract)
str = str[len(extract):] str = str[len(extract):]
} }
} }
msg.prevBufferWidth = width msg.prevBufferWidth = width
msg.prevBareMode = bare
} }

View File

@ -30,7 +30,7 @@ func init() {
} }
type TextMessage struct { type TextMessage struct {
BaseTextMessage BaseMessage
cache tstring.TString cache tstring.TString
MsgText string MsgText string
} }
@ -38,7 +38,7 @@ type TextMessage struct {
// NewTextMessage creates a new UITextMessage object with the provided values and the default state. // NewTextMessage creates a new UITextMessage object with the provided values and the default state.
func NewTextMessage(id, sender, displayname, msgtype, text string, timestamp time.Time) UIMessage { func NewTextMessage(id, sender, displayname, msgtype, text string, timestamp time.Time) UIMessage {
return &TextMessage{ return &TextMessage{
BaseTextMessage: newBaseTextMessage(id, sender, displayname, msgtype, timestamp), BaseMessage: newBaseMessage(id, sender, displayname, msgtype, timestamp),
MsgText: text, MsgText: text,
} }
} }
@ -57,22 +57,22 @@ func (msg *TextMessage) getCache() tstring.TString {
} }
func (msg *TextMessage) SetType(msgtype string) { func (msg *TextMessage) SetType(msgtype string) {
msg.BaseTextMessage.SetType(msgtype) msg.BaseMessage.SetType(msgtype)
msg.cache = nil msg.cache = nil
} }
func (msg *TextMessage) SetState(state ifc.MessageState) { func (msg *TextMessage) SetState(state ifc.MessageState) {
msg.BaseTextMessage.SetState(state) msg.BaseMessage.SetState(state)
msg.cache = nil msg.cache = nil
} }
func (msg *TextMessage) SetIsHighlight(isHighlight bool) { func (msg *TextMessage) SetIsHighlight(isHighlight bool) {
msg.BaseTextMessage.SetIsHighlight(isHighlight) msg.BaseMessage.SetIsHighlight(isHighlight)
msg.cache = nil msg.cache = nil
} }
func (msg *TextMessage) SetIsService(isService bool) { func (msg *TextMessage) SetIsService(isService bool) {
msg.BaseTextMessage.SetIsService(isService) msg.BaseMessage.SetIsService(isService)
msg.cache = nil msg.cache = nil
} }
@ -80,11 +80,15 @@ func (msg *TextMessage) NotificationContent() string {
return msg.MsgText return msg.MsgText
} }
func (msg *TextMessage) CalculateBuffer(width int) { func (msg *TextMessage) PlainText() string {
msg.BaseTextMessage.calculateBufferWithText(msg.getCache(), width) return msg.MsgText
}
func (msg *TextMessage) CalculateBuffer(bare bool, width int) {
msg.calculateBufferWithText(bare, msg.getCache(), width)
} }
// RecalculateBuffer calculates the buffer again with the previously provided width. // RecalculateBuffer calculates the buffer again with the previously provided width.
func (msg *TextMessage) RecalculateBuffer() { func (msg *TextMessage) RecalculateBuffer() {
msg.CalculateBuffer(msg.prevBufferWidth) msg.CalculateBuffer(msg.prevBareMode, msg.prevBufferWidth)
} }

View File

@ -426,7 +426,7 @@ func (list *RoomList) GetTagDisplayName(tag string) string {
func (list *RoomList) Draw(screen tcell.Screen) { func (list *RoomList) Draw(screen tcell.Screen) {
list.Box.Draw(screen) list.Box.Draw(screen)
x, y, width, height := list.GetInnerRect() x, y, width, height := list.GetRect()
yLimit := y + height yLimit := y + height
y -= list.scrollOffset y -= list.scrollOffset

View File

@ -147,23 +147,11 @@ func (view *RoomView) Focus(delegate func(p tview.Primitive)) {
delegate(view.input) delegate(view.input)
} }
// Constants defining the size of the room view grid.
const (
UserListBorderWidth = 1
UserListWidth = 20
StaticHorizontalSpace = UserListBorderWidth + UserListWidth
TopicBarHeight = 1
StatusBarHeight = 1
InputBarHeight = 1
StaticVerticalSpace = TopicBarHeight + StatusBarHeight + InputBarHeight
)
func (view *RoomView) GetStatus() string { func (view *RoomView) GetStatus() string {
var buf strings.Builder var buf strings.Builder
if len(view.completions.list) > 0 { if len(view.completions.list) > 0 {
if view.completions.textCache != view.input.GetText() || view.completions.time.Add(10*time.Second).Before(time.Now()) { if view.completions.textCache != view.input.GetText() || view.completions.time.Add(10 * time.Second).Before(time.Now()) {
view.completions.list = []string{} view.completions.list = []string{}
} else { } else {
buf.WriteString(strings.Join(view.completions.list, ", ")) buf.WriteString(strings.Join(view.completions.list, ", "))
@ -184,11 +172,23 @@ func (view *RoomView) GetStatus() string {
} }
func (view *RoomView) Draw(screen tcell.Screen) { func (view *RoomView) Draw(screen tcell.Screen) {
x, y, width, height := view.GetInnerRect() x, y, width, height := view.GetRect()
if width <= 0 || height <= 0 { if width <= 0 || height <= 0 {
return return
} }
// Constants defining the size of the room view grid.
const (
UserListBorderWidth = 1
UserListWidth = 20
StaticHorizontalSpace = UserListBorderWidth + UserListWidth
TopicBarHeight = 1
StatusBarHeight = 1
InputBarHeight = 1
StaticVerticalSpace = TopicBarHeight + StatusBarHeight + InputBarHeight
)
// Calculate actual grid based on view rectangle and constants defined above. // Calculate actual grid based on view rectangle and constants defined above.
var ( var (
contentHeight = height - StaticVerticalSpace contentHeight = height - StaticVerticalSpace
@ -202,12 +202,15 @@ func (view *RoomView) Draw(screen tcell.Screen) {
statusRow = contentRow + contentHeight statusRow = contentRow + contentHeight
inputRow = statusRow + StatusBarHeight inputRow = statusRow + StatusBarHeight
) )
if !view.parent.ShowUserList() {
contentWidth = width
}
// Update the rectangles of all the children. // Update the rectangles of all the children.
view.topic.SetRect(x, topicRow, width, TopicBarHeight) view.topic.SetRect(x, topicRow, width, TopicBarHeight)
view.content.SetRect(x, contentRow, contentWidth, contentHeight) view.content.SetRect(x, contentRow, contentWidth, contentHeight)
view.status.SetRect(x, statusRow, width, StatusBarHeight) view.status.SetRect(x, statusRow, width, StatusBarHeight)
if userListColumn > x { if view.parent.ShowUserList() && userListColumn > x {
view.userList.SetRect(userListColumn, contentRow, UserListWidth, contentHeight) view.userList.SetRect(userListColumn, contentRow, UserListWidth, contentHeight)
view.ulBorder.SetRect(userListBorderColumn, contentRow, UserListBorderWidth, contentHeight) view.ulBorder.SetRect(userListBorderColumn, contentRow, UserListBorderWidth, contentHeight)
} }
@ -220,8 +223,10 @@ func (view *RoomView) Draw(screen tcell.Screen) {
view.status.SetText(view.GetStatus()) view.status.SetText(view.GetStatus())
view.status.Draw(screen) view.status.Draw(screen)
view.input.Draw(screen) view.input.Draw(screen)
if view.parent.ShowUserList() {
view.ulBorder.Draw(screen) view.ulBorder.Draw(screen)
view.userList.Draw(screen) view.userList.Draw(screen)
}
} }
func (view *RoomView) SetCompletions(completions []string) { func (view *RoomView) SetCompletions(completions []string) {

View File

@ -48,6 +48,18 @@ type MainView struct {
gmx ifc.Gomuks gmx ifc.Gomuks
config *config.Config config *config.Config
parent *GomuksUI parent *GomuksUI
hideUserList bool
hideRoomList bool
bareDisplay bool
}
func (view *MainView) ShowRoomList() bool {
return !view.bareDisplay && !view.hideRoomList
}
func (view *MainView) ShowUserList() bool {
return !view.bareDisplay && !view.hideUserList
} }
func (ui *GomuksUI) NewMainView() tview.Primitive { func (ui *GomuksUI) NewMainView() tview.Primitive {
@ -63,10 +75,11 @@ func (ui *GomuksUI) NewMainView() tview.Primitive {
parent: ui, parent: ui,
} }
mainView.SetDirection(tview.FlexColumn) mainView.
mainView.AddItem(mainView.roomList, 25, 0, false) SetDirection(tview.FlexColumn).
mainView.AddItem(widget.NewBorder(), 1, 0, false) AddItem(mainView.roomList, 25, 0, false).
mainView.AddItem(mainView.roomView, 0, 1, true) AddItem(widget.NewBorder(), 1, 0, false).
AddItem(mainView.roomView, 0, 1, true)
mainView.BumpFocus(nil) mainView.BumpFocus(nil)
ui.mainView = mainView ui.mainView = mainView
@ -74,6 +87,15 @@ func (ui *GomuksUI) NewMainView() tview.Primitive {
return mainView return mainView
} }
func (view *MainView) Draw(screen tcell.Screen) {
if !view.ShowRoomList() {
view.roomView.SetRect(view.GetRect())
view.roomView.Draw(screen)
} else {
view.Flex.Draw(screen)
}
}
func (view *MainView) BumpFocus(roomView *RoomView) { func (view *MainView) BumpFocus(roomView *RoomView) {
view.lastFocusTime = time.Now() view.lastFocusTime = time.Now()
view.MarkRead(roomView) view.MarkRead(roomView)
@ -195,16 +217,20 @@ func (view *MainView) KeyEventHandler(roomView *RoomView, key *tcell.EventKey) *
view.BumpFocus(roomView) view.BumpFocus(roomView)
k := key.Key() k := key.Key()
c := key.Rune()
if key.Modifiers() == tcell.ModCtrl || key.Modifiers() == tcell.ModAlt { if key.Modifiers() == tcell.ModCtrl || key.Modifiers() == tcell.ModAlt {
switch k { switch {
case tcell.KeyDown: case k == tcell.KeyDown:
view.SwitchRoom(view.roomList.Next()) view.SwitchRoom(view.roomList.Next())
case tcell.KeyUp: case k == tcell.KeyUp:
view.SwitchRoom(view.roomList.Previous()) view.SwitchRoom(view.roomList.Previous())
case tcell.KeyEnter: case k == tcell.KeyEnter:
searchModal := NewFuzzySearchModal(view, 42, 12) searchModal := NewFuzzySearchModal(view, 42, 12)
view.parent.views.AddPage("fuzzy-search-modal", searchModal, true, true) view.parent.views.AddPage("fuzzy-search-modal", searchModal, true, true)
view.parent.app.SetFocus(searchModal) view.parent.app.SetFocus(searchModal)
case c == 'l':
view.bareDisplay = !view.bareDisplay
view.parent.Render()
default: default:
return key return key
} }