Added a debug overlay.
This commit is contained in:
parent
43d49a0dbb
commit
869f87dd4f
@ -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
149
ui/debug.go
Normal 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
21
ui/debug_test.go
Normal 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)
|
||||
}
|
Loading…
Reference in New Issue
Block a user