274 lines · 5.5 KB · Go
RawDownload
package control9 import (	"bitbucket.org/mischief/draw9"	"fmt"	"image"	"log"	"strings") type Group struct {	*BaseControl	lastbut, border int	mansize         bool	separation      int	selected        int	lastkid         int	bordercolor     *draw9.Image	image           *draw9.Image	kids            []Control	separators      []image.Rectangle} func (g *Group) Ctl(e string) {	var r image.Rectangle	f := strings.Fields(e) 	switch f[0] {	case "add":		for i := 1; i < len(f); i++ {			if c := g.set.Called(f[i]); c != nil {				g.add(c)			} else {				log.Printf("no such control %q", f[i])			}		}	case "border":		bsz := ctlatoi(f[1])		if bsz < 0 {			log.Printf("bad border size %d", bsz)		} else {			g.border = ctlatoi(f[1])		}	case "bordercolor":	case "focus":	case "hide":		for _, c := range g.kids {			c.Ctl("hide")		}		g.hidden = true	case "image":	case "rect":		if len(f) < 5 {			log.Printf("%s: bad rectangle: %s", g.name, e)		} else {			r := image.Rect(0, 0, 1, 1)			r.Min.X = ctlatoi(f[1])			r.Min.Y = ctlatoi(f[2])			r.Max.X = ctlatoi(f[3])			r.Max.Y = ctlatoi(f[4]) 			if r.Dx() <= 0 || r.Dy() <= 0 {				log.Printf("%s: bad rectangle: %s", g.name, e)				break			} 			g.rect = r			r = r.Inset(g.border)			if len(g.kids) == 0 {				return			}			switch g.typ {			case CtlRow:				g.rowresize(r)			}		}	case "remove":	case "reveal":	case "show":		if g.hidden {			break		}		g.screen.Border(g.rect, g.border, g.bordercolor, g.bordercolor.R.Min)		r := g.rect.Inset(g.border)		g.screen.Draw(r, g.image, nil, g.image.R.Min)		for i := 0; i < len(g.kids); i++ {			g.kids[i].Ctl("show")		}		g.image.Display.Flush()	case "size":		switch len(f) {		case 1:			g.mansize = false			g.SetSize()		case 5:			r.Max.X = ctlatoi(f[3])			r.Max.Y = ctlatoi(f[4])			fallthrough		case 3:			r.Min.X = ctlatoi(f[1])			r.Min.Y = ctlatoi(f[2])			if r.Min.X <= 0 || r.Min.Y <= 0 || r.Max.X <= 0 || r.Max.Y <= 0 || r.Max.X < r.Min.X || r.Max.Y < r.Min.Y {				log.Printf("%s: bad rectangle: %s", g.name, e)				return			}			g.size = r			g.mansize = true		}	case "separation":	default:		log.Printf("%q: unrecognized message %q", g.name, f[0])	}} // interface functions func (g *Group) Mouse(ms draw9.Mouse) {	log.Printf("%s mouse %s", g.name, ms)	/* TODO CtlStack */	lastkid := -1	for i, k := range g.kids {		if ((!ms.Any() || g.lastbut == 0) && ms.Pt().In(k.Rect())) || ((ms.Any() || g.lastbut != 0) && g.lastkid == i) {			k.Mouse(ms)			lastkid = i		}	}	g.lastkid = lastkid	g.lastbut = ms.Buttons()} func (g *Group) Key(r rune) {}func (g *Group) Exit()      {}func (g *Group) SetSize() {	if g.mansize {		return	} 	r := image.Rect(1, 1, 1, 1)	for i, k := range g.kids {		k.SetSize()		sz := k.Size()		if sz.Min.X == 0 || sz.Min.Y == 0 || sz.Max.X == 0 || sz.Max.Y == 0 {			log.Printf("%s: invalid size: %s %s", g.name, k.Name(), sz)			return		}		switch g.typ {		case CtlRow:			if i > 0 {				r.Min.X += sz.Min.X + g.border				r.Max.X += sz.Max.X + g.border			} else {				r.Min.X = sz.Min.X				r.Max.X = sz.Max.X			}			if r.Min.Y < sz.Min.Y {				r.Min.X = sz.Min.Y			}			if r.Max.Y < sz.Max.Y {				r.Max.Y = sz.Max.Y			}		}	}	g.size = r.Add(image.Pt(g.border, g.border))	log.Printf("%s size %s", g.name, g.size)}func (g *Group) Activate() {} // private functions func (g *Group) init() {	g.bordercolor = geti("black")	g.image = geti("white")	g.border = 0	g.mansize = false	g.separation = 0	g.selected = -1	g.lastkid = -1} func (g *Group) add(c Control) {	g.kids = append(g.kids, c)} // resizing functionsfunc (g *Group) rowresize(r image.Rectangle) {	var j int	var rr image.Rectangle 	x := r.Dx()	y := r.Dy() 	if x < g.size.Min.X {		log.Printf("rowresize %s: too narrow: need %d, have %d", g.name, g.size.Min.X, x)		r.Max.X = r.Min.X + g.size.Min.X		x = r.Dx()	} 	if y < g.size.Min.Y {		log.Printf("rowresize %s: too short: need %d, have %d", g.name, g.size.Min.Y, y)		r.Max.Y = r.Min.Y + g.size.Min.Y	} 	d := make([]int, len(g.kids))	p := make([]int, len(g.kids))	for i, k := range g.kids {		ksz := k.Size()		d[i] = ksz.Min.X		x -= d[i]		p[i] = ksz.Max.Y - ksz.Min.X	}	x -= (len(g.kids) - 1) * g.separation	if x < 0 {		log.Printf("rowresize %s: x == %d", g.name, x)		x = 0	} 	if x >= g.size.Max.X-g.size.Min.X {		log.Printf("rowresize %s: max: %d > %d - %d", g.name, x, g.size.Max.X, g.size.Min.X)		for i, _ := range g.kids {			d[i] += p[i]		}		x -= g.size.Max.X - g.size.Min.X	} else {		log.Printf("rowresize %s: divvie up: %d < %d - %d", g.name, x, g.size.Max.X, g.size.Min.X)		// rects cant be max width		j = x		for i, _ := range g.kids {			t := p[i] * x / (g.size.Max.X - g.size.Min.X)			d[i] += t			j -= t		}		d[0] += j		x = 0	}	g.separators = make([]image.Rectangle, len(g.kids)-1)	rr = r	for i, k := range g.kids {		if i < len(g.kids)-1 {			g.separators[i].Min.Y = r.Min.Y			g.separators[i].Max.Y = r.Max.Y		}		t := x / (len(g.kids) - i)		x -= t		j += t / 2 		rr.Min.X = r.Min.X + j		if i > 0 {			g.separators[i-1].Max.X = rr.Min.X		}		j += d[i]		rr.Max.X = r.Min.X + j		if i < len(g.kids)-1 {			g.separators[i].Min.X = rr.Max.X		}		j += g.separation + t - t/2		k.Ctl(fmt.Sprintf("rect %d %d %d %d", rr.Min.X, rr.Min.Y, rr.Max.X, rr.Max.Y)) 	}} // ctor // Row creates a new Group that is visually represented as a row of controls.func (cs *Controlset) Row(name string) Control {	row := &Group{		BaseControl: cs.newctl(name, CtlRow),	} 	row.init() 	cs.addctl(row) 	return row}