aerc

Working clone of aerc-mail.org
git clone git://git.danielmoch.com/aerc.git
Log | Files | Refs | README | LICENSE

tab.go (3640B)


      1 package ui
      2 
      3 import (
      4 	"github.com/gdamore/tcell"
      5 	"github.com/mattn/go-runewidth"
      6 )
      7 
      8 type Tabs struct {
      9 	Tabs       []*Tab
     10 	TabStrip   *TabStrip
     11 	TabContent *TabContent
     12 	Selected   int
     13 	history    []int
     14 
     15 	onInvalidateStrip   func(d Drawable)
     16 	onInvalidateContent func(d Drawable)
     17 }
     18 
     19 type Tab struct {
     20 	Content Drawable
     21 	Name    string
     22 	invalid bool
     23 }
     24 
     25 type TabStrip Tabs
     26 type TabContent Tabs
     27 
     28 func NewTabs() *Tabs {
     29 	tabs := &Tabs{}
     30 	tabs.TabStrip = (*TabStrip)(tabs)
     31 	tabs.TabContent = (*TabContent)(tabs)
     32 	tabs.history = []int{0}
     33 	return tabs
     34 }
     35 
     36 func (tabs *Tabs) Add(content Drawable, name string) *Tab {
     37 	tab := &Tab{
     38 		Content: content,
     39 		Name:    name,
     40 	}
     41 	tabs.Tabs = append(tabs.Tabs, tab)
     42 	tabs.TabStrip.Invalidate()
     43 	content.OnInvalidate(tabs.invalidateChild)
     44 	return tab
     45 }
     46 
     47 func (tabs *Tabs) invalidateChild(d Drawable) {
     48 	if tabs.Selected >= len(tabs.Tabs) {
     49 		return
     50 	}
     51 
     52 	if tabs.Tabs[tabs.Selected].Content == d {
     53 		if tabs.onInvalidateContent != nil {
     54 			tabs.onInvalidateContent(tabs.TabContent)
     55 		}
     56 	}
     57 }
     58 
     59 func (tabs *Tabs) Remove(content Drawable) {
     60 	for i, tab := range tabs.Tabs {
     61 		if tab.Content == content {
     62 			tabs.Tabs = append(tabs.Tabs[:i], tabs.Tabs[i+1:]...)
     63 			tabs.removeHistory(i)
     64 			break
     65 		}
     66 	}
     67 	tabs.Select(tabs.popHistory())
     68 	tabs.TabStrip.Invalidate()
     69 }
     70 
     71 func (tabs *Tabs) Select(index int) {
     72 	if index >= len(tabs.Tabs) {
     73 		panic("Tried to set tab index to a non-existing element")
     74 	}
     75 
     76 	if tabs.Selected != index {
     77 		tabs.Selected = index
     78 		tabs.pushHistory(index)
     79 		tabs.TabStrip.Invalidate()
     80 		tabs.TabContent.Invalidate()
     81 	}
     82 }
     83 
     84 func (tabs *Tabs) pushHistory(index int) {
     85 	tabs.history = append(tabs.history, index)
     86 }
     87 
     88 func (tabs *Tabs) popHistory() int {
     89 	lastIdx := len(tabs.history) - 1
     90 	item := tabs.history[lastIdx]
     91 	tabs.history = tabs.history[:lastIdx]
     92 	return item
     93 }
     94 
     95 func (tabs *Tabs) removeHistory(index int) {
     96 	newHist := make([]int, 0, len(tabs.history))
     97 	for i, item := range tabs.history {
     98 		if item == index {
     99 			continue
    100 		}
    101 		if item > index {
    102 			item = item - 1
    103 		}
    104 		// dedup
    105 		if i > 0 && len(newHist) > 0 && item == newHist[len(newHist)-1] {
    106 			continue
    107 		}
    108 		newHist = append(newHist, item)
    109 	}
    110 	tabs.history = newHist
    111 }
    112 
    113 // TODO: Color repository
    114 func (strip *TabStrip) Draw(ctx *Context) {
    115 	x := 0
    116 	for i, tab := range strip.Tabs {
    117 		style := tcell.StyleDefault.Foreground(tcell.ColorOlive).Reverse(true)
    118 		if strip.Selected == i {
    119 			style = tcell.StyleDefault
    120 		}
    121 		trunc := runewidth.Truncate(tab.Name, 32, "…")
    122 		x += ctx.Printf(x, 0, style, " %s ", trunc)
    123 	}
    124 	style := tcell.StyleDefault.Foreground(tcell.ColorOlive).Reverse(true)
    125 	ctx.Fill(x, 0, ctx.Width()-x, 1, ' ', style)
    126 }
    127 
    128 func (strip *TabStrip) Invalidate() {
    129 	if strip.onInvalidateStrip != nil {
    130 		strip.onInvalidateStrip(strip)
    131 	}
    132 }
    133 
    134 func (strip *TabStrip) OnInvalidate(onInvalidate func(d Drawable)) {
    135 	strip.onInvalidateStrip = onInvalidate
    136 }
    137 
    138 func (content *TabContent) Children() []Drawable {
    139 	children := make([]Drawable, len(content.Tabs))
    140 	for i, tab := range content.Tabs {
    141 		children[i] = tab.Content
    142 	}
    143 	return children
    144 }
    145 
    146 func (content *TabContent) Draw(ctx *Context) {
    147 	if content.Selected >= len(content.Tabs) {
    148 		width := ctx.Width()
    149 		height := ctx.Height()
    150 		ctx.Fill(0, 0, width, height, ' ', tcell.StyleDefault)
    151 	}
    152 
    153 	tab := content.Tabs[content.Selected]
    154 	tab.Content.Draw(ctx)
    155 }
    156 
    157 func (content *TabContent) Invalidate() {
    158 	if content.onInvalidateContent != nil {
    159 		content.onInvalidateContent(content)
    160 	}
    161 	tab := content.Tabs[content.Selected]
    162 	tab.Content.Invalidate()
    163 }
    164 
    165 func (content *TabContent) OnInvalidate(onInvalidate func(d Drawable)) {
    166 	content.onInvalidateContent = onInvalidate
    167 }