From 23bb46b18fa88ec870ba78cb7f08b296257b4ac5 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sun, 25 Mar 2018 14:21:59 +0300 Subject: Move room list to custom widget --- ui/view-main.go | 30 ++++------- ui/widget/message-view.go | 55 ++++---------------- ui/widget/room-list.go | 128 ++++++++++++++++++++++++++++++++++++++++++++++ ui/widget/util.go | 47 +++++++++++++++++ 4 files changed, 195 insertions(+), 65 deletions(-) create mode 100644 ui/widget/room-list.go create mode 100644 ui/widget/util.go diff --git a/ui/view-main.go b/ui/view-main.go index a5580b3..2014aea 100644 --- a/ui/view-main.go +++ b/ui/view-main.go @@ -37,7 +37,7 @@ import ( type MainView struct { *tview.Flex - roomList *tview.List + roomList *widget.RoomList roomView *tview.Pages rooms map[string]*widget.RoomView currentRoomIndex int @@ -54,7 +54,7 @@ type MainView struct { func (ui *GomuksUI) NewMainView() tview.Primitive { mainView := &MainView{ Flex: tview.NewFlex(), - roomList: tview.NewList(), + roomList: widget.NewRoomList(), roomView: tview.NewPages(), rooms: make(map[string]*widget.RoomView), @@ -64,12 +64,6 @@ func (ui *GomuksUI) NewMainView() tview.Primitive { parent: ui, } - mainView.roomList. - ShowSecondaryText(false). - SetSelectedBackgroundColor(tcell.ColorDarkGreen). - SetSelectedTextColor(tcell.ColorWhite). - SetBorderPadding(0, 0, 1, 0) - mainView.SetDirection(tview.FlexColumn) mainView.AddItem(mainView.roomList, 25, 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() if key.Modifiers() == tcell.ModCtrl || key.Modifiers() == tcell.ModAlt { - if k == tcell.KeyDown { + switch k { + case tcell.KeyDown: view.SwitchRoom(view.currentRoomIndex + 1) - view.roomList.SetCurrentItem(view.currentRoomIndex) - } else if k == tcell.KeyUp { + case tcell.KeyUp: view.SwitchRoom(view.currentRoomIndex - 1) - view.roomList.SetCurrentItem(view.currentRoomIndex) - } else { + default: return key } } 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.roomView.SwitchToPage(view.CurrentRoomID()) - view.roomList.SetCurrentItem(roomIndex) + view.roomList.SetSelected(view.rooms[view.CurrentRoomID()].Room) view.gmx.App().SetFocus(view) view.parent.Render() } @@ -289,9 +282,7 @@ func (view *MainView) SaveAllHistory() { func (view *MainView) addRoom(index int, room string) { roomStore := view.matrix.GetRoom(room) - view.roomList.AddItem(roomStore.GetTitle(), "", 0, func() { - view.SwitchRoom(index) - }) + view.roomList.Add(roomStore) if !view.roomView.HasPage(room) { roomView := widget.NewRoomView(roomStore). SetInputSubmitFunc(view.InputSubmit). @@ -334,7 +325,8 @@ func (view *MainView) AddRoom(room string) { } func (view *MainView) RemoveRoom(room string) { - if !view.HasRoom(room) { + roomView := view.GetRoom(room) + if roomView == nil { return } removeIndex := 0 @@ -344,7 +336,7 @@ func (view *MainView) RemoveRoom(room string) { } else { 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.roomView.RemovePage(room) delete(view.rooms, room) diff --git a/ui/widget/message-view.go b/ui/widget/message-view.go index 50de405..6f07c55 100644 --- a/ui/widget/message-view.go +++ b/ui/widget/message-view.go @@ -24,7 +24,6 @@ import ( "time" "github.com/gdamore/tcell" - "github.com/mattn/go-runewidth" "maunium.net/go/gomuks/ui/debug" "maunium.net/go/gomuks/ui/types" "maunium.net/go/tview" @@ -248,42 +247,6 @@ func (view *MessageView) IsAtTop() bool { 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 ( TimestampSenderGap = 1 SenderSeparatorGap = 1 @@ -293,11 +256,11 @@ const ( func (view *MessageView) Draw(screen tcell.Screen) { view.Box.Draw(screen) - x, y, _, height := view.GetInnerRect() + x, y, width, height := view.GetInnerRect() view.recalculateBuffers() 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 } @@ -311,7 +274,7 @@ func (view *MessageView) Draw(screen tcell.Screen) { if view.LoadingMessages { 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) { @@ -355,16 +318,16 @@ func (view *MessageView) Draw(screen tcell.Screen) { text, meta := view.textBuffer[index], view.metaBuffer[index] if meta != prevMeta { 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() { - view.writeLineRight( - screen, meta.GetSender(), - usernameX, y+line, - view.widestSender, meta.GetSenderColor()) + writeLine( + screen, tview.AlignRight, meta.GetSender(), + usernameX, y+line, view.widestSender, + meta.GetSenderColor()) } prevMeta = meta } - view.writeLine(screen, text, messageX, y+line, meta.GetTextColor()) + writeLine(screen, tview.AlignLeft, text, messageX, y+line, width, meta.GetTextColor()) } } diff --git a/ui/widget/room-list.go b/ui/widget/room-list.go new file mode 100644 index 0000000..b908510 --- /dev/null +++ b/ui/widget/room-list.go @@ -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 . + +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 + } + } +} diff --git a/ui/widget/util.go b/ui/widget/util.go new file mode 100644 index 0000000..5bde263 --- /dev/null +++ b/ui/widget/util.go @@ -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 . + +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 + } + } +} -- cgit v1.2.3