diff options
author | Koni Marti <koni.marti@gmail.com> | 2023-10-02 16:29:14 +0200 |
---|---|---|
committer | Robin Jarry <robin@jarry.cc> | 2023-10-13 00:31:54 +0200 |
commit | 3b1bc60f4e8f11c3244097c714db15bbf34d806e (patch) | |
tree | 76dc5defcd1d1060fb620255104114b0f575e6ee /app | |
parent | a2af6a89abb13cbf255988f28676c849814be45e (diff) | |
download | aerc-3b1bc60f4e8f11c3244097c714db15bbf34d806e.tar.gz |
msgviewer: separate part switcher from viewer
Separate part switcher from message viewer. The part switcher
implementation was woven into the message viewer code. Decouple them to
make the code more readable.
Signed-off-by: Koni Marti <koni.marti@gmail.com>
Tested-by: Inwit <inwit@sindominio.net>
Acked-by: Robin Jarry <robin@jarry.cc>
Diffstat (limited to 'app')
-rw-r--r-- | app/msgviewer.go | 170 | ||||
-rw-r--r-- | app/partswitcher.go | 178 |
2 files changed, 186 insertions, 162 deletions
diff --git a/app/msgviewer.go b/app/msgviewer.go index 5da37552..2189779a 100644 --- a/app/msgviewer.go +++ b/app/msgviewer.go @@ -37,15 +37,6 @@ type MessageViewer struct { uiConfig *config.UIConfig } -type PartSwitcher struct { - parts []*PartViewer - selected int - alwaysShowMime bool - - height int - mv *MessageViewer -} - func NewMessageViewer( acct *AccountView, msg lib.MessageView, ) *MessageViewer { @@ -326,9 +317,7 @@ func (mv *MessageViewer) ToggleKeyPassthrough() bool { } func (mv *MessageViewer) SelectedMessagePart() *PartInfo { - switcher := mv.switcher - part := switcher.parts[switcher.selected] - + part := mv.switcher.SelectedPart() return &PartInfo{ Index: part.index, Msg: part.msg.MessageInfo(), @@ -338,47 +327,22 @@ func (mv *MessageViewer) SelectedMessagePart() *PartInfo { } func (mv *MessageViewer) AttachmentParts(all bool) []*PartInfo { - var attachments []*PartInfo - - for _, p := range mv.switcher.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 + return mv.switcher.AttachmentParts(all) } func (mv *MessageViewer) PreviousPart() { - switcher := mv.switcher - for { - switcher.selected-- - if switcher.selected < 0 { - switcher.selected = len(switcher.parts) - 1 - } - if switcher.parts[switcher.selected].part.MIMEType != "multipart" { - break - } + if mv.switcher == nil { + return } + mv.switcher.PreviousPart() mv.Invalidate() } func (mv *MessageViewer) NextPart() { - switcher := mv.switcher - for { - switcher.selected++ - if switcher.selected >= len(switcher.parts) { - switcher.selected = 0 - } - if switcher.parts[switcher.selected].part.MIMEType != "multipart" { - break - } + if mv.switcher == nil { + return } + mv.switcher.NextPart() mv.Invalidate() } @@ -396,124 +360,6 @@ func (mv *MessageViewer) Close() { } } -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 tcell.Event) bool { - return ps.parts[ps.selected].Event(event) -} - -func (ps *PartSwitcher) Draw(ctx *ui.Context) { - height := len(ps.parts) - if height == 1 && !config.Viewer.AlwaysShowMime { - ps.parts[ps.selected].Draw(ctx) - return - } - - var styleSwitcher, styleFile, styleMime tcell.Style - - // 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 { - if ps.selected == i { - styleSwitcher = ps.mv.uiConfig.GetStyleSelected(config.STYLE_PART_SWITCHER) - styleFile = ps.mv.uiConfig.GetStyleSelected(config.STYLE_PART_FILENAME) - styleMime = ps.mv.uiConfig.GetStyleSelected(config.STYLE_PART_MIMETYPE) - } else { - styleSwitcher = ps.mv.uiConfig.GetStyle(config.STYLE_PART_SWITCHER) - styleFile = ps.mv.uiConfig.GetStyle(config.STYLE_PART_FILENAME) - styleMime = ps.mv.uiConfig.GetStyle(config.STYLE_PART_MIMETYPE) - } - ctx.Fill(0, y+i, 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, y+i, styleFile, "%s ", name) - } - t := "(" + part.part.FullMIMEType() + ")" - t = runewidth.Truncate(t, ctx.Width()-left, "…") - ctx.Printf(left, y+i, styleMime, "%s", t) - } - ps.parts[ps.selected].Draw(ctx.Subcontext( - 0, 0, ctx.Width(), ctx.Height()-height)) -} - -func (ps *PartSwitcher) MouseEvent(localX int, localY int, event tcell.Event) { - if event, ok := event.(*tcell.EventMouse); ok { - switch event.Buttons() { - case tcell.Button1: - height := len(ps.parts) - y := ps.height - height - if localY < y && ps.parts[ps.selected].term != nil { - 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 != nil { - 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 != nil { - 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 (ps *PartSwitcher) Cleanup() { - for _, partViewer := range ps.parts { - partViewer.Cleanup() - } -} - func (mv *MessageViewer) Event(event tcell.Event) bool { return mv.switcher.Event(event) } diff --git a/app/partswitcher.go b/app/partswitcher.go new file mode 100644 index 00000000..fa2f56b2 --- /dev/null +++ b/app/partswitcher.go @@ -0,0 +1,178 @@ +package app + +import ( + "git.sr.ht/~rjarry/aerc/config" + "git.sr.ht/~rjarry/aerc/lib/ui" + "github.com/gdamore/tcell/v2" + "github.com/mattn/go-runewidth" +) + +type PartSwitcher struct { + parts []*PartViewer + selected int + alwaysShowMime bool + + height int + mv *MessageViewer +} + +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 tcell.Event) bool { + return ps.parts[ps.selected].Event(event) +} + +func (ps *PartSwitcher) Draw(ctx *ui.Context) { + height := len(ps.parts) + if height == 1 && !config.Viewer.AlwaysShowMime { + ps.parts[ps.selected].Draw(ctx) + return + } + + var styleSwitcher, styleFile, styleMime tcell.Style + + // 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 { + if ps.selected == i { + styleSwitcher = ps.mv.uiConfig.GetStyleSelected(config.STYLE_PART_SWITCHER) + styleFile = ps.mv.uiConfig.GetStyleSelected(config.STYLE_PART_FILENAME) + styleMime = ps.mv.uiConfig.GetStyleSelected(config.STYLE_PART_MIMETYPE) + } else { + styleSwitcher = ps.mv.uiConfig.GetStyle(config.STYLE_PART_SWITCHER) + styleFile = ps.mv.uiConfig.GetStyle(config.STYLE_PART_FILENAME) + styleMime = ps.mv.uiConfig.GetStyle(config.STYLE_PART_MIMETYPE) + } + ctx.Fill(0, y+i, 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, y+i, styleFile, "%s ", name) + } + t := "(" + part.part.FullMIMEType() + ")" + t = runewidth.Truncate(t, ctx.Width()-left, "…") + ctx.Printf(left, y+i, styleMime, "%s", t) + } + ps.parts[ps.selected].Draw(ctx.Subcontext( + 0, 0, ctx.Width(), ctx.Height()-height)) +} + +func (ps *PartSwitcher) MouseEvent(localX int, localY int, event tcell.Event) { + if event, ok := event.(*tcell.EventMouse); ok { + switch event.Buttons() { + case tcell.Button1: + height := len(ps.parts) + y := ps.height - height + if localY < y && ps.parts[ps.selected].term != nil { + 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 != nil { + 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 != nil { + 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 (ps *PartSwitcher) Cleanup() { + for _, partViewer := range ps.parts { + partViewer.Cleanup() + } +} |