150 lines
3.4 KiB
Go
150 lines
3.4 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()
|
||
|
// bounds := control.Bounds()
|
||
|
// renderer.Rectangle(bounds, o.boundsColor, 1)
|
||
|
|
||
|
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()
|
||
|
renderer.FillRectangle(pos.RectRel2D(nameTexture.Width(), nameTexture.Height()), color.Black)
|
||
|
renderer.DrawTexturePoint(nameTexture, pos)
|
||
|
childPos := pos.Add2D(nameTexture.Width()+8, 0)
|
||
|
for _, child := range node.Children {
|
||
|
if childPos.Y == maxY {
|
||
|
childPos.Y = maxY + nameTexture.Height()
|
||
|
}
|
||
|
renderHoverNode(childPos, child)
|
||
|
maxY = childPos.Y
|
||
|
childPos.Y += nameTexture.Height() + 8
|
||
|
}
|
||
|
}
|
||
|
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 {
|
||
|
if !hover.In(control.Bounds()) {
|
||
|
return nil
|
||
|
}
|
||
|
node := &controlNode{Name: controlName(control)}
|
||
|
for _, child := range controlChildren(control) {
|
||
|
childNode := createHoverNodes(hover, child)
|
||
|
if childNode != nil {
|
||
|
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
|
||
|
Children []*controlNode
|
||
|
}
|