Hi, I'm not sure if this is my misunderstanding (probably!) or a layout bug.
I'm trying to put some content in the top left and bottom left of an anchor layout container (red) inside a FlipBook (blue).
But what I get is...
...or, if I swap the order of the two children of gameplayPage
(red) I get...
...but what I'm expecting is that both cyan and yellow boxes be within the red box. Nothing is expected to be in the blue area.
It feels like the first child of gameplayPage
is affecting the layout of the second child somehow?
I apologise if I've totally misunderstood how layouts or children are supposed to work, or if I've missed some config from the demo code.
The simplified repro code (based on cmd/scaffold
) is...
package main
import (
"image/color"
_ "image/png"
"io/ioutil"
"log"
"github.com/blizzy78/ebitenui"
"github.com/blizzy78/ebitenui/image"
"github.com/blizzy78/ebitenui/widget"
"github.com/golang/freetype/truetype"
"github.com/hajimehoshi/ebiten/v2"
"golang.org/x/image/font"
)
type game struct {
ui *ebitenui.UI
}
func main() {
// load button text font
face, err := loadFont("fonts/NotoSans-Regular.ttf", 20)
if err != nil {
log.Println(err)
return
}
defer face.Close()
// construct a new container that serves as the root of the UI hierarchy
rootContainer := widget.NewContainer(
// the container will use a plain color as its background
widget.ContainerOpts.BackgroundImage(image.NewNineSliceColor(color.RGBA{0x13, 0x1a, 0x22, 0xff})),
// the container will use an anchor layout to layout its single child widget
widget.ContainerOpts.Layout(widget.NewAnchorLayout()),
)
flipBook := widget.NewFlipBook(
widget.FlipBookOpts.Padding(widget.Insets{
Top: 50,
Left: 50,
Right: 50,
Bottom: 50,
}),
widget.FlipBookOpts.ContainerOpts(
widget.ContainerOpts.BackgroundImage(image.NewNineSliceColor(color.RGBA{0x00, 0x00, 0xff, 0xff})),
// get the flipbook to fill the page
widget.ContainerOpts.WidgetOpts(
widget.WidgetOpts.LayoutData(
widget.AnchorLayoutData{
StretchHorizontal: true,
StretchVertical: true,
},
),
),
),
)
playerStatsText := widget.NewText(widget.TextOpts.Text("PLAYER STATS", face, color.Black))
playerStatsPanel := widget.NewContainer(
widget.ContainerOpts.BackgroundImage(image.NewNineSliceColor(color.RGBA{0xff, 0xff, 0x00, 0xff})),
widget.ContainerOpts.Layout(widget.NewAnchorLayout()),
widget.ContainerOpts.WidgetOpts(
widget.WidgetOpts.LayoutData(
widget.AnchorLayoutData{
HorizontalPosition: widget.AnchorLayoutPositionStart,
VerticalPosition: widget.AnchorLayoutPositionStart,
},
),
),
)
nofityText := widget.NewText(widget.TextOpts.Text("NOTIFY", face, color.Black))
notifyPanel := widget.NewContainer(
widget.ContainerOpts.BackgroundImage(image.NewNineSliceColor(color.RGBA{0x00, 0xff, 0xff, 0xff})),
widget.ContainerOpts.Layout(widget.NewAnchorLayout()),
widget.ContainerOpts.WidgetOpts(
widget.WidgetOpts.LayoutData(
widget.AnchorLayoutData{
HorizontalPosition: widget.AnchorLayoutPositionStart,
VerticalPosition: widget.AnchorLayoutPositionEnd,
},
),
),
)
gameplayPage := widget.NewContainer(
widget.ContainerOpts.BackgroundImage(image.NewNineSliceColor(color.RGBA{0xff, 0x00, 0x00, 0xff})),
widget.ContainerOpts.Layout(widget.NewAnchorLayout()),
// this is in an implicit AnchorLayout from FlipBook
widget.ContainerOpts.WidgetOpts(
widget.WidgetOpts.LayoutData(
widget.AnchorLayoutData{
StretchHorizontal: true,
StretchVertical: true,
},
),
),
)
playerStatsPanel.AddChild(playerStatsText)
notifyPanel.AddChild(nofityText)
// NOTE: ****** swap the below two lines order to see a difference in layout, but neither as expected ******
gameplayPage.AddChild(playerStatsPanel)
gameplayPage.AddChild(notifyPanel)
flipBook.SetPage(gameplayPage)
// add the button as a child of the container
rootContainer.AddChild(flipBook)
// construct the UI
ui := ebitenui.UI{
Container: rootContainer,
}
// Ebiten setup
ebiten.SetWindowSize(400, 400)
ebiten.SetWindowTitle("Ebiten UI Scaffold")
game := game{
ui: &ui,
}
// run Ebiten main loop
if err := ebiten.RunGame(&game); err != nil {
log.Println(err)
}
}
// Update implements Game.
func (g *game) Layout(outsideWidth int, outsideHeight int) (int, int) {
return outsideWidth, outsideHeight
}
// Update implements Game.
func (g *game) Update() error {
// update the UI
g.ui.Update()
return nil
}
// Draw implements Ebiten's Draw method.
func (g *game) Draw(screen *ebiten.Image) {
// draw the UI onto the screen
g.ui.Draw(screen)
}
func loadFont(path string, size float64) (font.Face, error) {
fontData, err := ioutil.ReadFile(path)
if err != nil {
return nil, err
}
ttfFont, err := truetype.Parse(fontData)
if err != nil {
return nil, err
}
return truetype.NewFace(ttfFont, &truetype.Options{
Size: size,
DPI: 72,
Hinting: font.HintingFull,
}), nil
}
question