Move room list to custom widget

This commit is contained in:
Tulir Asokan 2018-03-25 14:21:59 +03:00
parent c128666109
commit 23bb46b18f
4 changed files with 195 additions and 65 deletions

View File

@ -37,7 +37,7 @@ import (
type MainView struct { type MainView struct {
*tview.Flex *tview.Flex
roomList *tview.List roomList *widget.RoomList
roomView *tview.Pages roomView *tview.Pages
rooms map[string]*widget.RoomView rooms map[string]*widget.RoomView
currentRoomIndex int currentRoomIndex int
@ -54,7 +54,7 @@ type MainView struct {
func (ui *GomuksUI) NewMainView() tview.Primitive { func (ui *GomuksUI) NewMainView() tview.Primitive {
mainView := &MainView{ mainView := &MainView{
Flex: tview.NewFlex(), Flex: tview.NewFlex(),
roomList: tview.NewList(), roomList: widget.NewRoomList(),
roomView: tview.NewPages(), roomView: tview.NewPages(),
rooms: make(map[string]*widget.RoomView), rooms: make(map[string]*widget.RoomView),
@ -64,12 +64,6 @@ func (ui *GomuksUI) NewMainView() tview.Primitive {
parent: ui, parent: ui,
} }
mainView.roomList.
ShowSecondaryText(false).
SetSelectedBackgroundColor(tcell.ColorDarkGreen).
SetSelectedTextColor(tcell.ColorWhite).
SetBorderPadding(0, 0, 1, 0)
mainView.SetDirection(tview.FlexColumn) mainView.SetDirection(tview.FlexColumn)
mainView.AddItem(mainView.roomList, 25, 0, false) mainView.AddItem(mainView.roomList, 25, 0, false)
mainView.AddItem(widget.NewBorder(), 1, 0, false) mainView.AddItem(widget.NewBorder(), 1, 0, false)
@ -186,13 +180,12 @@ func (view *MainView) KeyEventHandler(roomView *widget.RoomView, key *tcell.Even
k := key.Key() k := key.Key()
if key.Modifiers() == tcell.ModCtrl || key.Modifiers() == tcell.ModAlt { if key.Modifiers() == tcell.ModCtrl || key.Modifiers() == tcell.ModAlt {
if k == tcell.KeyDown { switch k {
case tcell.KeyDown:
view.SwitchRoom(view.currentRoomIndex + 1) view.SwitchRoom(view.currentRoomIndex + 1)
view.roomList.SetCurrentItem(view.currentRoomIndex) case tcell.KeyUp:
} else if k == tcell.KeyUp {
view.SwitchRoom(view.currentRoomIndex - 1) view.SwitchRoom(view.currentRoomIndex - 1)
view.roomList.SetCurrentItem(view.currentRoomIndex) default:
} else {
return key return key
} }
} else if k == tcell.KeyPgUp || k == tcell.KeyPgDn || k == tcell.KeyUp || k == tcell.KeyDown || k == tcell.KeyEnd || k == tcell.KeyHome { } else if k == tcell.KeyPgUp || k == tcell.KeyPgDn || k == tcell.KeyUp || k == tcell.KeyDown || k == tcell.KeyEnd || k == tcell.KeyHome {
@ -265,7 +258,7 @@ func (view *MainView) SwitchRoom(roomIndex int) {
} }
view.currentRoomIndex = roomIndex % len(view.roomIDs) view.currentRoomIndex = roomIndex % len(view.roomIDs)
view.roomView.SwitchToPage(view.CurrentRoomID()) view.roomView.SwitchToPage(view.CurrentRoomID())
view.roomList.SetCurrentItem(roomIndex) view.roomList.SetSelected(view.rooms[view.CurrentRoomID()].Room)
view.gmx.App().SetFocus(view) view.gmx.App().SetFocus(view)
view.parent.Render() view.parent.Render()
} }
@ -289,9 +282,7 @@ func (view *MainView) SaveAllHistory() {
func (view *MainView) addRoom(index int, room string) { func (view *MainView) addRoom(index int, room string) {
roomStore := view.matrix.GetRoom(room) roomStore := view.matrix.GetRoom(room)
view.roomList.AddItem(roomStore.GetTitle(), "", 0, func() { view.roomList.Add(roomStore)
view.SwitchRoom(index)
})
if !view.roomView.HasPage(room) { if !view.roomView.HasPage(room) {
roomView := widget.NewRoomView(roomStore). roomView := widget.NewRoomView(roomStore).
SetInputSubmitFunc(view.InputSubmit). SetInputSubmitFunc(view.InputSubmit).
@ -334,7 +325,8 @@ func (view *MainView) AddRoom(room string) {
} }
func (view *MainView) RemoveRoom(room string) { func (view *MainView) RemoveRoom(room string) {
if !view.HasRoom(room) { roomView := view.GetRoom(room)
if roomView == nil {
return return
} }
removeIndex := 0 removeIndex := 0
@ -344,7 +336,7 @@ func (view *MainView) RemoveRoom(room string) {
} else { } else {
removeIndex = sort.StringSlice(view.roomIDs).Search(room) removeIndex = sort.StringSlice(view.roomIDs).Search(room)
} }
view.roomList.RemoveItem(removeIndex) view.roomList.Remove(roomView.Room)
view.roomIDs = append(view.roomIDs[:removeIndex], view.roomIDs[removeIndex+1:]...) view.roomIDs = append(view.roomIDs[:removeIndex], view.roomIDs[removeIndex+1:]...)
view.roomView.RemovePage(room) view.roomView.RemovePage(room)
delete(view.rooms, room) delete(view.rooms, room)

View File

@ -24,7 +24,6 @@ import (
"time" "time"
"github.com/gdamore/tcell" "github.com/gdamore/tcell"
"github.com/mattn/go-runewidth"
"maunium.net/go/gomuks/ui/debug" "maunium.net/go/gomuks/ui/debug"
"maunium.net/go/gomuks/ui/types" "maunium.net/go/gomuks/ui/types"
"maunium.net/go/tview" "maunium.net/go/tview"
@ -248,42 +247,6 @@ func (view *MessageView) IsAtTop() bool {
return view.ScrollOffset >= totalHeight-height+PaddingAtTop return view.ScrollOffset >= totalHeight-height+PaddingAtTop
} }
func (view *MessageView) writeLine(screen tcell.Screen, line string, x, y int, color tcell.Color) {
offsetX := 0
for _, ch := range line {
chWidth := runewidth.RuneWidth(ch)
if chWidth == 0 {
continue
}
for localOffset := 0; localOffset < chWidth; localOffset++ {
screen.SetContent(x+offsetX+localOffset, y, ch, nil, tcell.StyleDefault.Foreground(color))
}
offsetX += chWidth
}
}
func (view *MessageView) writeLineRight(screen tcell.Screen, line string, x, y, maxWidth int, color tcell.Color) {
offsetX := maxWidth - runewidth.StringWidth(line)
if offsetX < 0 {
offsetX = 0
}
for _, ch := range line {
chWidth := runewidth.RuneWidth(ch)
if chWidth == 0 {
continue
}
for localOffset := 0; localOffset < chWidth; localOffset++ {
screen.SetContent(x+offsetX+localOffset, y, ch, nil, tcell.StyleDefault.Foreground(color))
}
offsetX += chWidth
if offsetX > maxWidth {
break
}
}
}
const ( const (
TimestampSenderGap = 1 TimestampSenderGap = 1
SenderSeparatorGap = 1 SenderSeparatorGap = 1
@ -293,11 +256,11 @@ const (
func (view *MessageView) Draw(screen tcell.Screen) { func (view *MessageView) Draw(screen tcell.Screen) {
view.Box.Draw(screen) view.Box.Draw(screen)
x, y, _, height := view.GetInnerRect() x, y, width, height := view.GetInnerRect()
view.recalculateBuffers() view.recalculateBuffers()
if len(view.textBuffer) == 0 { if len(view.textBuffer) == 0 {
view.writeLine(screen, "It's quite empty in here.", x, y+height, tcell.ColorDefault) writeLine(screen, tview.AlignLeft,"It's quite empty in here.", x, y+height, width, tcell.ColorDefault)
return return
} }
@ -311,7 +274,7 @@ func (view *MessageView) Draw(screen tcell.Screen) {
if view.LoadingMessages { if view.LoadingMessages {
message = "Loading more messages..." message = "Loading more messages..."
} }
view.writeLine(screen, message, messageX, y, tcell.ColorGreen) writeLine(screen, tview.AlignLeft, message, messageX, y, width, tcell.ColorGreen)
} }
if len(view.textBuffer) != len(view.metaBuffer) { if len(view.textBuffer) != len(view.metaBuffer) {
@ -355,16 +318,16 @@ func (view *MessageView) Draw(screen tcell.Screen) {
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.GetTimestamp()) > 0 { if len(meta.GetTimestamp()) > 0 {
view.writeLine(screen, meta.GetTimestamp(), x, y+line, meta.GetTimestampColor()) writeLine(screen, tview.AlignLeft, meta.GetTimestamp(), x, y+line, width, meta.GetTimestampColor())
} }
if prevMeta == nil || meta.GetSender() != prevMeta.GetSender() { if prevMeta == nil || meta.GetSender() != prevMeta.GetSender() {
view.writeLineRight( writeLine(
screen, meta.GetSender(), screen, tview.AlignRight, meta.GetSender(),
usernameX, y+line, usernameX, y+line, view.widestSender,
view.widestSender, meta.GetSenderColor()) meta.GetSenderColor())
} }
prevMeta = meta prevMeta = meta
} }
view.writeLine(screen, text, messageX, y+line, meta.GetTextColor()) writeLine(screen, tview.AlignLeft, text, messageX, y+line, width, meta.GetTextColor())
} }
} }

128
ui/widget/room-list.go Normal file
View File

@ -0,0 +1,128 @@
// gomuks - A terminal Matrix client written in Go.
// Copyright (C) 2018 Tulir Asokan
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package widget
import (
"github.com/gdamore/tcell"
"maunium.net/go/gomuks/matrix/rooms"
"maunium.net/go/tview"
)
type RoomList struct {
*tview.Box
indices map[*rooms.Room]int
items []*rooms.Room
selected *rooms.Room
// The item main text color.
mainTextColor tcell.Color
// The text color for selected items.
selectedTextColor tcell.Color
// The background color for selected items.
selectedBackgroundColor tcell.Color
}
func NewRoomList() *RoomList {
return &RoomList{
Box: tview.NewBox(),
indices: make(map[*rooms.Room]int),
items: []*rooms.Room{},
mainTextColor: tcell.ColorWhite,
selectedTextColor: tcell.ColorWhite,
selectedBackgroundColor: tcell.ColorDarkGreen,
}
}
func (list *RoomList) Add(room *rooms.Room) {
list.indices[room] = len(list.items)
list.items = append(list.items, room)
if list.selected == nil {
list.selected = room
}
}
func (list *RoomList) Remove(room *rooms.Room) {
index, ok := list.indices[room]
if !ok {
return
}
delete(list.indices, room)
list.items = append(list.items[0:index], list.items[index+1:]...)
if len(list.items) == 0 {
list.selected = nil
}
}
func (list *RoomList) Clear() {
list.indices = make(map[*rooms.Room]int)
list.items = []*rooms.Room{}
list.selected = nil
}
func (list *RoomList) SetSelected(room *rooms.Room) {
list.selected = room
}
// Draw draws this primitive onto the screen.
func (list *RoomList) Draw(screen tcell.Screen) {
list.Box.Draw(screen)
x, y, width, height := list.GetInnerRect()
bottomLimit := y + height
var offset int
currentItemIndex, hasSelected := list.indices[list.selected]
if hasSelected && currentItemIndex >= height {
offset = currentItemIndex + 1 - height
}
// Draw the list items.
for index, item := range list.items {
if index < offset {
continue
}
if y >= bottomLimit {
break
}
text := item.GetTitle()
writeLine(screen, tview.AlignLeft, text, x, y, width, list.mainTextColor)
// Background color of selected text.
if item == list.selected {
textWidth := tview.StringWidth(text)
for bx := 0; bx < textWidth && bx < width; bx++ {
m, c, style, _ := screen.GetContent(x+bx, y)
fg, _, _ := style.Decompose()
if fg == list.mainTextColor {
fg = list.selectedTextColor
}
style = style.Background(list.selectedBackgroundColor).Foreground(fg)
screen.SetContent(x+bx, y, m, c, style)
}
}
y++
if y >= bottomLimit {
break
}
}
}

47
ui/widget/util.go Normal file
View File

@ -0,0 +1,47 @@
// gomuks - A terminal Matrix client written in Go.
// Copyright (C) 2018 Tulir Asokan
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package widget
import (
"github.com/gdamore/tcell"
"github.com/mattn/go-runewidth"
"maunium.net/go/tview"
)
func writeLine(screen tcell.Screen, align int, line string, x, y, maxWidth int, color tcell.Color) {
offsetX := 0
if align == tview.AlignRight {
offsetX = maxWidth - runewidth.StringWidth(line)
}
if offsetX < 0 {
offsetX = 0
}
for _, ch := range line {
chWidth := runewidth.RuneWidth(ch)
if chWidth == 0 {
continue
}
for localOffset := 0; localOffset < chWidth; localOffset++ {
screen.SetContent(x+offsetX+localOffset, y, ch, nil, tcell.StyleDefault.Foreground(color))
}
offsetX += chWidth
if offsetX > maxWidth {
break
}
}
}