shithub: mycel

ref: 89d4bc312ff9a8639a4bf912f36e1a48e8a4e113
dir: /browser/duitx/place.go/

View raw version
package duitx

// Original code from github.com/mjl-/duit
//
// Copyright 2018 Mechiel Lukkien mechiel@ueber.net
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

import (
	"image"

	"9fans.net/go/draw"
	"github.com/mjl-/duit"
	"github.com/psilva261/opossum/logger"
)

// Place contains other UIs it can position absolute, possibly on top of each other.
type Place struct {
	// Place is called during layout. It must configure Kids, and set self.R, based on sizeAvail.
	Place      func(self *duit.Kid, sizeAvail image.Point) `json:"-"`
	Kids       []*duit.Kid                                 // Kids to draw, set by the Place function.
	Background *draw.Image                                 `json:"-"` // For background color.

	kidsReversed []*duit.Kid
	size         image.Point
	img          *draw.Image
	force        bool
}

var _ duit.UI = &Place{}

func (ui *Place) ensure() {
	if len(ui.kidsReversed) == len(ui.Kids) {
		return
	}
	ui.kidsReversed = make([]*duit.Kid, len(ui.Kids))
	for i, k := range ui.Kids {
		ui.kidsReversed[len(ui.Kids)-1-i] = k
	}
}

func (ui *Place) Layout(dui *duit.DUI, self *duit.Kid, sizeAvail image.Point, force bool) {
	ui.ensure()
	debugLayout(dui, self)

	ui.Place(self, sizeAvail)
}

func (ui *Place) Draw(dui *duit.DUI, self *duit.Kid, img *draw.Image, orig image.Point, m draw.Mouse, force bool) {
	if self.Draw == duit.Clean {
		return
	}
	self.Draw = duit.Clean
	if ui.img == nil || ui.Kids[0].R.Size() != ui.img.R.Size() {
		var err error
		if ui.img != nil {
			ui.img.Free()
			ui.img = nil
		}
		if ui.Kids[0].R.Dx() == 0 || ui.Kids[0].R.Dy() == 0 {
			return
		}
		ui.img, err = dui.Display.AllocImage(ui.Kids[0].R, draw.ARGB32, false, 0x00000000)
		if err != nil {
			log.Errorf("allocimage: %v", err)
			return
		}
		self.Draw = duit.DirtyKid
	}
	if self.Draw == duit.DirtyKid || ui.force {
		duit.KidsDraw(dui, self, ui.Kids, ui.size, ui.Background, ui.img, image.ZP, m, true)
		self.Draw = duit.Clean
		ui.force = false
	}
	img.Draw(ui.img.R.Add(orig), ui.img, nil, image.ZP)
}

func (ui *Place) result(dui *duit.DUI, self *duit.Kid, r *duit.Result) {
	relayout := false
	redraw := false

	for _, k := range ui.Kids {
		if k.Layout != duit.Clean {
			relayout = true
		} else if k.Draw != duit.Clean {
			redraw = true
		}
	}
	if relayout {
		self.Layout = duit.DirtyKid
		self.Draw = duit.DirtyKid
		ui.force = ui.force || r.Consumed
	} else if redraw {
		self.Draw = duit.DirtyKid
		ui.force = ui.force || r.Consumed
	}
}

func (ui *Place) Mouse(dui *duit.DUI, self *duit.Kid, m draw.Mouse, origM draw.Mouse, orig image.Point) (r duit.Result) {
	r = duit.KidsMouse(dui, self, ui.kidsReversed, m, origM, orig)
	ui.result(dui, self, &r)
	return
}

func (ui *Place) Key(dui *duit.DUI, self *duit.Kid, k rune, m draw.Mouse, orig image.Point) (r duit.Result) {
	r = duit.KidsKey(dui, self, ui.kidsReversed, k, m, orig)
	ui.result(dui, self, &r)
	return
}

func (ui *Place) FirstFocus(dui *duit.DUI, self *duit.Kid) (warp *image.Point) {
	return duit.KidsFirstFocus(dui, self, ui.Kids)
}

func (ui *Place) Focus(dui *duit.DUI, self *duit.Kid, o duit.UI) (warp *image.Point) {
	return duit.KidsFocus(dui, self, ui.Kids, o)
}

func (ui *Place) Mark(self *duit.Kid, o duit.UI, forLayout bool) (marked bool) {
	return duit.KidsMark(self, ui.Kids, o, forLayout)
}

func (ui *Place) Print(self *duit.Kid, indent int) {
	duit.PrintUI("Place", self, indent)
	duit.KidsPrint(ui.Kids, indent+1)
}