EBUI is a UI framework for Ebitengine, providing a set of components and layouts for building game interfaces and tools.
- Component-Based Architecture: Build UIs using reusable, composable components
- Flexible Layout System: Arrange components using various layout strategies
- Event System: Handle user interactions with a flexible event system
- Component Library:
- Labels with text alignment options
- Buttons with customizable colors and states
- Text inputs with selection and clipboard support
- Scrollable content containers
- Windows with drag-and-drop functionality
go get github.com/cbodonnell/ebuipackage main
import (
"image/color"
"log"
"github.com/cbodonnell/ebui"
"github.com/hajimehoshi/ebiten/v2"
)
type Game struct {
ui *ebui.Manager
}
func NewGame() *Game {
// Create a root container
root := ebui.NewLayoutContainer(
ebui.WithSize(800, 600),
ebui.WithLayout(ebui.NewVerticalStackLayout(0, ebui.AlignCenter)),
)
// Create a label
label := ebui.NewLabel(
"Welcome to EBUI!",
ebui.WithSize(800, 40),
ebui.WithColor(color.White),
)
// Create a button
button := ebui.NewButton(
ebui.WithSize(120, 40),
ebui.WithLabelText("Click Me"),
ebui.WithClickHandler(func() {
log.Println("Button clicked!")
}),
)
// Create a container to center the button
buttonContainer := ebui.NewLayoutContainer(
ebui.WithSize(800, 40),
ebui.WithLayout(ebui.NewHorizontalStackLayout(0, ebui.AlignCenter)),
)
// Add button to button container
buttonContainer.AddChild(button)
// Add label and button container to root
root.AddChild(label)
root.AddChild(buttonContainer)
return &Game{
// Create a UI manager using the root component
ui: ebui.NewManager(root),
}
}
func (g *Game) Update() error {
return g.ui.Update()
}
func (g *Game) Draw(screen *ebiten.Image) {
g.ui.Draw(screen)
}
func (g *Game) Layout(outsideWidth, outsideHeight int) (screenWidth, screenHeight int) {
return 800, 600
}
func main() {
ebiten.SetWindowSize(800, 600)
ebiten.SetWindowTitle("EBUI Example")
if err := ebiten.RunGame(NewGame()); err != nil {
log.Fatal(err)
}
}More comprehensive examples can be found in the examples directory.
Components are the building blocks of EBUI. Every UI element implements the Component interface:
type Component interface {
Identifiable
EbitenLifecycle
SetPosition(pos Position)
GetPosition() Position
SetSize(size Size)
GetSize() Size
SetParent(parent Container)
GetParent() Container
SetPadding(padding Padding)
GetPadding() Padding
Contains(x, y float64) bool
GetAbsolutePosition() Position
}Containers are components that can hold other components. EBUI provides several types of containers:
- BaseContainer: Basic container with no layout management
- LayoutContainer: Container that arranges children using a layout strategy
- ScrollableContainer: Container with scrolling capability
- ZIndexedContainer: Container that manages component layering
- WindowManager: Special container for managing multiple windows
EBUI provides flexible layout options:
- Vertical Stack Layout: Arrange components vertically
- Horizontal Stack Layout: Arrange components horizontally
- Custom layouts can be implemented by implementing the
Layoutinterface
The event system supports:
- Mouse events (click, hover, drag)
- Keyboard input
- Focus management
- Event bubbling and capturing
label := ebui.NewLabel(
"Hello World",
ebui.WithSize(200, 40),
ebui.WithJustify(ebui.JustifyCenter),
ebui.WithColor(color.Black),
ebui.WithFont(basicfont.Face7x13), // Default font
)button := ebui.NewButton(
ebui.WithSize(120, 40),
ebui.WithLabelText("Click Me"),
ebui.WithButtonColors(ebui.ButtonColors{
Default: color.RGBA{200, 200, 200, 255},
Hovered: color.RGBA{220, 220, 220, 255},
Pressed: color.RGBA{170, 170, 170, 255},
}),
)input := ebui.NewTextInput(
ebui.WithSize(200, 40),
ebui.WithInitialText("Hello"),
ebui.WithOnChange(func(text string) {
println("Text changed:", text)
}),
)scrollable := ebui.NewScrollableContainer(
ebui.WithSize(300, 400),
ebui.WithLayout(ebui.NewVerticalStackLayout(10, ebui.AlignStart)),
)windowManager := ebui.NewWindowManager(
ebui.WithSize(800, 600),
)
window := windowManager.CreateWindow(400, 300,
ebui.WithWindowTitle("My Window"),
ebui.WithWindowColors(ebui.WindowColors{
Background: color.RGBA{240, 240, 240, 255},
Header: color.RGBA{200, 200, 200, 255},
Border: color.RGBA{0, 0, 0, 255},
}),
)Arrows move focus spatially, Tab cycles windows (or controls in a single scope), Enter activates and Escape closes the focused window. To route keys yourself, pass WithNavInput(nil) and call Manager.Navigate, which reports whether the UI handled the action.
Components draw their chrome (window frames, headers and titles, buttons and their labels, focus rings, tooltips, slider and scroll parts, text input wells and carets) through DefaultPainter. Each part arrives as a Paint: the Part, the component's role (WithRole, WithWindowRole), its State (hovered, pressed, focused, disabled), its rectangle, its flat colors and any text. Paint reports whether it drew the part; a part it declines, or every part when DefaultPainter is nil, is drawn flat in the color sets above. A painter that draws PartWindowTitle or PartButtonLabel replaces the component's own label.
type painter struct{}
func (painter) Paint(dst *ebiten.Image, p ebui.Paint) bool {
if p.Part != ebui.PartButton || p.Role != "primary" {
return false
}
// draw a primary button's face in p.Rect for p.State
return true
}
ebui.DefaultPainter = painter{}EBUI includes a debug mode that visualizes component bounds and layout information. Set the global Debug variable to true to enable debug mode:
ebui.Debug = trueContributions are welcome! Please feel free to open issues or submit pull requests.
This project is licensed under the MIT License - see the LICENSE file for details.