mirror of
https://git.sr.ht/~rjarry/aerc
synced 2025-02-22 14:53:57 +01:00

Replace all tcell.EventMouse events with vaxis mouse events Signed-off-by: Tim Culverhouse <tim@timculverhouse.com> Acked-by: Robin Jarry <robin@jarry.cc>
207 lines
4.7 KiB
Go
207 lines
4.7 KiB
Go
package app
|
|
|
|
import (
|
|
"math"
|
|
|
|
"git.sr.ht/~rjarry/aerc/config"
|
|
"git.sr.ht/~rjarry/aerc/lib/ui"
|
|
"git.sr.ht/~rockorager/vaxis"
|
|
"github.com/mattn/go-runewidth"
|
|
)
|
|
|
|
type PartSwitcher struct {
|
|
Scrollable
|
|
parts []*PartViewer
|
|
selected int
|
|
|
|
height int
|
|
offset int
|
|
|
|
uiConfig *config.UIConfig
|
|
}
|
|
|
|
func (ps *PartSwitcher) PreviousPart() {
|
|
for {
|
|
ps.selected--
|
|
if ps.selected < 0 {
|
|
ps.selected = len(ps.parts) - 1
|
|
}
|
|
if ps.parts[ps.selected].part.MIMEType != "multipart" {
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
func (ps *PartSwitcher) NextPart() {
|
|
for {
|
|
ps.selected++
|
|
if ps.selected >= len(ps.parts) {
|
|
ps.selected = 0
|
|
}
|
|
if ps.parts[ps.selected].part.MIMEType != "multipart" {
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
func (ps *PartSwitcher) SelectedPart() *PartViewer {
|
|
return ps.parts[ps.selected]
|
|
}
|
|
|
|
func (ps *PartSwitcher) AttachmentParts(all bool) []*PartInfo {
|
|
var attachments []*PartInfo
|
|
for _, p := range ps.parts {
|
|
if p.part.Disposition == "attachment" || (all && p.part.FileName() != "") {
|
|
pi := &PartInfo{
|
|
Index: p.index,
|
|
Msg: p.msg.MessageInfo(),
|
|
Part: p.part,
|
|
}
|
|
attachments = append(attachments, pi)
|
|
}
|
|
}
|
|
return attachments
|
|
}
|
|
|
|
func (ps *PartSwitcher) Invalidate() {
|
|
ui.Invalidate()
|
|
}
|
|
|
|
func (ps *PartSwitcher) Focus(focus bool) {
|
|
if ps.parts[ps.selected].term != nil {
|
|
ps.parts[ps.selected].term.Focus(focus)
|
|
}
|
|
}
|
|
|
|
func (ps *PartSwitcher) Show(visible bool) {
|
|
if ps.parts[ps.selected].term != nil {
|
|
ps.parts[ps.selected].term.Show(visible)
|
|
}
|
|
}
|
|
|
|
func (ps *PartSwitcher) Event(event vaxis.Event) bool {
|
|
return ps.parts[ps.selected].Event(event)
|
|
}
|
|
|
|
func (ps *PartSwitcher) Draw(ctx *ui.Context) {
|
|
uiConfig := ps.uiConfig
|
|
n := len(ps.parts)
|
|
if n == 1 && !config.Viewer.AlwaysShowMime {
|
|
ps.parts[ps.selected].Draw(ctx)
|
|
return
|
|
}
|
|
|
|
ps.height = config.Viewer.MaxMimeHeight
|
|
if ps.height <= 0 || n < ps.height {
|
|
ps.height = n
|
|
}
|
|
if ps.height > ctx.Height()/2 {
|
|
ps.height = ctx.Height() / 2
|
|
}
|
|
|
|
ps.UpdateScroller(ps.height, n)
|
|
ps.EnsureScroll(ps.selected)
|
|
|
|
var styleSwitcher, styleFile, styleMime vaxis.Style
|
|
|
|
scrollbarWidth := 0
|
|
if ps.NeedScrollbar() {
|
|
scrollbarWidth = 1
|
|
}
|
|
|
|
ps.offset = ctx.Height() - ps.height
|
|
y := ps.offset
|
|
row := ps.offset
|
|
ctx.Fill(0, y, ctx.Width(), ps.height, ' ', uiConfig.GetStyle(config.STYLE_PART_SWITCHER))
|
|
for i := ps.Scroll(); i < n; i++ {
|
|
part := ps.parts[i]
|
|
if ps.selected == i {
|
|
styleSwitcher = uiConfig.GetStyleSelected(config.STYLE_PART_SWITCHER)
|
|
styleFile = uiConfig.GetStyleSelected(config.STYLE_PART_FILENAME)
|
|
styleMime = uiConfig.GetStyleSelected(config.STYLE_PART_MIMETYPE)
|
|
} else {
|
|
styleSwitcher = uiConfig.GetStyle(config.STYLE_PART_SWITCHER)
|
|
styleFile = uiConfig.GetStyle(config.STYLE_PART_FILENAME)
|
|
styleMime = uiConfig.GetStyle(config.STYLE_PART_MIMETYPE)
|
|
}
|
|
ctx.Fill(0, row, ctx.Width(), 1, ' ', styleSwitcher)
|
|
left := len(part.index) * 2
|
|
if part.part.FileName() != "" {
|
|
name := runewidth.Truncate(part.part.FileName(),
|
|
ctx.Width()-left-1, "…")
|
|
left += ctx.Printf(left, row, styleFile, "%s ", name)
|
|
}
|
|
t := "(" + part.part.FullMIMEType() + ")"
|
|
t = runewidth.Truncate(t, ctx.Width()-left-scrollbarWidth, "…")
|
|
ctx.Printf(left, row, styleMime, "%s", t)
|
|
row++
|
|
|
|
if (i - ps.Scroll()) >= ps.height {
|
|
break
|
|
}
|
|
}
|
|
if ps.NeedScrollbar() {
|
|
ps.drawScrollbar(ctx.Subcontext(ctx.Width()-1, y, 1, ps.height))
|
|
}
|
|
ps.parts[ps.selected].Draw(ctx.Subcontext(
|
|
0, 0, ctx.Width(), ctx.Height()-ps.height))
|
|
}
|
|
|
|
func (ps *PartSwitcher) drawScrollbar(ctx *ui.Context) {
|
|
uiConfig := ps.uiConfig
|
|
gutterStyle := uiConfig.GetStyle(config.STYLE_MSGLIST_GUTTER)
|
|
pillStyle := uiConfig.GetStyle(config.STYLE_MSGLIST_PILL)
|
|
|
|
// gutter
|
|
ctx.Fill(0, 0, 1, ctx.Height(), ' ', gutterStyle)
|
|
|
|
// pill
|
|
pillSize := int(math.Ceil(float64(ctx.Height()) * ps.PercentVisible()))
|
|
pillOffset := int(math.Floor(float64(ctx.Height()) * ps.PercentScrolled()))
|
|
ctx.Fill(0, pillOffset, 1, pillSize, ' ', pillStyle)
|
|
}
|
|
|
|
func (ps *PartSwitcher) MouseEvent(localX int, localY int, event vaxis.Event) {
|
|
if localY < ps.offset && ps.parts[ps.selected].term != nil {
|
|
ps.parts[ps.selected].term.MouseEvent(localX, localY, event)
|
|
return
|
|
}
|
|
|
|
e, ok := event.(vaxis.Mouse)
|
|
if !ok {
|
|
return
|
|
}
|
|
|
|
if ps.parts[ps.selected].term != nil {
|
|
ps.parts[ps.selected].term.Focus(false)
|
|
}
|
|
|
|
switch e.Button {
|
|
case vaxis.MouseLeftButton:
|
|
i := localY - ps.offset + ps.Scroll()
|
|
if i < 0 || i >= len(ps.parts) {
|
|
break
|
|
}
|
|
if ps.parts[i].part.MIMEType == "multipart" {
|
|
break
|
|
}
|
|
ps.selected = i
|
|
ps.Invalidate()
|
|
case vaxis.MouseWheelDown:
|
|
ps.NextPart()
|
|
ps.Invalidate()
|
|
case vaxis.MouseWheelUp:
|
|
ps.PreviousPart()
|
|
ps.Invalidate()
|
|
}
|
|
|
|
if ps.parts[ps.selected].term != nil {
|
|
ps.parts[ps.selected].term.Focus(true)
|
|
}
|
|
}
|
|
|
|
func (ps *PartSwitcher) Cleanup() {
|
|
for _, partViewer := range ps.parts {
|
|
partViewer.Cleanup()
|
|
}
|
|
}
|