~sircmpwn/aerc

15b72df1dabb6675c20cff043648e97a209d2132 — Jeffas 1 year, 11 months ago c6f4d7b
Rework msglist scrolling

This changes the scrolling to be done on the draw, when the height is
updated, ensuring that the selected item is kept on screen during
resizing.

Also, this ensures that messages will fill the screen when resizing the
window, for instance, shrinking and then growing drags down more
messages if possible.

This is a transplant of the dirlist scrolling logic.
M commands/account/next-result.go => commands/account/next-result.go +2 -2
@@ 34,13 34,13 @@ func (NextPrevResult) Execute(aerc *widgets.Aerc, args []string) error {
		if store != nil {
			store.PrevResult()
		}
		acct.Messages().Scroll()
		acct.Messages().Invalidate()
	} else {
		store := acct.Store()
		if store != nil {
			store.NextResult()
		}
		acct.Messages().Scroll()
		acct.Messages().Invalidate()
	}
	return nil
}

M commands/account/next.go => commands/account/next.go +2 -2
@@ 65,13 65,13 @@ func ExecuteNextPrevMessage(args []string, acct *widgets.AccountView, pct bool, 
		store := acct.Store()
		if store != nil {
			store.NextPrev(-n)
			acct.Messages().Scroll()
			acct.Messages().Invalidate()
		}
	} else {
		store := acct.Store()
		if store != nil {
			store.NextPrev(n)
			acct.Messages().Scroll()
			acct.Messages().Invalidate()
		}
	}
	return nil

M commands/account/search.go => commands/account/search.go +1 -1
@@ 45,7 45,7 @@ func (SearchFilter) Execute(aerc *widgets.Aerc, args []string) error {
			acct.Logger().Printf("Search results: %v", uids)
			store.ApplySearch(uids)
			// TODO: Remove when stores have multiple OnUpdate handlers
			acct.Messages().Scroll()
			acct.Messages().Invalidate()
		}
	}
	store.Search(args, cb)

M commands/msg/archive.go => commands/msg/archive.go +1 -1
@@ 53,7 53,7 @@ func (Archive) Execute(aerc *widgets.Aerc, args []string) error {
	}
	archiveDir := acct.AccountConfig().Archive
	store.Next()
	acct.Messages().Scroll()
	acct.Messages().Invalidate()

	var uidMap map[string][]uint32
	switch args[1] {

M commands/msg/delete.go => commands/msg/delete.go +2 -2
@@ 62,7 62,7 @@ func (Delete) Execute(aerc *widgets.Aerc, args []string) error {
			// no more messages in the list
			if next == nil {
				aerc.RemoveTab(h.msgProvider)
				acct.Messages().Scroll()
				acct.Messages().Invalidate()
				return nil
			}
			lib.NewMessageStoreView(next, store, aerc.DecryptKeys,


@@ 76,7 76,7 @@ func (Delete) Execute(aerc *widgets.Aerc, args []string) error {
				})
		}
	}
	acct.Messages().Scroll()
	acct.Messages().Invalidate()
	return nil
}


M commands/msg/move.go => commands/msg/move.go +1 -1
@@ 62,7 62,7 @@ func (Move) Execute(aerc *widgets.Aerc, args []string) error {
		aerc.RemoveTab(h.msgProvider)
	}
	store.Next()
	acct.Messages().Scroll()
	acct.Messages().Invalidate()
	joinedArgs := strings.Join(args[optind:], " ")
	store.Move(uids, joinedArgs, createParents, func(
		msg types.WorkerMessage) {

M widgets/msglist.go => widgets/msglist.go +30 -14
@@ 63,6 63,8 @@ func (ml *MessageList) Draw(ctx *ui.Context) {
		}
	}

	ml.ensureScroll()

	var (
		needsHeaders []uint32
		row          int = 0


@@ 179,12 181,12 @@ func (ml *MessageList) MouseEvent(localX int, localY int, event tcell.Event) {
			if ml.store != nil {
				ml.store.Next()
			}
			ml.Scroll()
			ml.Invalidate()
		case tcell.WheelUp:
			if ml.store != nil {
				ml.store.Prev()
			}
			ml.Scroll()
			ml.Invalidate()
		}
	}
}


@@ 225,7 227,6 @@ func (ml *MessageList) storeUpdate(store *lib.MessageStore) {
		ml.nmsgs = len(uids)
	}

	ml.Scroll()
	ml.Invalidate()
}



@@ 266,25 267,40 @@ func (ml *MessageList) Selected() *models.MessageInfo {
func (ml *MessageList) Select(index int) {
	store := ml.Store()
	store.Select(index)
	ml.Scroll()
	ml.Invalidate()
}

func (ml *MessageList) Scroll() {
func (ml *MessageList) ensureScroll() {
	store := ml.Store()

	if store == nil || len(store.Uids()) == 0 {
		return
	}
	if ml.Height() != 0 {
		// I'm too lazy to do the math right now
		for store.SelectedIndex()-ml.scroll >= ml.Height() {
			ml.scroll += 1
		}
		for store.SelectedIndex()-ml.scroll < 0 {
			ml.scroll -= 1

	h := ml.Height()

	maxScroll := len(store.Uids()) - h
	if maxScroll < 0 {
		maxScroll = 0
	}

	selectedIndex := store.SelectedIndex()

	if selectedIndex >= ml.scroll && selectedIndex < ml.scroll+h {
		if ml.scroll > maxScroll {
			ml.scroll = maxScroll
		}
		return
	}

	if selectedIndex >= ml.scroll+h {
		ml.scroll = selectedIndex - h + 1
	} else if selectedIndex < ml.scroll {
		ml.scroll = selectedIndex
	}

	if ml.scroll > maxScroll {
		ml.scroll = maxScroll
	}
	ml.Invalidate()
}

func (ml *MessageList) drawEmptyMessage(ctx *ui.Context) {