162 lines
3.8 KiB
Go
162 lines
3.8 KiB
Go
package ui
|
|
|
|
import (
|
|
"image/color"
|
|
"reflect"
|
|
|
|
"opslag.de/schobers/geom"
|
|
|
|
"opslag.de/schobers/zntg"
|
|
)
|
|
|
|
const DefaultDebugOverlay = "ui-default-debug"
|
|
|
|
func controlChildren(control Control) []Control {
|
|
container, ok := control.(*ContainerBase)
|
|
if ok {
|
|
return container.Children
|
|
}
|
|
|
|
proxy, ok := control.(*Proxy)
|
|
if ok {
|
|
return []Control{proxy.Content}
|
|
}
|
|
return controlChildrenReflect(reflect.ValueOf(control))
|
|
}
|
|
|
|
func controlChildrenReflect(control reflect.Value) []Control {
|
|
switch control.Kind() {
|
|
case reflect.Interface:
|
|
return controlChildrenReflect(control.Elem())
|
|
case reflect.Ptr:
|
|
return controlChildrenReflect(control.Elem())
|
|
}
|
|
if reflect.TypeOf(ContainerBase{}) == control.Type() {
|
|
container := control.Interface().(ContainerBase)
|
|
return container.Children
|
|
}
|
|
if reflect.TypeOf(Proxy{}) == control.Type() {
|
|
proxy := control.Interface().(Proxy)
|
|
return []Control{proxy.Content}
|
|
}
|
|
if control.NumField() == 0 {
|
|
return nil
|
|
}
|
|
field := control.Type().Field(0)
|
|
if !field.Anonymous {
|
|
return nil
|
|
}
|
|
return controlChildrenReflect(control.Field(0))
|
|
}
|
|
|
|
func controlName(control Control) string {
|
|
typ := reflect.TypeOf(control)
|
|
return typ.Elem().Name()
|
|
}
|
|
|
|
type debugOverlay struct {
|
|
ControlBase
|
|
|
|
root Control
|
|
|
|
hoverNodes *controlNode
|
|
|
|
boundsColor color.Color
|
|
textColor color.Color
|
|
textShadowColor color.Color
|
|
}
|
|
|
|
func NewDebugOverlay(root Control) *debugOverlay {
|
|
return &debugOverlay{
|
|
root: root,
|
|
boundsColor: zntg.MustHexColor(`#00FF003F`),
|
|
textColor: zntg.MustHexColor(`#FFFFFF3F`),
|
|
textShadowColor: zntg.MustHexColor(`#0000003F`),
|
|
}
|
|
}
|
|
|
|
func (o *debugOverlay) renderControl(ctx Context, control Control) {
|
|
renderer := ctx.Renderer()
|
|
|
|
currentColor := zntg.MustHexColor("#FF0000")
|
|
parentColor := zntg.MustHexColor("#0000FF")
|
|
|
|
var maxY float32
|
|
var renderHoverNode func(pos geom.PointF32, node *controlNode)
|
|
renderHoverNode = func(pos geom.PointF32, node *controlNode) {
|
|
if node == nil {
|
|
return
|
|
}
|
|
nameTexture, err := ctx.Fonts().TextTexture("debug", color.White, node.Name)
|
|
if err != nil {
|
|
return
|
|
}
|
|
defer nameTexture.Destroy()
|
|
nameTextureWidth := float32(nameTexture.Width())
|
|
nameTextureHeight := float32(nameTexture.Height())
|
|
renderer.FillRectangle(pos.RectRel2D(nameTextureWidth, nameTextureHeight), color.Black)
|
|
renderer.DrawTexturePoint(nameTexture, pos)
|
|
childPos := pos.Add2D(nameTextureWidth+ctx.Style().Dimensions.Margin, 0)
|
|
if len(node.Children) == 0 {
|
|
renderer.Rectangle(node.Parent.Bounds, parentColor, 1)
|
|
renderer.Rectangle(node.Bounds, currentColor, 1)
|
|
}
|
|
for _, child := range node.Children {
|
|
if childPos.Y == maxY {
|
|
childPos.Y = maxY + nameTextureHeight
|
|
}
|
|
renderHoverNode(childPos, child)
|
|
maxY = childPos.Y
|
|
childPos.Y += nameTextureHeight + ctx.Style().Dimensions.Margin
|
|
}
|
|
}
|
|
renderHoverNode(geom.PtF32(4, 4), o.hoverNodes)
|
|
|
|
children := controlChildren(control)
|
|
for _, child := range children {
|
|
o.renderControl(ctx, child)
|
|
}
|
|
}
|
|
|
|
func createHoverNodes(hover geom.PointF32, control Control) *controlNode {
|
|
bounds := control.Bounds()
|
|
if !hover.In(bounds) {
|
|
return nil
|
|
}
|
|
node := &controlNode{Name: controlName(control), Bounds: bounds}
|
|
for _, child := range controlChildren(control) {
|
|
childNode := createHoverNodes(hover, child)
|
|
if childNode == nil {
|
|
continue
|
|
}
|
|
childNode.Parent = node
|
|
node.Children = append(node.Children, childNode)
|
|
}
|
|
return node
|
|
}
|
|
|
|
func (o *debugOverlay) Handle(ctx Context, e Event) bool {
|
|
switch e := e.(type) {
|
|
case *MouseMoveEvent:
|
|
o.hoverNodes = createHoverNodes(e.Pos(), o.root)
|
|
case *MouseLeaveEvent:
|
|
o.hoverNodes = nil
|
|
}
|
|
return false
|
|
}
|
|
|
|
func (o *debugOverlay) Hidden() {}
|
|
|
|
func (o *debugOverlay) Render(ctx Context) {
|
|
o.renderControl(ctx, o.root)
|
|
}
|
|
|
|
func (o *debugOverlay) Shown() {}
|
|
|
|
type controlNode struct {
|
|
Name string
|
|
Bounds geom.RectangleF32
|
|
Parent *controlNode
|
|
Children []*controlNode
|
|
}
|