aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/ui/borders.go7
-rw-r--r--lib/ui/grid.go41
-rw-r--r--lib/ui/interfaces.go15
-rw-r--r--lib/ui/stack.go9
-rw-r--r--lib/ui/tab.go102
-rw-r--r--lib/ui/textinput.go14
-rw-r--r--widgets/account-wizard.go2
-rw-r--r--widgets/account.go11
-rw-r--r--widgets/aerc.go41
-rw-r--r--widgets/compose.go21
-rw-r--r--widgets/dirlist.go29
-rw-r--r--widgets/msglist.go45
-rw-r--r--widgets/msgviewer.go72
-rw-r--r--widgets/terminal.go14
14 files changed, 376 insertions, 47 deletions
diff --git a/lib/ui/borders.go b/lib/ui/borders.go
index cffd3ca3..7a757595 100644
--- a/lib/ui/borders.go
+++ b/lib/ui/borders.go
@@ -66,3 +66,10 @@ func (bordered *Bordered) Draw(ctx *Context) {
subctx := ctx.Subcontext(x, y, width, height)
bordered.content.Draw(subctx)
}
+
+func (bordered *Bordered) MouseEvent(localX int, localY int, event tcell.Event) {
+ switch content := bordered.content.(type) {
+ case Mouseable:
+ content.MouseEvent(localX, localY, event)
+ }
+}
diff --git a/lib/ui/grid.go b/lib/ui/grid.go
index 7f131bdf..b47c6bd6 100644
--- a/lib/ui/grid.go
+++ b/lib/ui/grid.go
@@ -5,6 +5,8 @@ import (
"math"
"sync"
"sync/atomic"
+
+ "github.com/gdamore/tcell"
)
type Grid struct {
@@ -141,6 +143,45 @@ func (grid *Grid) Draw(ctx *Context) {
}
}
+func (grid *Grid) MouseEvent(localX int, localY int, event tcell.Event) {
+ switch event := event.(type) {
+ case *tcell.EventMouse:
+ invalid := grid.invalid
+
+ grid.mutex.RLock()
+ defer grid.mutex.RUnlock()
+
+ for _, cell := range grid.cells {
+ cellInvalid := cell.invalid.Load().(bool)
+ if !cellInvalid && !invalid {
+ continue
+ }
+ rows := grid.rowLayout[cell.Row : cell.Row+cell.RowSpan]
+ cols := grid.columnLayout[cell.Column : cell.Column+cell.ColSpan]
+ x := cols[0].Offset
+ y := rows[0].Offset
+ width := 0
+ height := 0
+ for _, col := range cols {
+ width += col.Size
+ }
+ for _, row := range rows {
+ height += row.Size
+ }
+ if x <= localX && localX < x+width && y <= localY && localY < y+height {
+ switch content := cell.Content.(type) {
+ case MouseableDrawableInteractive:
+ content.MouseEvent(localX-x, localY-y, event)
+ case Mouseable:
+ content.MouseEvent(localX-x, localY-y, event)
+ case MouseHandler:
+ content.MouseEvent(localX-x, localY-y, event)
+ }
+ }
+ }
+ }
+}
+
func (grid *Grid) reflow(ctx *Context) {
grid.rowLayout = nil
grid.columnLayout = nil
diff --git a/lib/ui/interfaces.go b/lib/ui/interfaces.go
index 2f634248..9e795712 100644
--- a/lib/ui/interfaces.go
+++ b/lib/ui/interfaces.go
@@ -50,9 +50,18 @@ type Container interface {
Children() []Drawable
}
-// A drawable that can be clicked
-type Clickable interface {
+type MouseHandler interface {
+ // Handle a mouse event which occurred at the local x and y positions
+ MouseEvent(localX int, localY int, event tcell.Event)
+}
+
+// A drawable that can be interacted with by the mouse
+type Mouseable interface {
Drawable
+ MouseHandler
+}
- MouseEvent(event tcell.Event)
+type MouseableDrawableInteractive interface {
+ DrawableInteractive
+ MouseHandler
}
diff --git a/lib/ui/stack.go b/lib/ui/stack.go
index 75cc7807..690a8699 100644
--- a/lib/ui/stack.go
+++ b/lib/ui/stack.go
@@ -37,6 +37,15 @@ func (stack *Stack) Draw(ctx *Context) {
}
}
+func (stack *Stack) MouseEvent(localX int, localY int, event tcell.Event) {
+ if len(stack.children) > 0 {
+ switch element := stack.Peek().(type) {
+ case Mouseable:
+ element.MouseEvent(localX, localY, event)
+ }
+ }
+}
+
func (stack *Stack) Push(d Drawable) {
if len(stack.children) != 0 {
stack.Peek().OnInvalidate(nil)
diff --git a/lib/ui/tab.go b/lib/ui/tab.go
index 90c7ce90..1fd2b80b 100644
--- a/lib/ui/tab.go
+++ b/lib/ui/tab.go
@@ -14,6 +14,9 @@ type Tabs struct {
onInvalidateStrip func(d Drawable)
onInvalidateContent func(d Drawable)
+
+ parent *Tabs
+ CloseTab func(index int)
}
type Tab struct {
@@ -28,7 +31,9 @@ type TabContent Tabs
func NewTabs() *Tabs {
tabs := &Tabs{}
tabs.TabStrip = (*TabStrip)(tabs)
+ tabs.TabStrip.parent = tabs
tabs.TabContent = (*TabContent)(tabs)
+ tabs.TabContent.parent = tabs
tabs.history = []int{}
return tabs
}
@@ -114,6 +119,22 @@ func (tabs *Tabs) SelectPrevious() bool {
return true
}
+func (tabs *Tabs) NextTab() {
+ next := tabs.Selected + 1
+ if next >= len(tabs.Tabs) {
+ next = 0
+ }
+ tabs.Select(next)
+}
+
+func (tabs *Tabs) PrevTab() {
+ next := tabs.Selected - 1
+ if next < 0 {
+ next = len(tabs.Tabs) - 1
+ }
+ tabs.Select(next)
+}
+
func (tabs *Tabs) pushHistory(index int) {
tabs.history = append(tabs.history, index)
}
@@ -146,19 +167,6 @@ func (tabs *Tabs) removeHistory(index int) {
tabs.history = newHist
}
-func (tabs *Tabs) MouseEvent(event tcell.Event) {
- switch event := event.(type) {
- case *tcell.EventMouse:
- if event.Buttons()&tcell.Button1 != 0 {
- x, y := event.Position()
- selectedTab, ok := tabs.TabStrip.Clicked(x, y)
- if ok {
- tabs.Select(selectedTab)
- }
- }
- }
-}
-
// TODO: Color repository
func (strip *TabStrip) Draw(ctx *Context) {
x := 0
@@ -187,21 +195,65 @@ func (strip *TabStrip) Invalidate() {
}
}
+func (strip *TabStrip) MouseEvent(localX int, localY int, event tcell.Event) {
+ changeFocus := func(focus bool) {
+ interactive, ok := strip.parent.Tabs[strip.parent.Selected].Content.(Interactive)
+ if ok {
+ interactive.Focus(focus)
+ }
+ }
+ unfocus := func() { changeFocus(false) }
+ refocus := func() { changeFocus(true) }
+ switch event := event.(type) {
+ case *tcell.EventMouse:
+ switch event.Buttons() {
+ case tcell.Button1:
+ selectedTab, ok := strip.Clicked(localX, localY)
+ if !ok || selectedTab == strip.parent.Selected {
+ return
+ }
+ unfocus()
+ strip.parent.Select(selectedTab)
+ refocus()
+ case tcell.WheelDown:
+ unfocus()
+ strip.parent.NextTab()
+ refocus()
+ case tcell.WheelUp:
+ unfocus()
+ strip.parent.PrevTab()
+ refocus()
+ case tcell.Button3:
+ selectedTab, ok := strip.Clicked(localX, localY)
+ if !ok {
+ return
+ }
+ unfocus()
+ if selectedTab == strip.parent.Selected {
+ strip.parent.CloseTab(selectedTab)
+ } else {
+ current := strip.parent.Selected
+ strip.parent.CloseTab(selectedTab)
+ strip.parent.Select(current)
+ }
+ refocus()
+ }
+ }
+}
+
func (strip *TabStrip) OnInvalidate(onInvalidate func(d Drawable)) {
strip.onInvalidateStrip = onInvalidate
}
func (strip *TabStrip) Clicked(mouseX int, mouseY int) (int, bool) {
x := 0
- if mouseY == 0 {
- for i, tab := range strip.Tabs {
- trunc := runewidth.Truncate(tab.Name, 32, "…")
- length := len(trunc) + 2
- if x <= mouseX && mouseX < x+length {
- return i, true
- }
- x += length
+ for i, tab := range strip.Tabs {
+ trunc := runewidth.Truncate(tab.Name, 32, "…")
+ length := len(trunc) + 2
+ if x <= mouseX && mouseX < x+length {
+ return i, true
}
+ x += length
}
return 0, false
}
@@ -225,6 +277,14 @@ func (content *TabContent) Draw(ctx *Context) {
tab.Content.Draw(ctx)
}
+func (content *TabContent) MouseEvent(localX int, localY int, event tcell.Event) {
+ tab := content.Tabs[content.Selected]
+ switch tabContent := tab.Content.(type) {
+ case Mouseable:
+ tabContent.MouseEvent(localX, localY, event)
+ }
+}
+
func (content *TabContent) Invalidate() {
if content.onInvalidateContent != nil {
content.onInvalidateContent(content)
diff --git a/lib/ui/textinput.go b/lib/ui/textinput.go
index 00e91eee..39351735 100644
--- a/lib/ui/textinput.go
+++ b/lib/ui/textinput.go
@@ -97,6 +97,20 @@ func (ti *TextInput) Draw(ctx *Context) {
}
}
+func (ti *TextInput) MouseEvent(localX int, localY int, event tcell.Event) {
+ switch event := event.(type) {
+ case *tcell.EventMouse:
+ switch event.Buttons() {
+ case tcell.Button1:
+ if localX >= len(ti.prompt)+1 && localX <= len(ti.text[ti.scroll:])+len(ti.prompt)+1 {
+ ti.index = localX - len(ti.prompt) - 1
+ ti.ensureScroll()
+ ti.Invalidate()
+ }
+ }
+ }
+}
+
func (ti *TextInput) Focus(focus bool) {
ti.focus = focus
if focus && ti.ctx != nil {
diff --git a/widgets/account-wizard.go b/widgets/account-wizard.go
index 5acd26c5..904013f9 100644
--- a/widgets/account-wizard.go
+++ b/widgets/account-wizard.go
@@ -523,7 +523,7 @@ func (wizard *AccountWizard) finish(tutorial bool) {
}
wizard.conf.Accounts = append(wizard.conf.Accounts, account)
- view := NewAccountView(wizard.conf, &account,
+ view := NewAccountView(wizard.aerc, wizard.conf, &account,
wizard.aerc.logger, wizard.aerc)
wizard.aerc.accounts[account.Name] = view
wizard.aerc.NewTab(view, account.Name)
diff --git a/widgets/account.go b/widgets/account.go
index 688b6602..1220753a 100644
--- a/widgets/account.go
+++ b/widgets/account.go
@@ -17,6 +17,7 @@ import (
type AccountView struct {
acct *config.AccountConfig
+ aerc *Aerc
conf *config.AercConfig
dirlist *DirectoryList
grid *ui.Grid
@@ -26,7 +27,7 @@ type AccountView struct {
worker *types.Worker
}
-func NewAccountView(conf *config.AercConfig, acct *config.AccountConfig,
+func NewAccountView(aerc *Aerc, conf *config.AercConfig, acct *config.AccountConfig,
logger *log.Logger, host TabHost) *AccountView {
grid := ui.NewGrid().Rows([]ui.GridSpec{
@@ -42,6 +43,7 @@ func NewAccountView(conf *config.AercConfig, acct *config.AccountConfig,
Color(tcell.ColorDefault, tcell.ColorRed)
return &AccountView{
acct: acct,
+ aerc: aerc,
grid: grid,
host: host,
logger: logger,
@@ -53,11 +55,12 @@ func NewAccountView(conf *config.AercConfig, acct *config.AccountConfig,
grid.AddChild(ui.NewBordered(dirlist, ui.BORDER_RIGHT))
}
- msglist := NewMessageList(conf, logger)
+ msglist := NewMessageList(conf, logger, aerc)
grid.AddChild(msglist).At(0, 1)
view := &AccountView{
acct: acct,
+ aerc: aerc,
conf: conf,
dirlist: dirlist,
grid: grid,
@@ -124,6 +127,10 @@ func (acct *AccountView) Draw(ctx *ui.Context) {
acct.grid.Draw(ctx)
}
+func (acct *AccountView) MouseEvent(localX int, localY int, event tcell.Event) {
+ acct.grid.MouseEvent(localX, localY, event)
+}
+
func (acct *AccountView) Focus(focus bool) {
// TODO: Unfocus children I guess
}
diff --git a/widgets/aerc.go b/widgets/aerc.go
index 87009cd3..fe3c1e21 100644
--- a/widgets/aerc.go
+++ b/widgets/aerc.go
@@ -74,7 +74,7 @@ func NewAerc(conf *config.AercConfig, logger *log.Logger,
conf.Triggers.ExecuteCommand = cmd
for i, acct := range conf.Accounts {
- view := NewAccountView(conf, &conf.Accounts[i], logger, aerc)
+ view := NewAccountView(aerc, conf, &conf.Accounts[i], logger, aerc)
aerc.accounts[acct.Name] = view
tabs.Add(view, acct.Name)
}
@@ -85,6 +85,22 @@ func NewAerc(conf *config.AercConfig, logger *log.Logger,
aerc.NewTab(wizard, "New account")
}
+ tabs.CloseTab = func(index int) {
+ switch content := aerc.tabs.Tabs[index].Content.(type) {
+ case *AccountView:
+ return
+ case *AccountWizard:
+ return
+ case *Composer:
+ aerc.RemoveTab(content)
+ content.Close()
+ case *Terminal:
+ content.Close(nil)
+ case *MessageViewer:
+ aerc.RemoveTab(content)
+ }
+ }
+
return aerc
}
@@ -235,7 +251,12 @@ func (aerc *Aerc) Event(event tcell.Event) bool {
return false
}
case *tcell.EventMouse:
- aerc.tabs.MouseEvent(event)
+ if event.Buttons() == tcell.ButtonNone {
+ return false
+ }
+ x, y := event.Position()
+ aerc.grid.MouseEvent(x, y, event)
+ return true
}
return false
}
@@ -260,8 +281,8 @@ func (aerc *Aerc) SelectedTab() ui.Drawable {
return aerc.tabs.Tabs[aerc.tabs.Selected].Content
}
-func (aerc *Aerc) NewTab(drawable ui.Drawable, name string) *ui.Tab {
- tab := aerc.tabs.Add(drawable, name)
+func (aerc *Aerc) NewTab(clickable ui.Drawable, name string) *ui.Tab {
+ tab := aerc.tabs.Add(clickable, name)
aerc.tabs.Select(len(aerc.tabs.Tabs) - 1)
return tab
}
@@ -275,19 +296,11 @@ func (aerc *Aerc) ReplaceTab(tabSrc ui.Drawable, tabTarget ui.Drawable, name str
}
func (aerc *Aerc) NextTab() {
- next := aerc.tabs.Selected + 1
- if next >= len(aerc.tabs.Tabs) {
- next = 0
- }
- aerc.tabs.Select(next)
+ aerc.tabs.NextTab()
}
func (aerc *Aerc) PrevTab() {
- next := aerc.tabs.Selected - 1
- if next < 0 {
- next = len(aerc.tabs.Tabs) - 1
- }
- aerc.tabs.Select(next)
+ aerc.tabs.PrevTab()
}
func (aerc *Aerc) SelectTab(name string) bool {
diff --git a/widgets/compose.go b/widgets/compose.go
index bd4301ae..0e7f09e6 100644
--- a/widgets/compose.go
+++ b/widgets/compose.go
@@ -40,10 +40,12 @@ type Composer struct {
worker *types.Worker
layout HeaderLayout
- focusable []ui.DrawableInteractive
+ focusable []ui.MouseableDrawableInteractive
focused int
onClose []func(ti *Composer)
+
+ width int
}
func NewComposer(conf *config.AercConfig,
@@ -87,10 +89,10 @@ func NewComposer(conf *config.AercConfig,
func buildComposeHeader(layout HeaderLayout, defaults map[string]string) (
newLayout HeaderLayout,
editors map[string]*headerEditor,
- focusable []ui.DrawableInteractive,
+ focusable []ui.MouseableDrawableInteractive,
) {
editors = make(map[string]*headerEditor)
- focusable = make([]ui.DrawableInteractive, 0)
+ focusable = make([]ui.MouseableDrawableInteractive, 0)
for _, row := range layout {
for _, h := range row {
@@ -99,7 +101,7 @@ func buildComposeHeader(layout HeaderLayout, defaults map[string]string) (
switch h {
case "From":
// Prepend From to support backtab
- focusable = append([]ui.DrawableInteractive{e}, focusable...)
+ focusable = append([]ui.MouseableDrawableInteractive{e}, focusable...)
default:
focusable = append(focusable, e)
}
@@ -176,6 +178,7 @@ func (c *Composer) OnClose(fn func(composer *Composer)) {
}
func (c *Composer) Draw(ctx *ui.Context) {
+ c.width = ctx.Width()
c.grid.Draw(ctx)
}
@@ -617,6 +620,16 @@ func (he *headerEditor) Draw(ctx *ui.Context) {
he.input.Draw(ctx.Subcontext(size, 0, ctx.Width()-size, 1))
}
+func (he *headerEditor) MouseEvent(localX int, localY int, event tcell.Event) {
+ switch event := event.(type) {
+ case *tcell.EventMouse:
+ width := runewidth.StringWidth(he.name + " ")
+ if localX >= width {
+ he.input.MouseEvent(localX-width, localY, event)
+ }
+ }
+}
+
func (he *headerEditor) Invalidate() {
he.input.Invalidate()
}
diff --git a/widgets/dirlist.go b/widgets/dirlist.go
index 33119dd2..ec730825 100644
--- a/widgets/dirlist.go
+++ b/widgets/dirlist.go
@@ -137,6 +137,35 @@ func (dirlist *DirectoryList) Draw(ctx *ui.Context) {
}
}
+func (dirlist *DirectoryList) MouseEvent(localX int, localY int, event tcell.Event) {
+ switch event := event.(type) {
+ case *tcell.EventMouse:
+ switch event.Buttons() {
+ case tcell.Button1:
+ clickedDir, ok := dirlist.Clicked(localX, localY)
+ if ok {
+ dirlist.Select(clickedDir)
+ }
+ case tcell.WheelDown:
+ dirlist.Next()
+ case tcell.WheelUp:
+ dirlist.Prev()
+ }
+ }
+}
+
+func (dirlist *DirectoryList) Clicked(x int, y int) (string, bool) {
+ if dirlist.dirs == nil || len(dirlist.dirs) == 0 {
+ return "", false
+ }
+ for i, name := range dirlist.dirs {
+ if i == y {
+ return name, true
+ }
+ }
+ return "", false
+}
+
func (dirlist *DirectoryList) NextPrev(delta int) {
curIdx := sort.SearchStrings(dirlist.dirs, dirlist.selected)
if curIdx == len(dirlist.dirs) {
diff --git a/widgets/msglist.go b/widgets/msglist.go
index 8ed716b0..b7c921c3 100644
--- a/widgets/msglist.go
+++ b/widgets/msglist.go
@@ -25,6 +25,7 @@ type MessageList struct {
spinner *Spinner
store *lib.MessageStore
isInitalizing bool
+ aerc *Aerc
}
type msgSorter struct {
@@ -55,12 +56,13 @@ func (s *msgSorter) Swap(i, j int) {
s.uids[j] = tmp
}
-func NewMessageList(conf *config.AercConfig, logger *log.Logger) *MessageList {
+func NewMessageList(conf *config.AercConfig, logger *log.Logger, aerc *Aerc) *MessageList {
ml := &MessageList{
conf: conf,
logger: logger,
spinner: NewSpinner(&conf.Ui),
isInitalizing: true,
+ aerc: aerc,
}
ml.spinner.OnInvalidate(func(_ ui.Drawable) {
ml.Invalidate()
@@ -161,6 +163,47 @@ func (ml *MessageList) Draw(ctx *ui.Context) {
}
}
+func (ml *MessageList) MouseEvent(localX int, localY int, event tcell.Event) {
+ switch event := event.(type) {
+ case *tcell.EventMouse:
+ switch event.Buttons() {
+ case tcell.Button1:
+ if ml.aerc == nil {
+ return
+ }
+ selectedMsg, ok := ml.Clicked(localX, localY)
+ if ok {
+ ml.Select(selectedMsg)
+ acct := ml.aerc.SelectedAccount()
+ if acct.Messages().Empty() {
+ return
+ }
+ store := acct.Messages().Store()
+ msg := acct.Messages().Selected()
+ if msg == nil {
+ return
+ }
+ viewer := NewMessageViewer(acct, ml.aerc.Config(), store, msg)
+ ml.aerc.NewTab(viewer, msg.Envelope.Subject)
+ }
+ case tcell.WheelDown:
+ ml.store.Next()
+ ml.Scroll()
+ case tcell.WheelUp:
+ ml.store.Prev()
+ ml.Scroll()
+ }
+ }
+}
+
+func (ml *MessageList) Clicked(x, y int) (int, bool) {
+ store := ml.Store()
+ if store == nil || ml.nmsgs == 0 || y >= ml.nmsgs {
+ return 0, false
+ }
+ return y + ml.scroll, true
+}
+
func (ml *MessageList) Height() int {
return ml.height
}
diff --git a/widgets/msgviewer.go b/widgets/msgviewer.go
index e210616a..c1790707 100644
--- a/widgets/msgviewer.go
+++ b/widgets/msgviewer.go
@@ -42,6 +42,9 @@ type PartSwitcher struct {
selected int
showHeaders bool
alwaysShowMime bool
+
+ height int
+ mv *MessageViewer
}
func NewMessageViewer(acct *AccountView, conf *config.AercConfig,
@@ -77,7 +80,7 @@ func NewMessageViewer(acct *AccountView, conf *config.AercConfig,
grid.AddChild(header).At(0, 0)
grid.AddChild(switcher).At(1, 0)
- return &MessageViewer{
+ mv := &MessageViewer{
acct: acct,
conf: conf,
grid: grid,
@@ -85,6 +88,9 @@ func NewMessageViewer(acct *AccountView, conf *config.AercConfig,
store: store,
switcher: switcher,
}
+ switcher.mv = mv
+
+ return mv
}
func fmtHeader(msg *models.MessageInfo, header string) string {
@@ -194,6 +200,13 @@ func (mv *MessageViewer) Draw(ctx *ui.Context) {
mv.grid.Draw(ctx)
}
+func (mv *MessageViewer) MouseEvent(localX int, localY int, event tcell.Event) {
+ if mv.err != nil {
+ return
+ }
+ mv.grid.MouseEvent(localX, localY, event)
+}
+
func (mv *MessageViewer) Invalidate() {
mv.grid.Invalidate()
}
@@ -295,6 +308,7 @@ func (ps *PartSwitcher) Draw(ctx *ui.Context) {
return
}
// TODO: cap height and add scrolling for messages with many parts
+ ps.height = ctx.Height()
y := ctx.Height() - height
for i, part := range ps.parts {
style := tcell.StyleDefault.Reverse(ps.selected == i)
@@ -311,6 +325,62 @@ func (ps *PartSwitcher) Draw(ctx *ui.Context) {
0, 0, ctx.Width(), ctx.Height()-height))
}
+func (ps *PartSwitcher) MouseEvent(localX int, localY int, event tcell.Event) {
+ switch event := event.(type) {
+ case *tcell.EventMouse:
+ switch event.Buttons() {
+ case tcell.Button1:
+ height := len(ps.parts)
+ y := ps.height - height
+ if localY < y {
+ ps.parts[ps.selected].term.MouseEvent(localX, localY, event)
+ }
+ for i, _ := range ps.parts {
+ if localY != y+i {
+ continue
+ }
+ if ps.parts[i].part.MIMEType == "multipart" {
+ continue
+ }
+ if ps.parts[ps.selected].term != nil {
+ ps.parts[ps.selected].term.Focus(false)
+ }
+ ps.selected = i
+ ps.Invalidate()
+ if ps.parts[ps.selected].term != nil {
+ ps.parts[ps.selected].term.Focus(true)
+ }
+ }
+ case tcell.WheelDown:
+ height := len(ps.parts)
+ y := ps.height - height
+ if localY < y {
+ ps.parts[ps.selected].term.MouseEvent(localX, localY, event)
+ }
+ if ps.parts[ps.selected].term != nil {
+ ps.parts[ps.selected].term.Focus(false)
+ }
+ ps.mv.NextPart()
+ if ps.parts[ps.selected].term != nil {
+ ps.parts[ps.selected].term.Focus(true)
+ }
+ case tcell.WheelUp:
+ height := len(ps.parts)
+ y := ps.height - height
+ if localY < y {
+ ps.parts[ps.selected].term.MouseEvent(localX, localY, event)
+ }
+ if ps.parts[ps.selected].term != nil {
+ ps.parts[ps.selected].term.Focus(false)
+ }
+ ps.mv.PreviousPart()
+ if ps.parts[ps.selected].term != nil {
+ ps.parts[ps.selected].term.Focus(true)
+ }
+ }
+ }
+}
+
func (mv *MessageViewer) Event(event tcell.Event) bool {
return mv.switcher.Event(event)
}
diff --git a/widgets/terminal.go b/widgets/terminal.go
index 008a36f0..6ad6904b 100644
--- a/widgets/terminal.go
+++ b/widgets/terminal.go
@@ -311,6 +311,20 @@ func (term *Terminal) Draw(ctx *ui.Context) {
}
}
+func (term *Terminal) MouseEvent(localX int, localY int, event tcell.Event) {
+ switch event := event.(type) {
+ case *tcell.EventMouse:
+ if term.OnEvent != nil {
+ if term.OnEvent(event) {
+ return
+ }
+ }
+ if term.closed {
+ return
+ }
+ }
+}
+
func (term *Terminal) Focus(focus bool) {
if term.closed {
return