diff options
| author | Drew DeVault <sir@cmpwn.com> | 2019-01-13 15:10:47 -0500 | 
|---|---|---|
| committer | Drew DeVault <sir@cmpwn.com> | 2019-01-13 15:10:47 -0500 | 
| commit | 3157897c1a20e5638feaf56e753b7886bc4ba267 (patch) | |
| tree | d47b8ea1654a5627811df1e5ad5c5cfd172358fc | |
| parent | 755aa9af731c6faac64cbe3ad77324fb2850a7ae (diff) | |
Add abstract list, update dirlist accordingly
| -rw-r--r-- | lib/ui/grid.go | 1 | ||||
| -rw-r--r-- | lib/ui/list.go | 110 | ||||
| -rw-r--r-- | widgets/directories.go | 71 | 
3 files changed, 156 insertions, 26 deletions
diff --git a/lib/ui/grid.go b/lib/ui/grid.go index 3c375ee..5fe6ab2 100644 --- a/lib/ui/grid.go +++ b/lib/ui/grid.go @@ -5,6 +5,7 @@ import (  	"math"  ) +// A container which arranges its children on a grid.  type Grid struct {  	rows         []GridSpec  	rowLayout    []gridLayout diff --git a/lib/ui/list.go b/lib/ui/list.go new file mode 100644 index 0000000..58f304f --- /dev/null +++ b/lib/ui/list.go @@ -0,0 +1,110 @@ +package ui + +import ( +	"fmt" +) + +// A container which arranges its children in a list. +type List struct { +	Items        []*ListItem +	itemHeight   int +	onInvalidate func(d Drawable) +	selected     int +} + +type ListItem struct { +	Content Drawable +	invalid bool +} + +type SelectableDrawable interface { +	Drawable +	DrawWithSelected(ctx *Context, selected bool) +} + +func NewList() *List { +	return &List{itemHeight: 1, selected: -1} +} + +func (list *List) OnInvalidate(onInvalidate func(d Drawable)) { +	list.onInvalidate = onInvalidate +} + +func (list *List) Invalidate() { +	for _, item := range list.Items { +		item.Content.Invalidate() +	} +	if list.onInvalidate != nil { +		list.onInvalidate(list) +	} +} + +func (list *List) Draw(ctx *Context) { +	for i, item := range list.Items { +		if !item.invalid { +			continue +		} +		subctx := ctx.Subcontext(0, i, ctx.Width(), list.itemHeight) +		if content, ok := item.Content.(SelectableDrawable); ok { +			content.DrawWithSelected(subctx, i == list.selected) +		} else { +			item.Content.Draw(subctx) +		} +	} +} + +func (list *List) Add(child Drawable) { +	list.Items = append(list.Items, &ListItem{Content: child, invalid: true}) +	child.OnInvalidate(list.childInvalidated) +	list.Invalidate() +} + +func (list *List) Remove(child Drawable) { +	for i, item := range list.Items { +		if item.Content == child { +			list.Items = append(list.Items[:i], list.Items[i+1:]...) +			child.OnInvalidate(nil) +			list.Invalidate() +			return +		} +	} +	panic(fmt.Errorf("Attempted to remove unknown child")) +} + +func (list *List) Set(items []Drawable) { +	for _, item := range list.Items { +		item.Content.OnInvalidate(nil) +	} +	list.Items = make([]*ListItem, len(items)) +	for i, item := range items { +		list.Items[i] = &ListItem{Content: item, invalid: true} +		item.OnInvalidate(list.childInvalidated) +	} +	list.Invalidate() +} + +func (list *List) Select(index int) { +	if index >= len(list.Items) || index < 0 { +		panic(fmt.Errorf("Attempted to select unknown child")) +	} +	list.selected = index +	list.Invalidate() +} + +func (list *List) ItemHeight(height int) { +	list.itemHeight = height +	list.Invalidate() +} + +func (list *List) childInvalidated(child Drawable) { +	for _, item := range list.Items { +		if item.Content == child { +			item.invalid = true +			if list.onInvalidate != nil { +				list.onInvalidate(list) +			} +			return +		} +	} +	panic(fmt.Errorf("Attempted to invalidate unknown child")) +} diff --git a/widgets/directories.go b/widgets/directories.go index 16b0e5a..ff2f6f5 100644 --- a/widgets/directories.go +++ b/widgets/directories.go @@ -3,6 +3,7 @@ package widgets  import (  	"log"  	"sort" +	"strings"  	"github.com/gdamore/tcell" @@ -13,7 +14,7 @@ import (  type DirectoryList struct {  	conf         *config.AccountConfig -	dirs         []string +	dirs         *ui.List  	logger       *log.Logger  	onInvalidate func(d ui.Drawable)  	worker       *types.Worker @@ -22,50 +23,68 @@ type DirectoryList struct {  func NewDirectoryList(conf *config.AccountConfig,  	logger *log.Logger, worker *types.Worker) *DirectoryList { -	return &DirectoryList{conf: conf, logger: logger, worker: worker} +	return &DirectoryList{ +		conf:   conf, +		dirs:   ui.NewList(), +		logger: logger, +		worker: worker, +	}  }  func (dirlist *DirectoryList) UpdateList() { -	var dirs []string +	var dirs []ui.Drawable  	dirlist.worker.PostAction(  		&types.ListDirectories{}, func(msg types.WorkerMessage) {  			switch msg := msg.(type) {  			case *types.Directory: -				dirs = append(dirs, msg.Name) +				if len(dirlist.conf.Folders) > 1 { +					idx := sort.SearchStrings(dirlist.conf.Folders, msg.Name) +					if idx == len(dirlist.conf.Folders) || +						dirlist.conf.Folders[idx] != msg.Name { +						break +					} +				} +				dirs = append(dirs, directoryEntry(msg.Name))  			case *types.Done: -				sort.Strings(dirs) -				dirlist.dirs = dirs -				dirlist.Invalidate() +				sort.Slice(dirs, func(_a, _b int) bool { +					a, _ := dirs[_a].(directoryEntry) +					b, _ := dirs[_b].(directoryEntry) +					return strings.Compare(string(a), string(b)) > 0 +				}) +				dirlist.dirs.Set(dirs)  			}  		})  }  func (dirlist *DirectoryList) OnInvalidate(onInvalidate func(d ui.Drawable)) { -	dirlist.onInvalidate = onInvalidate +	dirlist.dirs.OnInvalidate(func(_ ui.Drawable) { +		onInvalidate(dirlist) +	})  }  func (dirlist *DirectoryList) Invalidate() { -	if dirlist.onInvalidate != nil { -		dirlist.onInvalidate(dirlist) -	} +	dirlist.dirs.Invalidate()  }  func (dirlist *DirectoryList) Draw(ctx *ui.Context) { +	dirlist.dirs.Draw(ctx) +} + +type directoryEntry string + +func (d directoryEntry) OnInvalidate(_ func(_ ui.Drawable)) { +} + +func (d directoryEntry) Invalidate() { +} + +func (d directoryEntry) Draw(ctx *ui.Context) { +	d.DrawWithSelected(ctx, false) +} + +func (d directoryEntry) DrawWithSelected(ctx *ui.Context, selected bool) { +	// TODO: distinguish the selected item  	ctx.Fill(0, 0, ctx.Width(), ctx.Height(), ' ', tcell.StyleDefault) -	row := 0 -	for _, name := range dirlist.dirs { -		if row >= ctx.Height() { -			break -		} -		if len(dirlist.conf.Folders) > 1 { -			idx := sort.SearchStrings(dirlist.conf.Folders, name) -			if idx == len(dirlist.conf.Folders) || -				dirlist.conf.Folders[idx] != name { -				continue -			} -		} -		ctx.Printf(0, row, tcell.StyleDefault, "%s", name) -		row++ -	} +	ctx.Printf(0, 0, tcell.StyleDefault, "%s", d)  }  | 
