shithub: wildlife

Download patch

ref: 7084ab4489ce1ddb6595a8f2624e8fdf23a73d8f
author: Philip Silva <[email protected]>
date: Mon Mar 28 19:43:43 EDT 2022

First commit

--- /dev/null
+++ b/.gitignore
@@ -1,0 +1,2 @@
+/data
+/wildlife
--- /dev/null
+++ b/README
@@ -1,0 +1,13 @@
+Plan 9 port of MS Dangerous Creatures (very wip)
+
+At the moment it's almost unusable and only the top level menus work. (right click: back)
+
+Compile:
+
+go build .
+
+Usage:
+
+./wildlife [-x scale]
+
+Original iso required, files need to be in ./data/
--- /dev/null
+++ b/go.mod
@@ -1,0 +1,17 @@
+module wildlife
+
+go 1.18
+
+replace 9fans.net/go v0.0.0-00010101000000-000000000000 => github.com/psilva261/go v0.0.0-20210805155101-6b9925e0d807
+
+replace 9fans.net/go v0.0.2 => github.com/psilva261/go v0.0.0-20210805155101-6b9925e0d807
+
+replace github.com/mjl-/duit v0.0.0-20200330125617-580cb0b2843f => github.com/psilva261/duit v0.0.0-20210802155600-7e8fedefa7ba
+
+require (
+	9fans.net/go v0.0.2
+	github.com/mjl-/duit v0.0.0-20200330125617-580cb0b2843f
+	golang.org/x/image v0.0.0-20220321031419-a8550c1d254a
+)
+
+require github.com/psilva261/szdd v0.0.0-20220328193535-155e45add743 // indirect
--- /dev/null
+++ b/go.sum
@@ -1,0 +1,12 @@
+github.com/psilva261/duit v0.0.0-20210802155600-7e8fedefa7ba h1:p8M5yp22QzefbIU3xGERHYnGxlfkcjWV6dh62xIO0U4=
+github.com/psilva261/duit v0.0.0-20210802155600-7e8fedefa7ba/go.mod h1:Ukumf0oazEttGwdWuN21g81jNap4NVccEgKuAUAqkf0=
+github.com/psilva261/go v0.0.0-20210805155101-6b9925e0d807 h1:JJqdNuwkTdbAe8hxrTaBBbX5TTk88gJrOhGigxoQb7c=
+github.com/psilva261/go v0.0.0-20210805155101-6b9925e0d807/go.mod h1:lfPdxjq9v8pVQXUMBCx5EO5oLXWQFlKRQgs1kEkjoIM=
+github.com/psilva261/szdd v0.0.0-20220328172236-36b7351d8d78 h1:4TlrF1ZxPU0gAEKXyLv39YsYBsC7kVSyAzPh2WFqnrU=
+github.com/psilva261/szdd v0.0.0-20220328172236-36b7351d8d78/go.mod h1:GUNIiWDWdjykRjKAc2I00bfkn6i3P4h2HIUZrEYl3F0=
+github.com/psilva261/szdd v0.0.0-20220328193535-155e45add743 h1:UTvkQdz3N7mxcTdRZM3b5hX6N1SXHdKKjsJdmZTn7rc=
+github.com/psilva261/szdd v0.0.0-20220328193535-155e45add743/go.mod h1:GUNIiWDWdjykRjKAc2I00bfkn6i3P4h2HIUZrEYl3F0=
+golang.org/x/image v0.0.0-20220321031419-a8550c1d254a h1:LnH9RNcpPv5Kzi15lXg42lYMPUf0x8CuPv1YnvBWZAg=
+golang.org/x/image v0.0.0-20220321031419-a8550c1d254a/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
+golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
--- /dev/null
+++ b/main.go
@@ -1,0 +1,510 @@
+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 {
+	*duit.Image
+
+	Pre string
+	Suf string
+	Name string
+	Items map[string]string
+	Targets []Target
+}
+
+func getFolder(root, pre string) (ff *Folder) {
+	//log.Printf("getFolder(%v, %v)", root, pre)
+	var rf *Folder
+	if root != "" {
+		for _, f := range folders {
+			if f.Pre == root {
+				rf = f
+			}
+		}
+	}
+	for _, f := range folders {
+		if f.Pre == pre {
+			ff = f
+		}
+	}
+	var fn string
+	if ff != nil {
+		fn = ff.Main()
+	} else {
+		ff = rf
+		fn = ff.getItem(pre)
+	}
+	ff.Image = &duit.Image{
+		Image: readImagePath(fn),
+	}
+	return
+}
+
+func (f Folder) Main() string {
+	fnSuf := f.Suf
+	if _, ok := f.Items[f.Suf]; !ok {
+		fnSuf = "0001"
+	}
+	return fmt.Sprintf("./data/about/%v%v/%v%v.dib", f.Pre, f.Suf, f.Pre, fnSuf)
+}
+
+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)
+}
+
+func (f *Folder) 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 _, t := range f.Targets {
+			if t.has(m.Point) {
+				tf := getFolder(f.Pre, t.key)
+				dui.Top.UI = tf
+				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")
+		dui.Top.UI = tf
+		dui.MarkLayout(dui.Top.UI)
+		dui.MarkDraw(dui.Top.UI)
+		dui.Render()
+	}
+	return f.Image.Mouse(dui, self, m, origM, orig)
+}
+
+type Target struct {
+	key string
+	xy draw.Point
+	r int
+}
+
+func (t Target) has(p draw.Point) bool {
+	x := p.X * 2 / scale
+	y := p.Y * 2 / scale
+	return math.Abs(float64(x)-float64(t.xy.X)) < float64(t.r) && math.Abs(float64(y)-float64(t.xy.Y)) < float64(t.r)
+}
+
+var folders = []*Folder{
+	&Folder{
+		Pre: "afri",
+		Suf: "00aa",
+		Name: "Africa",
+		Items: map[string]string{
+			"00aa": "Waterhole",
+			"00fb": "Art",
+		},
+	},
+	&Folder{
+		Pre: "atls",
+		Suf: "00nv",
+		Name: "Atlas",
+		Items: map[string]string{
+			"00nv": "Continents",
+			"01p1": "African reptiles",
+			"01p2": "African herbivores",
+			"01pu": "Africa",
+			"02pu": "Asia",
+			"03pu": "Australia",
+			"04pu": "Europe",
+			"05pu": "North America",
+			"06pu": "South America",
+		},
+		Targets: []Target{
+			Target{
+				key: "01pu",
+				xy: draw.Point{
+					X: 659,
+					Y: 461,
+				},
+				r: 100,
+			},
+			Target{
+				key: "02pu",
+				xy: draw.Point{
+					X: 931,
+					Y: 275,
+				},
+				r: 200,
+			},
+			Target{
+				key: "03pu",
+				xy: draw.Point{
+					X: 1117,
+					Y: 603,
+				},
+				r: 50,
+			},
+			Target{
+				key: "04pu",
+				xy: draw.Point{
+					X: 600,
+					Y: 262,
+				},
+				r: 50,
+			},
+			Target{
+				key: "05pu",
+				xy: draw.Point{
+					X: 222,
+					Y: 270,
+				},
+				r: 140,
+			},
+			Target{
+				key: "06pu",
+				xy: draw.Point{
+					X: 350,
+					Y: 552,
+				},
+				r: 120,
+			},
+		},
+	},
+	&Folder{
+		Pre: "aust",
+		Suf: "00aa",
+		Name: "Australia",
+		Items: map[string]string{
+			"00aa": "Oddities",
+		},
+	},
+	&Folder{
+		Pre: "beet",
+		Suf: "00aa",
+		Name: "Beetles",
+		Items: map[string]string{
+			"00aa": "Beetles",
+		},
+	},
+	&Folder{
+		Pre: "frst",
+		Suf: "00aa",
+		Name: "Forest",
+		Items: map[string]string{
+			"00aa": "Forest Environments",
+		},
+	},
+	&Folder{
+		Pre: "cont",
+		Suf: "00nv",
+		Name: "Contents",
+		Items: map[string]string{
+			"00nv": "Contents",
+		},
+		Targets: []Target{
+			Target{
+				key: "atls",
+				xy: draw.Point{
+					X: 242,
+					Y: 190,
+				},
+				r: 150,
+			},
+			Target{
+				key: "habt",
+				xy: draw.Point{
+					X: 256,
+					Y: 588,
+				},
+				r: 200,
+			},
+			Target{
+				key: "indx",
+				xy: draw.Point{
+					X: 920,
+					Y: 614,
+				},
+				r: 200,
+			},
+			Target{
+				key: "weap",
+				xy: draw.Point{
+					X: 997,
+					Y: 200,
+				},
+				r: 200,
+			},
+		},
+	},
+	&Folder{
+		Pre: "guid",
+		Suf: "00nv",
+		Name: "Guides",
+		Items: map[string]string{
+			"00nv": "Guides",
+		},
+	},
+	&Folder{
+		Pre: "habt",
+		Suf: "00nv",
+		Name: "Habitats",
+		Items: map[string]string{
+			"00nv": "Habitats",
+		},
+	},
+	&Folder{
+		Pre: "help",
+		Suf: "00nv",
+		Name: "Help",
+		Items: map[string]string{
+			"00nv": "Help",
+		},
+	},
+	&Folder{
+		Pre: "indx",
+		Suf: "00nv",
+		Name: "Index",
+		Items: map[string]string{
+			"0001": "Index",
+		},
+		Targets: []Target{
+			Target{
+				key: "0001",
+				xy: draw.Point{
+					X: 48,
+					Y: 90,
+				},
+				r: 25,
+			},
+			Target{
+				key: "0002",
+				xy: draw.Point{
+					X: 97,
+					Y: 90,
+				},
+				r: 25,
+			},
+			Target{
+				key: "0003",
+				xy: draw.Point{
+					X: 144,
+					Y: 90,
+				},
+				r: 25,
+			},
+			Target{
+				key: "0003",
+				xy: draw.Point{
+					X: 186,
+					Y: 90,
+				},
+				r: 25,
+			},
+			Target{
+				key: "0004",
+				xy: draw.Point{
+					X: 236,
+					Y: 90,
+				},
+				r: 25,
+			},
+			Target{
+				key: "0005",
+				xy: draw.Point{
+					X: 340,
+					Y: 90,
+				},
+				r: 40,
+			},
+			Target{
+				key: "0006",
+				xy: draw.Point{
+					X: 440,
+					Y: 90,
+				},
+				r: 40,
+			},
+			Target{
+				key: "0007",
+				xy: draw.Point{
+					X: 600,
+					Y: 90,
+				},
+				r: 90,
+			},
+			Target{
+				key: "0008",
+				xy: draw.Point{
+					X: 748,
+					Y: 90,
+				},
+				r: 40,
+			},
+			Target{
+				key: "0009",
+				xy: draw.Point{
+					X: 843,
+					Y: 90,
+				},
+				r: 38,
+			},
+			Target{
+				key: "0010",
+				xy: draw.Point{
+					X: 947,
+					Y: 90,
+				},
+				r: 60,
+			},
+			Target{
+				key: "0011",
+				xy: draw.Point{
+					X: 1112,
+					Y: 90,
+				},
+				r: 85,
+			},
+		},
+	},
+	/*Folder{
+		Pre: "titl",
+		Suf: "00nv",
+		Name: "Title",
+		Items: map[string]string{
+			"00nv": "Title",
+		},
+	},*/
+	&Folder{
+		Pre: "weap",
+		Suf: "00nv",
+		Name: "Index",
+		Items: map[string]string{
+			"00nv": "Index",
+		},
+		Targets: []Target{
+			Target{
+				key: "01pu",
+				xy: draw.Point{
+					X: 250,
+					Y: 400,
+				},
+				r: 150,
+			},
+			Target{
+				key: "03pu",
+				xy: draw.Point{
+					X: 654,
+					Y: 375,
+				},
+				r: 150,
+			},
+			Target{
+				key: "02pu",
+				xy: draw.Point{
+					X: 1047,
+					Y: 400,
+				},
+				r: 150,
+			},
+		},
+	},
+}
+
+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() * 2
+	newY:= bounds.Dy() * 2
+	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
+		}
+	}
+
+	_=readImagePath
+
+	f := getFolder("", "cont")
+
+	dui.Top.UI = f
+	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)
+		}
+	}
+}