Skip to content

Commit 573f4b7

Browse files
committed
debugui: implement (*Context).SetScale and (*Context).Scale
Closes #5
1 parent 9ccbd47 commit 573f4b7

File tree

8 files changed

+125
-27
lines changed

8 files changed

+125
-27
lines changed

control.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -390,3 +390,20 @@ func (c *Context) pushContainerBodyLayout(cnt *container, body image.Rectangle,
390390
c.pushLayout(body.Inset(c.style.padding), cnt.layout.ScrollOffset)
391391
cnt.layout.BodyBounds = body
392392
}
393+
394+
// SetScale sets the scale of the UI.
395+
//
396+
// The scale affects the rendering result of the UI.
397+
//
398+
// The default scale is 1.
399+
func (c *Context) SetScale(scale int) {
400+
if scale < 1 {
401+
panic("debugui: scale must be >= 1")
402+
}
403+
c.scale = scale
404+
}
405+
406+
// Scale returns the scale of the UI.
407+
func (c *Context) Scale() int {
408+
return c.scale
409+
}

debugui.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ type DebugUI struct {
1212
func New() *DebugUI {
1313
return &DebugUI{
1414
ctx: &Context{
15+
scale: 1,
1516
style: &defaultStyle,
1617
},
1718
}

draw.go

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -94,16 +94,17 @@ func (c *Context) draw(screen *ebiten.Image) {
9494
case commandRect:
9595
vector.DrawFilledRect(
9696
target,
97-
float32(cmd.rect.rect.Min.X),
98-
float32(cmd.rect.rect.Min.Y),
99-
float32(cmd.rect.rect.Dx()),
100-
float32(cmd.rect.rect.Dy()),
97+
float32(cmd.rect.rect.Min.X*c.scale),
98+
float32(cmd.rect.rect.Min.Y*c.scale),
99+
float32(cmd.rect.rect.Dx()*c.scale),
100+
float32(cmd.rect.rect.Dy()*c.scale),
101101
cmd.rect.color,
102102
false,
103103
)
104104
case commandText:
105105
op := &text.DrawOptions{}
106106
op.GeoM.Translate(float64(cmd.text.pos.X), float64(cmd.text.pos.Y))
107+
op.GeoM.Scale(float64(c.scale), float64(c.scale))
107108
op.ColorScale.ScaleWithColor(cmd.text.color)
108109
text.Draw(target, cmd.text.str, fontFace, op)
109110
case commandIcon:
@@ -115,12 +116,18 @@ func (c *Context) draw(screen *ebiten.Image) {
115116
x := cmd.icon.rect.Min.X + (cmd.icon.rect.Dx()-img.Bounds().Dx())/2
116117
y := cmd.icon.rect.Min.Y + (cmd.icon.rect.Dy()-img.Bounds().Dy())/2
117118
op.GeoM.Translate(float64(x), float64(y))
119+
op.GeoM.Scale(float64(c.scale), float64(c.scale))
118120
op.ColorScale.ScaleWithColor(cmd.icon.color)
119121
target.DrawImage(img, op)
120122
case commandDraw:
121123
cmd.draw.f(target)
122124
case commandClip:
123-
target = screen.SubImage(cmd.clip.rect).(*ebiten.Image)
125+
r := cmd.clip.rect
126+
r.Min.X *= c.scale
127+
r.Min.Y *= c.scale
128+
r.Max.X *= c.scale
129+
r.Max.Y *= c.scale
130+
target = screen.SubImage(r).(*ebiten.Image)
124131
}
125132
}
126133
}

example/gophers.jpg

16.3 KB
Loading

example/main.go

Lines changed: 74 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,31 @@
44
package main
55

66
import (
7-
"log"
7+
"bytes"
8+
_ "embed"
9+
"fmt"
10+
"image"
11+
"image/color"
12+
_ "image/jpeg"
13+
"math/rand/v2"
14+
"os"
815

916
"github.com/hajimehoshi/ebiten/v2"
1017

1118
"github.com/ebitengine/debugui"
1219
)
1320

21+
//go:embed gophers.jpg
22+
var gophersJPG []byte
23+
1424
type Game struct {
25+
gopherImage *ebiten.Image
26+
x int
27+
y int
28+
vx int
29+
vy int
30+
hiRes bool
31+
1532
debugUI *debugui.DebugUI
1633

1734
logBuf string
@@ -23,15 +40,44 @@ type Game struct {
2340
num2 float64
2441
}
2542

26-
func New() *Game {
27-
return &Game{
28-
debugUI: debugui.New(),
29-
bg: [3]float64{90, 95, 100},
30-
checks: [3]bool{true, false, true},
43+
func NewGame() (*Game, error) {
44+
img, _, err := image.Decode(bytes.NewReader(gophersJPG))
45+
if err != nil {
46+
return nil, err
47+
}
48+
49+
g := &Game{
50+
gopherImage: ebiten.NewImageFromImage(img),
51+
vx: 2,
52+
vy: 2,
53+
debugUI: debugui.New(),
54+
bg: [3]float64{90, 95, 100},
55+
checks: [3]bool{true, false, true},
3156
}
57+
g.resetPosition()
58+
59+
return g, nil
60+
}
61+
62+
func (g *Game) resetPosition() {
63+
sW, sH := g.screenSize()
64+
imgW, imgH := g.gopherImage.Bounds().Dx(), g.gopherImage.Bounds().Dy()
65+
g.x = rand.IntN(sW - imgW)
66+
g.y = rand.IntN(sH - imgH)
3267
}
3368

3469
func (g *Game) Update() error {
70+
sW, sH := g.screenSize()
71+
imgW, imgH := g.gopherImage.Bounds().Dx(), g.gopherImage.Bounds().Dy()
72+
g.x += g.vx
73+
g.y += g.vy
74+
if g.x < 0 || sW-imgW <= g.x {
75+
g.vx *= -1
76+
}
77+
if g.y < 0 || sH-imgH <= g.y {
78+
g.vy *= -1
79+
}
80+
3581
if ebiten.IsKeyPressed(ebiten.KeyEscape) {
3682
return ebiten.Termination
3783
}
@@ -44,17 +90,36 @@ func (g *Game) Update() error {
4490
}
4591

4692
func (g *Game) Draw(screen *ebiten.Image) {
93+
screen.Fill(color.RGBA{0x40, 0x40, 0x80, 0xff})
94+
op := &ebiten.DrawImageOptions{}
95+
op.GeoM.Translate(float64(g.x), float64(g.y))
96+
screen.DrawImage(g.gopherImage, op)
97+
4798
g.debugUI.Draw(screen)
4899
}
49100

50101
func (g *Game) Layout(outsideWidth, outsideHeight int) (int, int) {
51-
return 1280, 960
102+
return g.screenSize()
103+
}
104+
105+
func (g *Game) screenSize() (int, int) {
106+
scale := 1
107+
if g.hiRes {
108+
scale = 2
109+
}
110+
return 1280 * scale, 960 * scale
52111
}
53112

54113
func main() {
55114
ebiten.SetWindowTitle("Ebitengine DebugUI Demo")
56115
ebiten.SetWindowSize(1280, 960)
57-
if err := ebiten.RunGame(New()); err != nil {
58-
log.Fatal("err: ", err)
116+
g, err := NewGame()
117+
if err != nil {
118+
fmt.Fprintln(os.Stderr, err)
119+
os.Exit(1)
120+
}
121+
if err := ebiten.RunGame(g); err != nil {
122+
fmt.Fprintln(os.Stderr, err)
123+
os.Exit(1)
59124
}
60125
}

example/ui.go

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,16 @@ func (g *Game) testWindow(ctx *debugui.Context) {
3232
ctx.Text("Size:")
3333
ctx.Text(fmt.Sprintf("%d, %d", layout.Bounds.Dx(), layout.Bounds.Dy()))
3434
})
35+
ctx.Header("Game Config", true, func() {
36+
if ctx.Checkbox("Hi-Res", &g.hiRes) {
37+
if g.hiRes {
38+
ctx.SetScale(2)
39+
} else {
40+
ctx.SetScale(1)
41+
}
42+
g.resetPosition()
43+
}
44+
})
3545
ctx.Header("Test Buttons", true, func() {
3646
ctx.SetGridLayout([]int{100, -1, -1}, nil)
3747
ctx.Text("Test buttons 1:")
@@ -112,17 +122,19 @@ func (g *Game) testWindow(ctx *debugui.Context) {
112122
})
113123
ctx.Control("", func(bounds image.Rectangle) bool {
114124
ctx.DrawControl(func(screen *ebiten.Image) {
125+
scale := ctx.Scale()
115126
vector.DrawFilledRect(
116127
screen,
117-
float32(bounds.Min.X),
118-
float32(bounds.Min.Y),
119-
float32(bounds.Dx()),
120-
float32(bounds.Dy()),
128+
float32(bounds.Min.X*scale),
129+
float32(bounds.Min.Y*scale),
130+
float32(bounds.Dx()*scale),
131+
float32(bounds.Dy()*scale),
121132
color.RGBA{byte(g.bg[0]), byte(g.bg[1]), byte(g.bg[2]), 255},
122133
false)
123134
txt := fmt.Sprintf("#%02X%02X%02X", int(g.bg[0]), int(g.bg[1]), int(g.bg[2]))
124135
op := &text.DrawOptions{}
125136
op.GeoM.Translate(float64((bounds.Min.X+bounds.Max.X)/2), float64((bounds.Min.Y+bounds.Max.Y)/2))
137+
op.GeoM.Scale(float64(scale), float64(scale))
126138
op.PrimaryAlign = text.AlignCenter
127139
op.SecondaryAlign = text.AlignCenter
128140
debugui.DrawText(screen, txt, op)

helpers.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,10 @@ func (c *Context) mouseDelta() image.Point {
119119
}
120120

121121
func (c *Context) cursorPosition() image.Point {
122-
return image.Pt(ebiten.CursorPosition())
122+
p := image.Pt(ebiten.CursorPosition())
123+
p.X /= c.scale
124+
p.Y /= c.scale
125+
return p
123126
}
124127

125128
func (c *Context) end() {

type.go

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,7 @@ type ContainerLayout struct {
3737
}
3838

3939
type Context struct {
40-
// core state
41-
40+
scale int
4241
style *style
4342
hover controlID
4443
focus controlID
@@ -52,21 +51,15 @@ type Context struct {
5251
numberEditBuf string
5352
numberEdit controlID
5453

55-
// stacks
56-
5754
commandList []*command
5855
rootList []*container
5956
containerStack []*container
6057
clipStack []image.Rectangle
6158
layoutStack []layout
6259

63-
// retained state pools
64-
6560
idToContainer map[controlID]*container
6661
toggledIDs map[controlID]struct{}
6762

68-
// input state
69-
7063
lastMousePos image.Point
7164

7265
textInputTextFields map[controlID]*textinput.Field

0 commit comments

Comments
 (0)