Files
2026-06-27 15:59:49 +02:00

193 lines
4.4 KiB
Go

package main
import (
"os"
"path/filepath"
"strings"
"github.com/gen2brain/cbconvert"
"github.com/gen2brain/cbconvert/cmd/cbconvert-gui/i18n"
"github.com/gen2brain/iup-go/iup"
)
func fileDlg(title string, multiple, directory bool, dirKey string) ([]string, error) {
ret := make([]string, 0)
dlg := iup.FileDlg()
defer dlg.Destroy()
if !directory {
mf := "YES"
if !multiple {
mf = "NO"
}
dlg.SetAttributes(map[string]string{
"DIALOGTYPE": "OPEN",
"MULTIPLEFILES": mf,
"MULTIVALUEPATH": "YES",
"EXTFILTER": "Comic Files|*.rar;*.zip;*.7z;*.tar;*.cbr;*.cbz;*.cb7;*.cbt;*.pdf;*.epub;*.mobi;*.docx;*.pptx|",
"FILTER": "*.cb*", // for Motif
"TITLE": title,
"SHOWPREVIEW": "YES",
"PREVIEWWIDTH": "240",
"PREVIEWHEIGHT": "320",
})
dlg.SetCallback("FILE_CB", iup.FileFunc(previewCover()))
} else {
dlg.SetAttributes(map[string]string{
"DIALOGTYPE": "DIR",
"TITLE": title,
})
}
setStartDir(dlg, dirKey)
iup.Popup(dlg, iup.CENTERPARENT, iup.CENTERPARENT)
if dlg.GetInt("STATUS") == 0 {
switch {
case multiple:
// MULTIVALUEPATH makes each MULTIVALUE a full path (id 0 is the path), so a folder-spanning selection works.
count := dlg.GetInt("MULTIVALUECOUNT")
if count > 1 {
for i := 1; i < count; i++ {
ret = append(ret, iup.GetAttributeId(dlg, "MULTIVALUE", i))
}
} else if value := dlg.GetAttribute("VALUE"); value != "" {
ret = append(ret, value)
}
default:
ret = append(ret, dlg.GetAttribute("VALUE"))
}
rememberDir(dlg, dirKey)
}
return ret, nil
}
const dlgPreviewName = "_FILEDLGPREVIEW_"
// previewPad insets the cover from the preview pane edges, in pixels per side.
const previewPad = 8
// previewCover returns a FILE_CB handler that draws the highlighted comic's cover in the dialog preview pane.
// Extracted covers are cached by path so re-highlighting a file doesn't re-extract it.
func previewCover() iup.FileFunc {
const maxCache = 32
cache := make(map[string]iup.Ihandle)
order := make([]string, 0, maxCache)
cover := func(path string, w, h int) iup.Ihandle {
if img, ok := cache[path]; ok {
return img
}
img := loadCover(path, w, h)
cache[path] = img
order = append(order, path)
if len(order) > maxCache {
old := order[0]
order = order[1:]
if oi := cache[old]; oi != 0 {
oi.Destroy()
}
delete(cache, old)
}
return img
}
return func(ih iup.Ihandle, filename, status string) int {
switch status {
case "PAINT":
iup.DrawBegin(ih)
cw, ch := iup.DrawGetSize(ih)
iup.DrawParentBackground(ih)
if image := cover(filename, cw-2*previewPad, ch-2*previewPad); image != 0 {
iup.SetHandle(dlgPreviewName, image)
iw, iih, _ := iup.DrawGetImageInfo(dlgPreviewName)
iup.DrawImage(ih, dlgPreviewName, (cw-iw)/2, (ch-iih)/2, iw, iih)
} else {
ih.SetAttribute("DRAWCOLOR", "128 128 128")
noPreview := i18n.Str(i18n.NoPreview)
tw, th := iup.DrawGetTextSize(ih, noPreview)
iup.DrawText(ih, noPreview, (cw-tw)/2, (ch-th)/2, 0, 0)
}
iup.DrawEnd(ih)
case "FINISH":
for _, img := range cache {
if img != 0 {
img.Destroy()
}
}
cache = make(map[string]iup.Ihandle)
order = order[:0]
}
return iup.DEFAULT
}
}
// loadCover extracts the cover of a comic file and returns it as an IUP image fitted to w by h, or 0.
func loadCover(path string, w, h int) iup.Ihandle {
if w <= 0 || h <= 0 || !isComic(path) {
return 0
}
fi, err := os.Stat(path)
if err != nil || fi.IsDir() {
return 0
}
opts := cbconvert.NewOptions()
opts.DPI = 96
img, err := cbconvert.New(opts).CoverPreview(path, fi, w, h)
if err != nil || img.Image == nil {
return 0
}
return iup.ImageFromImage(img.Image)
}
func isComic(path string) bool {
switch strings.ToLower(filepath.Ext(path)) {
case ".rar", ".zip", ".7z", ".tar", ".cbr", ".cbz", ".cb7", ".cbt",
".pdf", ".xps", ".epub", ".mobi", ".docx", ".pptx", ".xlsx":
return true
}
return false
}
func saveDlg(title, dirKey string) string {
dlg := iup.FileDlg()
defer dlg.Destroy()
dlg.SetAttributes(map[string]string{
"DIALOGTYPE": "SAVE",
"EXTFILTER": "Comic Files|*.cbz;*.cbt|",
"FILTER": "*.cb*", // for Motif
"TITLE": title,
})
setStartDir(dlg, dirKey)
iup.Popup(dlg, iup.CENTERPARENT, iup.CENTERPARENT)
if dlg.GetInt("STATUS") == -1 {
return ""
}
rememberDir(dlg, dirKey)
return dlg.GetAttribute("VALUE")
}