diff --git a/go.mod b/go.mod index e413132..6e1a3f9 100644 --- a/go.mod +++ b/go.mod @@ -2,7 +2,7 @@ module git.yetaga.in/alazyreader/why go 1.24.0 -require modernc.org/tk9.0 v0.62.0 +require modernc.org/tk9.0 v0.62.1-0.20250222163156-e78eb59c0674 require ( github.com/adrg/xdg v0.5.3 // indirect diff --git a/go.sum b/go.sum index bc146fc..aee0fc2 100644 --- a/go.sum +++ b/go.sum @@ -111,5 +111,7 @@ modernc.org/tcl9.0 v0.15.25 h1:3xNx26D+vYmSY3K9FaNdPmlHd8Hcz39YGiqsBFCYx5c= modernc.org/tcl9.0 v0.15.25/go.mod h1:hCbqZz0GQRzN3Xnfn4dKpMCwvA9sfEb+Go++cw1cJ3A= modernc.org/tk9.0 v0.62.0 h1:V4lyYhCRSXZKn+txvjZCyUnWodAFVJRYFDpFuLldGlk= modernc.org/tk9.0 v0.62.0/go.mod h1:vzTmvDro5F7yCnusSheZrF8VXXOzmY9RxH2c5M3YFqc= +modernc.org/tk9.0 v0.62.1-0.20250222163156-e78eb59c0674 h1:iIzjoNi8sZ4lw0zIjfNNX730AqytNGIRnE+bZgrWhTg= +modernc.org/tk9.0 v0.62.1-0.20250222163156-e78eb59c0674/go.mod h1:vzTmvDro5F7yCnusSheZrF8VXXOzmY9RxH2c5M3YFqc= modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= diff --git a/gopher.png b/gopher.png deleted file mode 100644 index 7213edb..0000000 Binary files a/gopher.png and /dev/null differ diff --git a/main.go b/main.go index 34a6024..4d62786 100644 --- a/main.go +++ b/main.go @@ -11,15 +11,17 @@ import ( "io" "log" "os" + "path/filepath" "slices" - "strings" "time" tk "modernc.org/tk9.0" ) -//go:embed gopher.png -var gopher []byte +// this is a default image +// +//go:embed noise.png +var noise []byte var validFileTypes = []tk.FileType{ { @@ -40,14 +42,32 @@ var validFileTypes = []tk.FileType{ }, } -var metaPressed bool +var metaActive bool -func isType(filename string, desired string) bool { - splode := strings.Split(filename, ".") - if len(splode) < 2 { +var directoryState struct { + currentDirectory string + currentFile string + images []string +} + +func isImage(entry os.DirEntry) bool { + if entry.IsDir() { + return false + } + ext := filepath.Ext(entry.Name()) + for _, ft := range validFileTypes { + if slices.Contains(ft.Extensions, ext) { + return true + } + } + return false +} + +func isType(filename string, desired string) bool { + ext := filepath.Ext(filename) + if ext == "" { return false } - ext := fmt.Sprintf(".%s", splode[len(splode)-1]) for _, ft := range validFileTypes { if slices.Contains(ft.Extensions, ext) && ft.TypeName == desired { return true @@ -79,59 +99,93 @@ func jpegToPng(in io.Reader) (*bytes.Buffer, error) { return buf, nil } -func loadImage(img *tk.LabelWidget) func() { +func newDirectory(img *tk.LabelWidget) func() { return func() { files := tk.GetOpenFile(tk.Filetypes(validFileTypes)) if len(files) > 0 { - f, err := os.Open(files[0]) + directoryState.currentFile = filepath.Base(files[0]) + directoryState.currentDirectory = filepath.Dir(files[0]) + dirfiles, err := os.ReadDir(directoryState.currentDirectory) if err != nil { - log.Println(err.Error()) - return + log.Println(err) } - var r io.Reader - if isType(files[0], "JPEG") { - r, err = jpegToPng(f) - if err != nil { - log.Println(err.Error()) - return + directoryState.images = []string{} + for _, v := range dirfiles { + if isImage(v) { + directoryState.images = append(directoryState.images, v.Name()) } - } else { - r = f } - i, err := io.ReadAll(r) - if err != nil { - log.Println(err.Error()) - return - } - img.Configure(tk.Image(tk.NewPhoto(tk.Data(i)))) + updateImage(files[0], img) } } } +func updateImage(file string, img *tk.LabelWidget) { + f, err := os.Open(file) + if err != nil { + log.Println(err.Error()) + return + } + var r io.Reader + if isType(file, "JPEG") { + r, err = jpegToPng(f) + if err != nil { + log.Println(err.Error()) + return + } + } else { + r = f + } + i, err := io.ReadAll(r) + if err != nil { + log.Println(err.Error()) + return + } + img.Configure(tk.Image(tk.NewPhoto(tk.Data(i)))) + directoryState.currentFile = filepath.Base(file) +} + func main() { - img := tk.Label(tk.Image(tk.NewPhoto(tk.Data(gopher)))) + img := tk.Label(tk.Image(tk.NewPhoto(tk.Data(noise)))) menubar := tk.Menu() fileMenu := menubar.Menu() - fileMenu.AddCommand(tk.Lbl("Open"), tk.Underline(0), tk.Accelerator("Meta+O"), tk.Command(loadImage(img))) + fileMenu.AddCommand(tk.Lbl("Open"), tk.Underline(0), tk.Accelerator("Meta+O"), tk.Command(newDirectory(img))) menubar.AddCascade(tk.Lbl("File"), tk.Underline(0), tk.Mnu(fileMenu)) + // TODO: if someone presses the Meta key again after the openfile dialog box closes, + // it triggers a _release_ event instead of a press event. The second time afterward, it works correctly. tk.Bind(tk.App, "", tk.Command(func(e *tk.Event) { - if e.Keysym == "Meta_L" || e.Keysym == "Meta_R" { - metaPressed = true - } - if e.Keysym == "o" && metaPressed { - loadImage(img)() + curr := slices.Index(directoryState.images, directoryState.currentFile) + switch e.Keysym { + case ".": + log.Printf("state: %+v", directoryState) + case "Meta_L", "Meta_R": + metaActive = true + case "o": + if metaActive { + newDirectory(img)() + } + case "Up": + if curr > 0 { + updateImage(filepath.Join(directoryState.currentDirectory, directoryState.images[curr-1]), img) + } + case "Down": + if curr < len(directoryState.images)-1 && curr != -1 { + updateImage(filepath.Join(directoryState.currentDirectory, directoryState.images[curr+1]), img) + } } })) tk.Bind(tk.App, "", tk.Command(func(e *tk.Event) { - if e.Keysym == "Meta_L" || e.Keysym == "Meta_R" { - metaPressed = false + switch e.Keysym { + case "Meta_L", "Meta_R": + metaActive = false } })) - tk.Bind(tk.App, "", tk.Command(func(e *tk.Event) { - // TODO: this event doesn't contain deltas, which means I can't tell if I'm scrolling "in" or "out" - })) + // todo: resize image based on scroll events + // tk.Bind(tk.App, "", tk.Command(func(e *tk.Event) { + // log.Printf("%v, %v", int16(e.Delta>>16), int16(e.Delta&0xFFFF)) + // })) tk.Pack(img) tk.App.Configure(tk.Mnu(menubar)).Center().Wait() diff --git a/noise.png b/noise.png new file mode 100644 index 0000000..e9f9ad5 Binary files /dev/null and b/noise.png differ