Move room list to custom widget
This commit is contained in:
parent
c128666109
commit
23bb46b18f
@ -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)
|
||||||
|
@ -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
128
ui/widget/room-list.go
Normal 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
47
ui/widget/util.go
Normal 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user