Added a debug overlay.

This commit is contained in:
Sander Schobers 2020-05-24 20:15:40 +02:00
parent 43d49a0dbb
commit 869f87dd4f
3 changed files with 171 additions and 0 deletions

View File

@ -47,6 +47,7 @@ func newContext(r Renderer, s *Style, view Control) *context {
fonts: NewFonts(r),
textures: NewTextures(r)}
ctx.overlays.AddOnTop(uiDefaultTooltipOverlay, ctx.tooltip, false)
ctx.overlays.AddOnTop(DefaultDebugOverlay, NewDebugOverlay(view), false)
return ctx
}

149
ui/debug.go Normal file
View File

@ -0,0 +1,149 @@
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
}

21
ui/debug_test.go Normal file
View File

@ -0,0 +1,21 @@
package ui
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestControlName(t *testing.T) {
assert.Equal(t, "ControlBase", controlName(&ControlBase{}))
assert.Equal(t, "Label", controlName(&Label{}))
}
func TestControlChildren(t *testing.T) {
assert.Len(t, controlChildren(&ContainerBase{}), 0)
assert.Len(t, controlChildren(&ControlBase{}), 0)
assert.Len(t, controlChildren(&ContainerBase{Children: []Control{nil, nil}}), 2)
assert.Len(t, controlChildren(&StackPanel{ContainerBase: ContainerBase{Children: []Control{nil, nil}}}), 2)
assert.Len(t, controlChildren(&Proxy{Content: &ControlBase{}}), 1)
assert.Len(t, controlChildren(&overflow{Proxy: Proxy{Content: &ControlBase{}}}), 1)
}