From 6095638fbb0a39fa240a135cf47e54ce5681ee9d Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 26 Mar 2018 14:31:44 +0300 Subject: [PATCH] Fix and/or break scroll bar --- ui/view-main.go | 5 +++ ui/widget/message-view.go | 83 ++++++++++++++++++++++++--------------- 2 files changed, 57 insertions(+), 31 deletions(-) diff --git a/ui/view-main.go b/ui/view-main.go index 2014aea..94d09ab 100644 --- a/ui/view-main.go +++ b/ui/view-main.go @@ -232,11 +232,16 @@ func (view *MainView) MouseEventHandler(roomView *widget.RoomView, event *tcell. go view.LoadHistory(roomView.Room.ID, false) } else { msgView.AddScrollOffset(WheelScrollOffsetDiff) + + view.parent.Render() } case tcell.WheelDown: msgView.AddScrollOffset(-WheelScrollOffsetDiff) + + view.parent.Render() default: debug.Print("Mouse event received:", event.Buttons(), event.Modifiers(), x, y) + return event } return event diff --git a/ui/widget/message-view.go b/ui/widget/message-view.go index 6f07c55..332af94 100644 --- a/ui/widget/message-view.go +++ b/ui/widget/message-view.go @@ -214,20 +214,16 @@ func (view *MessageView) AddScrollOffset(diff int) { _, _, _, height := view.GetInnerRect() totalHeight := len(view.textBuffer) - if diff >= 0 && view.ScrollOffset >= totalHeight-height { - // If the user is at the top and presses page up again, add a bit of blank space. - if view.ScrollOffset+diff >= totalHeight-height+PaddingAtTop { - view.ScrollOffset = totalHeight - height + PaddingAtTop - } else { - view.ScrollOffset += diff - } - return + if diff >= 0 && view.ScrollOffset+diff >= totalHeight-height+PaddingAtTop { + view.ScrollOffset = totalHeight - height + PaddingAtTop + } else { + view.ScrollOffset += diff } - view.ScrollOffset += diff - if view.ScrollOffset > totalHeight-height { - view.ScrollOffset = totalHeight - height - } else if view.ScrollOffset < 0 { + if view.ScrollOffset > totalHeight-height+PaddingAtTop { + view.ScrollOffset = totalHeight - height + PaddingAtTop + } + if view.ScrollOffset < 0 { view.ScrollOffset = 0 } } @@ -253,6 +249,30 @@ const ( SenderMessageGap = 3 ) +func getScrollbarStyle(scrollbarHere, isTop, isBottom bool) (char rune, style tcell.Style) { + char = '│' + style = tcell.StyleDefault + if scrollbarHere { + style = style.Foreground(tcell.ColorGreen) + } + if isTop { + if scrollbarHere { + char = '╥' + } else { + char = '┬' + } + } else if isBottom { + if scrollbarHere { + char = '╨' + } else { + char = '┴' + } + } else if scrollbarHere { + char = '║' + } + return +} + func (view *MessageView) Draw(screen tcell.Screen) { view.Box.Draw(screen) @@ -260,7 +280,7 @@ func (view *MessageView) Draw(screen tcell.Screen) { view.recalculateBuffers() if len(view.textBuffer) == 0 { - writeLine(screen, tview.AlignLeft,"It's quite empty in here.", x, y+height, width, tcell.ColorDefault) + writeLine(screen, tview.AlignLeft, "It's quite empty in here.", x, y+height, width, tcell.ColorDefault) return } @@ -282,37 +302,38 @@ func (view *MessageView) Draw(screen tcell.Screen) { return } - totalHeight := float64(len(view.textBuffer)) - // The height of the scrollbar: ceil(height / (totalHeight / height)) - scrollBarHeight := int(math.Ceil(float64(height) / (totalHeight / float64(height)))) - // The position of the scrollbar from the bottom: height - ceil(scrollOffset) / totalHeight * height - scrollBarPos := height - int(math.Ceil(float64(view.ScrollOffset)/totalHeight*float64(height))) + var scrollBarHeight, scrollBarPos int + // Black magic (aka math) used to figure out where the scroll bar should be put. + { + viewportHeight := float64(height) + contentHeight := float64(len(view.textBuffer)) + + scrollBarHeight = int(math.Ceil(viewportHeight / (contentHeight / viewportHeight))) + + scrollBarPos = height - int(math.Round(float64(view.ScrollOffset)/contentHeight*viewportHeight)) + } var prevMeta types.MessageMeta firstLine := true + skippedLines := 0 for line := 0; line < height; line++ { index := indexOffset + line if index < 0 { + skippedLines++ continue } else if index >= len(view.textBuffer) { break } - borderChar := '│' - borderStyle := tcell.StyleDefault - if firstLine && view.ScrollOffset+height >= len(view.textBuffer) { - // At top of loaded message history - borderChar = '┬' - } else if line == height-1 && view.ScrollOffset == 0 { - // At bottom of message history - borderChar = '┴' - } else if line >= scrollBarPos && line < scrollBarPos+scrollBarHeight { - // Scroll bar - borderChar = '║' - borderStyle = borderStyle.Foreground(tcell.ColorGreen) - } + showScrollbar := line-skippedLines >= scrollBarPos-scrollBarHeight && line-skippedLines < scrollBarPos + isTop := firstLine && view.ScrollOffset+height >= len(view.textBuffer) + isBottom := line == height-1 && view.ScrollOffset == 0 + + borderChar, borderStyle := getScrollbarStyle(showScrollbar, isTop, isBottom) + firstLine = false + screen.SetContent(separatorX, y+line, borderChar, nil, borderStyle) text, meta := view.textBuffer[index], view.metaBuffer[index]