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)
}
}
}