ref: 50c527fe9f81010d304f49ce51dfc39a16cdec6c
dir: /main.go/
package main import ( "9fans.net/go/draw" "bytes" "fmt" "image" imagedraw "image/draw" "flag" "github.com/mjl-/duit" "github.com/psilva261/szdd" xdraw "golang.org/x/image/draw" "log" "math" "os" _ "golang.org/x/image/bmp" _ "image/gif" _ "image/jpeg" _ "image/png" ) var ( dui *duit.DUI scale int history []*Item lastM draw.Mouse ) type Category int const ( About Category = iota Animal ) func (c Category) path() string { switch c { case About: return "about" case Animal: return "animal" } log.Fatalf("%v unknown", c) return "" } type Folder struct { Category Pre string Suf string Name string Items map[string]*Item } func getFolder(root, pre string) (ff *Folder) { for _, f := range folders { if f.Pre == pre { ff = f } } return } func (f Folder) Main() *Item { fnSuf := f.Suf if _, ok := f.Items[f.Suf]; !ok { fnSuf = "0001" } return f.getItem(fnSuf) } func (f *Folder) Decode(k string) (fName, itName string) { if _, ok := f.Items[k]; ok { return f.Pre, k } var ff *Folder fName = k for _, fff := range folders { if fff.Pre == k { ff = fff } } if ff == nil { return f.Pre, k } itName = ff.Suf if _, ok := ff.Items[itName]; !ok { itName = "0001" } return } func (f Folder) getItem(k string) *Item { for key, it := range f.Items { if key == k { if it.Image == nil { fn := fmt.Sprintf("./data/%v/%v%v/%v%v.dib", f.Category.path(), f.Pre, f.Suf, f.Pre, k) it.Image = &duit.Image{ Image: readImagePath(fn), } } return it } } return nil } type Item struct { *duit.Image f *Folder name string Targets map[string]Target } func (it *Item) Mouse(dui *duit.DUI, self *duit.Kid, m draw.Mouse, origM draw.Mouse, orig image.Point) (r duit.Result) { defer func() { lastM = m }() if m.Buttons&1 == 1 && lastM.Buttons&1 == 0 { //log.Printf("m= %v,%v", m.Point.X*2/scale, m.Point.Y*2/scale) for k, t := range it.Targets { if t.has(m.Point) { history = append(history, it) fName, itName := it.f.Decode(k) _=fName tf := getFolder(it.f.Pre, k) if tf == nil { tf = it.f } it := tf.getItem(itName) dui.Top.UI = it dui.MarkLayout(dui.Top.UI) dui.MarkDraw(dui.Top.UI) dui.Render() } } return duit.Result{ Consumed: true, } } else if m.Buttons&4 == 4 { var it *Item if l := len(history); l > 0 { it, history = history[l-1], history[:l-1] } else { tf := getFolder("", "cont") it = tf.Main() } dui.Top.UI = it dui.MarkLayout(dui.Top.UI) dui.MarkDraw(dui.Top.UI) dui.Render() } return it.Image.Mouse(dui, self, m, origM, orig) } type Target interface { has(draw.Point) bool } type Circle struct { x int y int r int } func C(x, y, r int) Circle { return Circle{x: x, y: y, r: r} } func (c Circle) has(p draw.Point) bool { x := p.X * 2 / scale y := p.Y * 2 / scale return math.Abs(float64(x)-float64(c.x)) < float64(c.r) && math.Abs(float64(y)-float64(c.y)) < float64(c.r) } type Rectangle struct { x int y int x2 int y2 int } func R(x, y, x2, y2 int) Rectangle { return Rectangle{x: x, y: y, x2: x2, y2: y2} } func (r Rectangle) has(p draw.Point) bool { x := p.X * 2 / scale y := p.Y * 2 / scale return r.x <= x && x <= r.x2 && r.y <= y && y <= r.y2 } var folders = []*Folder{ /* about */ &Folder{ Pre: "afri", Suf: "00aa", Name: "Africa", Items: map[string]*Item{ "00aa": &Item{ name: "Waterhole", }, "00fb": &Item{ name: "Art", }, }, }, &Folder{ Pre: "atls", Suf: "00nv", Name: "Atlas", Items: map[string]*Item{ "00nv": &Item{ name: "Continents", Targets: map[string]Target{ "01pu": C(659, 461, 100), "02pu": C(931, 275, 200), "03pu": C(1117, 603, 50), "04pu": C(600, 262, 50), "05pu": C(222, 270, 140), "06pu": C(350, 552, 120), }, }, "01p1": &Item{ name: "African reptiles", }, "01p2": &Item{ name: "African herbivores", }, "01pu": &Item{ name: "Africa", Targets: map[string]Target{ "leop": C(114,610,80), "babn": C(348,568,55), "cock": C(474,716,40), "01p2": C(200,292,100), "01p1": C(680,539,100), "lion": C(468,360,60), "rats": C(391,74,60), "mosq": C(218,147,40), "aant": C(575,124,50), "chee": C(814,256,70), "vult": C(849,72, 90), "hyen": C(906,666,60), "cdog": C(1104,642,80), "fsal": C(1074,428,100), "kbee": C(1130,252,60), "afri": C(1150,68,50), }, }, "02pu": &Item{ name: "Asia", }, "03pu": &Item{ name: "Australia", }, "04pu": &Item{ name: "Europe", Targets: map[string]Target{ "addr": C(852,367,60), "cent": C(714,699, 100), "cock": C(69,256, 100), "crab": C(1013,175, 65), "fsal": C(670,497,80), "gsqu": C(411,95,75), "mosq": C(728,59,50), "rats": C(288,325, 100), "scor": C(160,593, 90), "vult": C(418,610, 70), "wlvr": C(609,193, 70), "wolf": C(1101, 546, 100), }, }, "05pu": &Item{ name: "North America", }, "06pu": &Item{ name: "South America", }, }, }, &Folder{ Pre: "aust", Suf: "00aa", Name: "Australia", Items: map[string]*Item{ "00aa": &Item{ name: "Oddities", }, }, }, &Folder{ Pre: "beet", Suf: "00aa", Name: "Beetles", Items: map[string]*Item{ "00aa": &Item{ name: "Beetles", }, }, }, &Folder{ Pre: "frst", Suf: "00aa", Name: "Forest", Items: map[string]*Item{ "00aa": &Item{ name: "Forest Environments", }, }, }, &Folder{ Pre: "cont", Suf: "00nv", Name: "Contents", Items: map[string]*Item{ "00nv": &Item{ name: "Contents", Targets: map[string]Target{ "atls": C(242, 190, 150), "habt": C(256, 588, 200), "indx": C(920, 614, 200), "weap": C(997, 200, 200), "wwfd": C(604, 384, 200), }, }, }, }, &Folder{ Pre: "guid", Suf: "00nv", Name: "Guides", Items: map[string]*Item{ "00nv": &Item{ name: "Guides", }, }, }, &Folder{ Pre: "habt", Suf: "00nv", Name: "Habitats", Items: map[string]*Item{ "00nv": &Item{ name: "Habitats", }, }, }, &Folder{ Pre: "help", Suf: "00nv", Name: "Help", Items: map[string]*Item{ "00nv": &Item{ name: "Help", }, }, }, &Folder{ Pre: "indx", Suf: "00nv", Name: "Index", Items: map[string]*Item{ "0001": &Item{ name: "Index", Targets: map[string]Target{ "0001": R(25,66, 72,114), "0002": R(75,70, 119,115), "0003": R(122,68, 163,114), "0004": R(166,69, 295,115), "0005": R(297,66, 389,115), "0006": R(394,69, 502,117), "0007": R(504,66, 703,115), "0008": R(702,66, 791,116), "0009": R(794,67, 880,117), "0010": R(879,68, 1018,114), "0011": R(1013,66, 1210,116), }, }, "0002": &Item{}, "0003": &Item{}, "0004": &Item{}, "0005": &Item{}, "0006": &Item{}, "0007": &Item{}, "0008": &Item{}, "0009": &Item{}, "0010": &Item{}, "0011": &Item{}, }, }, /*Folder{ Pre: "titl", Suf: "00nv", Name: "Title", Items: map[string]*Item{ "00nv": "Title", }, },*/ &Folder{ Pre: "weap", Suf: "00nv", Name: "Index", Items: map[string]*Item{ "00nv": &Item{ name: "Index", Targets: map[string]Target{ "01pu": C(250, 400, 150), "03pu": C(654, 375, 150), "02pu": C(1047, 400, 150), }, }, "01pu": &Item{}, "03pu": &Item{}, "02pu": &Item{}, }, }, &Folder{ Pre: "wwfd", Suf: "00aa", Name: "WWF", Items: map[string]*Item{ "00aa": &Item{ name: "WWF", Targets: map[string]Target{ "03pu": C(302, 176, 80), "04pu": C(518, 255, 80), "02pu": C(685, 415, 80), "06pu": C(952, 147, 80), "05pu": C(917, 324, 80), "01pu": C(1102, 313, 80), "07tv": C(202, 465, 80), "00fb": C(89, 55, 80), "01fb": C(1208, 69, 80), }, }, "03pu": &Item{}, "04pu": &Item{}, "02pu": &Item{}, "06pu": &Item{}, "05pu": &Item{}, "01pu": &Item{}, "07tv": &Item{}, "00fb": &Item{}, "01fb": &Item{}, }, }, /* animal */ &Folder{ Category: Animal, Pre: "addr", Suf: "00aa", Name: "European Adder", Items: map[string]*Item{ "00aa": &Item{ name: "European Adder", }, }, }, &Folder{ Category: Animal, Pre: "aant", Suf: "00aa", Name: "Army Ant", Items: map[string]*Item{ "00aa": &Item{ name: "Army Ant", }, }, }, &Folder{ Category: Animal, Pre: "alig", Suf: "00aa", Name: "Aligator", Items: map[string]*Item{ "00aa": &Item{ name: "Aligator", }, }, }, &Folder{ Category: Animal, Pre: "arow", Suf: "00aa", Name: "Poison Arrow Frog", Items: map[string]*Item{ "00aa": &Item{ name: "Poison Arrow Frog", }, }, }, &Folder{ Category: Animal, Pre: "babn", Suf: "00aa", Name: "Baboon", Items: map[string]*Item{ "00aa": &Item{ name: "Baboon", }, }, }, &Folder{ Category: Animal, Pre: "bara", Suf: "00aa", Name: "Baracuda", Items: map[string]*Item{ "00aa": &Item{ name: "Baracuda", }, }, }, &Folder{ Category: Animal, Pre: "boac", Suf: "00aa", Name: "Boa", Items: map[string]*Item{ "00aa": &Item{ name: "Boa", }, }, }, &Folder{ Category: Animal, Pre: "boct", Suf: "00aa", Name: "Blue-ringed Octopus", Items: map[string]*Item{ "00aa": &Item{ name: "Blue-ringed Octopus", }, }, }, &Folder{ Category: Animal, Pre: "bwid", Suf: "00aa", Name: "Black Widow Spider", Items: map[string]*Item{ "00aa": &Item{ name: "Black Widow Spider", }, }, }, &Folder{ Category: Animal, Pre: "cane", Suf: "00aa", Name: "Cane Toad", Items: map[string]*Item{ "00aa": &Item{ name: "Cane Toad", }, }, }, &Folder{ Category: Animal, Pre: "cbuf", Suf: "00aa", Name: "Cape Buffalo", Items: map[string]*Item{ "00aa": &Item{ name: "Cape Buffalo", }, }, }, &Folder{ Category: Animal, Pre: "cdog", Suf: "00aa", Name: "Cape Hunting Dog", Items: map[string]*Item{ "00aa": &Item{ name: "Cape Hunting Dog", }, }, }, &Folder{ Category: Animal, Pre: "cent", Suf: "00aa", Name: "Centipede", Items: map[string]*Item{ "00aa": &Item{ name: "Centipede", }, }, }, &Folder{ Category: Animal, Pre: "chee", Suf: "00aa", Name: "Cheetah", Items: map[string]*Item{ "00aa": &Item{ name: "Cheetah", }, }, }, &Folder{ Category: Animal, Pre: "cobr", Suf: "00aa", Name: "Cobra", Items: map[string]*Item{ "00aa": &Item{ name: "Cobra", }, }, }, &Folder{ Category: Animal, Pre: "cock", Suf: "00aa", Name: "Cockroach", Items: map[string]*Item{ "00aa": &Item{ name: "Cockroach", }, }, }, &Folder{ Category: Animal, Pre: "coug", Suf: "00aa", Name: "Cougar", Items: map[string]*Item{ "00aa": &Item{ name: "Cougar", }, }, }, &Folder{ Category: Animal, Pre: "crab", Suf: "00aa", Name: "Crab", Items: map[string]*Item{ "00aa": &Item{ name: "Crab", }, }, }, &Folder{ Category: Animal, Pre: "croc", Suf: "00aa", Name: "Crocodile", Items: map[string]*Item{ "00aa": &Item{ name: "Crocodile", }, }, }, &Folder{ Category: Animal, Pre: "eeel", Suf: "00aa", Name: "Electric Eel", Items: map[string]*Item{ "00aa": &Item{ name: "Electric Eel", }, }, }, &Folder{ Category: Animal, Pre: "elef", Suf: "00aa", Name: "Elefant", Items: map[string]*Item{ "00aa": &Item{ name: "Elefant", }, }, }, &Folder{ Category: Animal, Pre: "fsal", Suf: "00aa", Name: "Fire Salamander", Items: map[string]*Item{ "00aa": &Item{ name: "Fire Salamander", }, }, }, &Folder{ Category: Animal, Pre: "funl", Suf: "00aa", Name: "Funnel-web Spider", Items: map[string]*Item{ "00aa": &Item{ name: "Funnel-web Spider", }, }, }, &Folder{ Category: Animal, Pre: "gila", Suf: "00aa", Name: "Gila Monster", Items: map[string]*Item{ "00aa": &Item{ name: "Gila Monster", }, }, }, &Folder{ Category: Animal, Pre: "griz", Suf: "00aa", Name: "Grizzly Bear", Items: map[string]*Item{ "00aa": &Item{ name: "Grizzly Bear", }, }, }, &Folder{ Category: Animal, Pre: "gsqu", Suf: "00aa", Name: "Giant Squid", Items: map[string]*Item{ "00aa": &Item{ name: "Giant Squid", }, }, }, &Folder{ Category: Animal, Pre: "gwsh", Suf: "00aa", Name: "Great White Shark", Items: map[string]*Item{ "00aa": &Item{ name: "Great White Shark", }, }, }, &Folder{ Category: Animal, Pre: "gwsh", Suf: "00aa", Name: "Hammerhead Shark", Items: map[string]*Item{ "00aa": &Item{ name: "Hammerhead Shark", }, }, }, &Folder{ Category: Animal, Pre: "harp", Suf: "00aa", Name: "Harpy Eagle", Items: map[string]*Item{ "00aa": &Item{ name: "Harpy Eagle", }, }, }, &Folder{ Category: Animal, Pre: "hipp", Suf: "00aa", Name: "Hippopotamus", Items: map[string]*Item{ "00aa": &Item{ name: "Hippopotamus", }, }, }, &Folder{ Category: Animal, Pre: "hyen", Suf: "00aa", Name: "Hyena", Items: map[string]*Item{ "00aa": &Item{ name: "Hyena", }, }, }, &Folder{ Category: Animal, Pre: "jagu", Suf: "00aa", Name: "Jaguar", Items: map[string]*Item{ "00aa": &Item{ name: "Jaguar", }, }, }, &Folder{ Category: Animal, Pre: "kbee", Suf: "00aa", Name: "Killer Bee", Items: map[string]*Item{ "00aa": &Item{ name: "Killer Bee", }, }, }, &Folder{ Category: Animal, Pre: "komd", Suf: "00aa", Name: "Komodo Dragon", Items: map[string]*Item{ "00aa": &Item{ name: "Komodo Dragon", }, }, }, &Folder{ Category: Animal, Pre: "leop", Suf: "00aa", Name: "Leopard", Items: map[string]*Item{ "00aa": &Item{ name: "Leopard", }, }, }, &Folder{ Category: Animal, Pre: "lfsh", Suf: "00aa", Name: "Lionfish", Items: map[string]*Item{ "00aa": &Item{ name: "Lionfish", }, }, }, &Folder{ Category: Animal, Pre: "lion", Suf: "00aa", Name: "Lion", Items: map[string]*Item{ "00aa": &Item{ name: "Lion", }, }, }, &Folder{ Category: Animal, Pre: "mamb", Suf: "00aa", Name: "Black Mamba", Items: map[string]*Item{ "00aa": &Item{ name: "Black Mamba", }, }, }, &Folder{ Category: Animal, Pre: "mang", Suf: "00aa", Name: "Mangrove Snake", Items: map[string]*Item{ "00aa": &Item{ name: "Mangrove Snake", }, }, }, &Folder{ Category: Animal, Pre: "meel", Suf: "00aa", Name: "Moray Eel", Items: map[string]*Item{ "00aa": &Item{ name: "Moray Eel", }, }, }, &Folder{ Category: Animal, Pre: "mosq", Suf: "00aa", Name: "Mosquito", Items: map[string]*Item{ "00aa": &Item{ name: "Mosquito", }, }, }, &Folder{ Category: Animal, Pre: "mwar", Suf: "00aa", Name: "Portuguese Man-of-War", Items: map[string]*Item{ "00aa": &Item{ name: "Portuguese Man-of-War", }, }, }, &Folder{ Category: Animal, Pre: "orca", Suf: "00aa", Name: "Killer Whale", Items: map[string]*Item{ "00aa": &Item{ name: "Killer Whale", }, }, }, &Folder{ Category: Animal, Pre: "pbea", Suf: "00aa", Name: "Polar Bear", Items: map[string]*Item{ "00aa": &Item{ name: "Polar Bear", }, }, }, &Folder{ Category: Animal, Pre: "pira", Suf: "00aa", Name: "Piranha", Items: map[string]*Item{ "00aa": &Item{ name: "Piranha", }, }, }, &Folder{ Category: Animal, Pre: "plat", Suf: "00aa", Name: "Platypus", Items: map[string]*Item{ "00aa": &Item{ name: "Platypus", }, }, }, &Folder{ Category: Animal, Pre: "porc", Suf: "00aa", Name: "Porcupine Fish", Items: map[string]*Item{ "00aa": &Item{ name: "Porcupine Fish", }, }, }, &Folder{ Category: Animal, Pre: "post", Suf: "00aa", Name: "Passion-vine Caterpillar", Items: map[string]*Item{ "00aa": &Item{ name: "Passion-vine Caterpillar", }, }, }, &Folder{ Category: Animal, Pre: "pyth", Suf: "00aa", Name: "Python", Items: map[string]*Item{ "00aa": &Item{ name: "Python", }, }, }, &Folder{ Category: Animal, Pre: "rats", Suf: "00aa", Name: "Rats", Items: map[string]*Item{ "00aa": &Item{ name: "Rats", }, }, }, &Folder{ Category: Animal, Pre: "rhin", Suf: "00aa", Name: "Rhinoceros", Items: map[string]*Item{ "00aa": &Item{ name: "Rhinoceros", }, }, }, &Folder{ Category: Animal, Pre: "rttl", Suf: "00aa", Name: "Rattlesnake", Items: map[string]*Item{ "00aa": &Item{ name: "Rattlesnake", }, }, }, &Folder{ Category: Animal, Pre: "scor", Suf: "00aa", Name: "Scorpion", Items: map[string]*Item{ "00aa": &Item{ name: "Scorpion", }, }, }, &Folder{ Category: Animal, Pre: "seas", Suf: "00aa", Name: "Sea Snake", Items: map[string]*Item{ "00aa": &Item{ name: "Sea Snake", }, }, }, &Folder{ Category: Animal, Pre: "snap", Suf: "00aa", Name: "Snapping Turtle", Items: map[string]*Item{ "00aa": &Item{ name: "Snapping Turtle", }, }, }, &Folder{ Category: Animal, Pre: "sray", Suf: "00aa", Name: "Stingray", Items: map[string]*Item{ "00aa": &Item{ name: "Stingray", }, }, }, &Folder{ Category: Animal, Pre: "swsp", Suf: "00aa", Name: "Australian Sea Wasp", Items: map[string]*Item{ "00aa": &Item{ name: "Australian Sea Wasp", }, }, }, &Folder{ Category: Animal, Pre: "tasm", Suf: "00aa", Name: "Tasmanian Devil", Items: map[string]*Item{ "00aa": &Item{ name: "Tasmanian Devil", }, }, }, &Folder{ Category: Animal, Pre: "tigr", Suf: "00aa", Name: "Tiger", Items: map[string]*Item{ "00aa": &Item{ name: "Tiger", }, }, }, &Folder{ Category: Animal, Pre: "vamp", Suf: "00aa", Name: "Vampire Bat", Items: map[string]*Item{ "00aa": &Item{ name: "Vampire Bat", }, }, }, &Folder{ Category: Animal, Pre: "vult", Suf: "00aa", Name: "Vulture", Items: map[string]*Item{ "00aa": &Item{ name: "Vulture", }, }, }, &Folder{ Category: Animal, Pre: "wart", Suf: "00aa", Name: "Warthog", Items: map[string]*Item{ "00aa": &Item{ name: "Warthog", }, }, }, &Folder{ Category: Animal, Pre: "wasp", Suf: "00aa", Name: "Wasp", Items: map[string]*Item{ "00aa": &Item{ name: "Wasp", }, }, }, &Folder{ Category: Animal, Pre: "wlvr", Suf: "00aa", Name: "Wolverine", Items: map[string]*Item{ "00aa": &Item{ name: "Wolverine", }, }, }, &Folder{ Category: Animal, Pre: "wolf", Suf: "00aa", Name: "Wolf", Items: map[string]*Item{ "00aa": &Item{ name: "Wolf", }, }, }, } func init() { for _, f := range folders { for _, it := range f.Items { it.f = f if f.Pre == "indx" { it.Targets = f.Items["0001"].Targets } } } } func check(err error, msg string) { if err != nil { log.Fatalf("%s: %s\n", msg, err) } } func resize(img image.Image, scale int) image.Image { bounds := img.Bounds() newX := bounds.Dx() * scale newY:= bounds.Dy() * scale dst := image.NewRGBA(image.Rect(0, 0, newX, newY)) xdraw.NearestNeighbor.Scale(dst, dst.Rect, img, img.Bounds(), xdraw.Over, nil) return dst } func readImagePath(path string) *draw.Image { bs, err := os.ReadFile(path) check(err, "read file") data, err := szdd.Expand(bs) check(err, "expand") img, _, err := image.Decode(bytes.NewReader(data)) check(err, "decode") if scale > 1 { img = resize(img, scale) } bounds := img.Bounds() ni, err := dui.Display.AllocImage(bounds, draw.ABGR32, false, draw.White) check(err, "allocimage") var rgba *image.RGBA switch i := img.(type) { case *image.RGBA: rgba = i default: b := img.Bounds() rgba = image.NewRGBA(image.Rectangle{image.ZP, b.Size()}) imagedraw.Draw(rgba, rgba.Bounds(), img, b.Min, imagedraw.Src) } _, err = ni.Load(rgba.Bounds(), rgba.Pix) check(err, "load image") return ni } func main() { sc := flag.Int("x", 0, "scale") flag.Parse() scale = *sc var err error dui, err = duit.NewDUI("wildlife", nil) check(err, "new dui") if scale == 0 { if dui.Display.DPI > 100 { scale = 2 } else { scale = 1 } } f := getFolder("", "cont") it := f.Main() history = append(history, it) dui.Top.UI = it dui.Render() for { select { case e := <-dui.Inputs: dui.Input(e) case err, ok := <-dui.Error: if !ok { return } log.Printf("duit: %s\n", err) } } }