Improved scrolling.

* Added scrolling with scroll wheel on mouse.
 * Added scrolling with vim style j/k keys.
 * Changed scrolling so that it is more smooth and the whole screen is
   not redrawn each time
 * Changed channel keyboardQueue to a buffered queue, so there are not
   too many scroll requests, and the draw commands can be done once the
   queue is empty.
 * Added UpDownJump in profile, so user can set how much PgUp/PgDown jumps

 * Have not tested with a _huge_ number of stocks in ticker, probably
   worth doing
master
root 3 years ago
parent 6f78b90964
commit e1f62d6afc
  1. 46
      cmd/mop/main.go
  2. 6
      profile.go
  3. 4
      screen.go

@ -33,8 +33,8 @@ NO WARRANTIES OF ANY KIND WHATSOEVER. SEE THE LICENSE FILE FOR DETAILS.
g Group stocks by advancing/declining issues. g Group stocks by advancing/declining issues.
o Change column sort order. o Change column sort order.
p Pause market data and stock updates. p Pause market data and stock updates.
PgDn Scroll Down, down arrow key also works. Scroll Scroll up/down.
PgUp Scroll up, up arrow key also works. PgUp/PgDn; Up/Down arrow; j/k;J/K also all scroll up/down
q Quit mop. q Quit mop.
esc Ditto. esc Ditto.
@ -48,13 +48,18 @@ func mainLoop(screen *mop.Screen, profile *mop.Profile) {
var lineEditor *mop.LineEditor var lineEditor *mop.LineEditor
var columnEditor *mop.ColumnEditor var columnEditor *mop.ColumnEditor
keyboardQueue := make(chan termbox.Event) termbox.SetInputMode(termbox.InputMouse)
// use buffered channel for keyboard event queue
keyboardQueue := make(chan termbox.Event, 16)
timestampQueue := time.NewTicker(1 * time.Second) timestampQueue := time.NewTicker(1 * time.Second)
quotesQueue := time.NewTicker(5 * time.Second) quotesQueue := time.NewTicker(5 * time.Second)
marketQueue := time.NewTicker(12 * time.Second) marketQueue := time.NewTicker(12 * time.Second)
showingHelp := false showingHelp := false
paused := false paused := false
pgUpDownLines := 10 upDownJump := profile.UpDownJump
redrawQuotesFlag := false
go func() { go func() {
for { for {
@ -96,13 +101,19 @@ loop:
showingHelp = true showingHelp = true
screen.Clear().Draw(help) screen.Clear().Draw(help)
} else if event.Key == termbox.KeyPgdn || } else if event.Key == termbox.KeyPgdn ||
event.Key == termbox.KeyArrowDown { event.Ch == 'J' {
screen.IncreaseOffset(pgUpDownLines, len(profile.Tickers)) screen.IncreaseOffset(upDownJump, len(profile.Tickers))
screen.Clear().Draw(market, quotes) redrawQuotesFlag = true
} else if event.Key == termbox.KeyPgup || } else if event.Key == termbox.KeyPgup ||
event.Key == termbox.KeyArrowUp { event.Ch == 'K' {
screen.DecreaseOffset(pgUpDownLines) screen.DecreaseOffset(upDownJump)
screen.Clear().Draw(market, quotes) redrawQuotesFlag = true
} else if event.Key == termbox.KeyArrowUp || event.Ch == 'k' {
screen.DecreaseOffset(1)
redrawQuotesFlag = true
} else if event.Key == termbox.KeyArrowDown || event.Ch == 'j' {
screen.IncreaseOffset(1, len(profile.Tickers))
redrawQuotesFlag = true
} }
} else if lineEditor != nil { } else if lineEditor != nil {
if done := lineEditor.Handle(event); done { if done := lineEditor.Handle(event); done {
@ -123,6 +134,17 @@ loop:
} else { } else {
screen.Draw(help) screen.Draw(help)
} }
case termbox.EventMouse:
if lineEditor == nil && columnEditor == nil && !showingHelp {
switch event.Key {
case termbox.MouseWheelUp:
screen.DecreaseOffset(1)
redrawQuotesFlag = true
case termbox.MouseWheelDown:
screen.IncreaseOffset(1, len(profile.Tickers))
redrawQuotesFlag = true
}
}
} }
case <-timestampQueue.C: case <-timestampQueue.C:
@ -140,6 +162,10 @@ loop:
screen.Draw(market) screen.Draw(market)
} }
} }
if redrawQuotesFlag && len(keyboardQueue) == 0 {
screen.Draw(quotes)
}
} }
} }

@ -31,6 +31,7 @@ type Profile struct {
Ascending bool // True when sort order is ascending. Ascending bool // True when sort order is ascending.
Grouped bool // True when stocks are grouped by advancing/declining. Grouped bool // True when stocks are grouped by advancing/declining.
Filter string // Filter in human form Filter string // Filter in human form
UpDownJump int // Number of lines to go up/down when scrolling.
Colors struct { // User defined colors Colors struct { // User defined colors
Gain string Gain string
Loss string Loss string
@ -93,6 +94,10 @@ func NewProfile(filename string) (*Profile, error) {
} }
profile.selectedColumn = -1 profile.selectedColumn = -1
if profile.UpDownJump < 1 {
profile.UpDownJump = 10
}
return profile, err return profile, err
} }
@ -105,6 +110,7 @@ func (profile *Profile) InitDefaultProfile() {
profile.SortColumn = 0 // Stock quotes are sorted by ticker name. profile.SortColumn = 0 // Stock quotes are sorted by ticker name.
profile.Ascending = true // A to Z. profile.Ascending = true // A to Z.
profile.Filter = "" profile.Filter = ""
profile.UpDownJump = 10
profile.Colors.Gain = defaultGainColor profile.Colors.Gain = defaultGainColor
profile.Colors.Loss = defaultLossColor profile.Colors.Loss = defaultLossColor
profile.Colors.Tag = defaultTagColor profile.Colors.Tag = defaultTagColor

@ -92,7 +92,7 @@ func (screen *Screen) ClearLine(x int, y int) *Screen {
// Increase the offset for scrolling feature by n // Increase the offset for scrolling feature by n
// Takes number of tickers as max, so not scrolling down forever // Takes number of tickers as max, so not scrolling down forever
func (screen *Screen) IncreaseOffset(n int, max int) { func (screen *Screen) IncreaseOffset(n int, max int) {
if screen.offset+n < max { if screen.offset+n+1 < max {
screen.offset += n screen.offset += n
} }
} }
@ -205,7 +205,7 @@ func (screen *Screen) draw(str string, offset bool) {
// cycle. In that case, padding with blank lines would overwrite the // cycle. In that case, padding with blank lines would overwrite the
// stocks list.) // stocks list.)
if drewHeading { if drewHeading {
for i := len(allLines) - 1; i < screen.height; i++ { for i := len(allLines) - 1 - screen.offset; i < screen.height; i++ {
screen.DrawLine(0, i, blankLine) screen.DrawLine(0, i, blankLine)
} }
} }

Loading…
Cancel
Save