ref: eca59fe0c9f2e78eca5246e626950ee5b408ca12
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 ) type Folder struct { 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/about/%v%v/%v%v.dib", f.Pre, f.Suf, f.Pre, k) it.Image = &duit.Image{ Image: readImagePath(fn), } } return it } } return nil } /*func (f Folder) getItem(k string) string { fnSuf := k return fmt.Sprintf("./data/about/%v%v/%v%v.dib", f.Pre, f.Suf, f.Pre, fnSuf) }*/ 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) { if m.Buttons&1 == 1 { //log.Printf("m=%+v, origM=%+v", m, origM) for k, t := range it.Targets { if t.has(m.Point) { 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 { 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{ &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", }, "02pu": &Item{ name: "Asia", }, "03pu": &Item{ name: "Australia", }, "04pu": &Item{ name: "Europe", }, "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{}, }, }, } 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") dui.Top.UI = f.Main() 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) } } }