Refactor widget initialization and enhance container API. Updated WidgetApp.Init to use a chained API for widget creation. Renamed Fill to Filler and adjusted related functions for improved clarity and flexibility. Introduced Row and Column functions for easier container creation with default constraints. Enhanced AddChild methods for chaining. Updated documentation for clarity.

This commit is contained in:
2025-10-26 20:54:22 +00:00
parent 73e6a8bd99
commit acdd7f7166
3 changed files with 145 additions and 115 deletions

View File

@@ -13,84 +13,32 @@ type WidgetApp struct {
rootWidget *widget.RootWidget
}
// Init initializes the widget tree
// Init initializes the widget tree using the chained API with inline creation
func (app *WidgetApp) Init() (err error) {
// Create four fill widgets with different colors
redFill := widget.NewFlexFill(
1.0, 0.0, 0.0, 1.0, // Red color (RGBA)
0, 0, // Min width/height (flexible)
1e9, 1e9, // Max width/height (very large)
app.rootWidget = widget.Root(
widget.Overlay().
Child(
widget.Column().
Flex(
widget.Row().
Flex(widget.Fill(1.0, 0.0, 0.0, 1.0), 1.0).
Flex(widget.Fill(1.0, 1.0, 0.0, 1.0), 1.0),
1.0,
).
Flex(
widget.Row().
Flex(widget.Fill(0.0, 1.0, 0.0, 1.0), 1.0).
Flex(widget.Fill(0.0, 0.0, 1.0, 1.0), 1.0),
1.0,
),
).
Child(
widget.Center(
widget.Fill(1.0, 1.0, 1.0, 0.75, widget.NewRigidConstraints(64, 64)),
),
),
)
yellowFill := widget.NewFlexFill(
1.0, 1.0, 0.0, 1.0, // Yellow color (RGBA)
0, 0, // Min width/height (flexible)
1e9, 1e9, // Max width/height (very large)
)
greenFill := widget.NewFlexFill(
0.0, 1.0, 0.0, 1.0, // Green color (RGBA)
0, 0, // Min width/height (flexible)
1e9, 1e9, // Max width/height (very large)
)
blueFill := widget.NewFlexFill(
0.0, 0.0, 1.0, 1.0, // Blue color (RGBA)
0, 0, // Min width/height (flexible)
1e9, 1e9, // Max width/height (very large)
)
// Create first row container (red and yellow)
topRow := widget.NewContainer(
widget.DirectionRow,
widget.NewFlexConstraints(0, 0, 1e9, 1e9), // Flexible constraints
)
topRow.AddChild(widget.NewFlexChild(redFill, 1.0)) // Equal weight
topRow.AddChild(widget.NewFlexChild(yellowFill, 1.0)) // Equal weight
// Create second row container (green and blue)
bottomRow := widget.NewContainer(
widget.DirectionRow,
widget.NewFlexConstraints(0, 0, 1e9, 1e9), // Flexible constraints
)
bottomRow.AddChild(widget.NewFlexChild(greenFill, 1.0)) // Equal weight
bottomRow.AddChild(widget.NewFlexChild(blueFill, 1.0)) // Equal weight
// Create main column container
mainColumn := widget.NewContainer(
widget.DirectionColumn,
widget.NewFlexConstraints(0, 0, 1e9, 1e9), // Flexible constraints
)
mainColumn.AddChild(widget.NewFlexChild(topRow, 1.0)) // Equal weight
mainColumn.AddChild(widget.NewFlexChild(bottomRow, 1.0)) // Equal weight
// Create a white box with fixed 64x64 size (no position needed)
// Using 0.5 alpha to test alpha blending
whiteBox := widget.NewRigidFill(
1.0, 1.0, 1.0, 0.75, // White with 0.75 alpha
64, 64, // Fixed 64x64 size
)
// Wrap the white box in a DirectionWidget with center gravity
centeredWhiteBox := widget.NewDirectionWidget(
whiteBox,
widget.GravityCenter,
widget.NewFlexConstraints(0, 0, 1e9, 1e9), // Flexible constraints to fill available space
)
// Create overlay widget to demonstrate overpainting
overlay := widget.NewOverlayWidget(
widget.NewFlexConstraints(0, 0, 1e9, 1e9), // Flexible constraints
)
// Add the flex layout first (background)
overlay.AddChild(mainColumn)
// Add the centered white box second (foreground - will paint over the flex layout)
overlay.AddChild(centeredWhiteBox)
// Create root widget with the overlay as child
app.rootWidget = widget.NewRootWidget(overlay)
return
}

View File

@@ -4,64 +4,64 @@ import (
"github.com/go-gl/gl/all-core/gl"
)
// Fill is a widget that fills its box with a solid color
type Fill struct {
// Filler is a widget that fills its box with a solid color
type Filler struct {
color [4]float32
constraints Constraints
}
// NewFill creates a new Fill widget with the specified color and constraints
func NewFill(red, green, blue, alpha float32, constraints Constraints) *Fill {
return &Fill{
color: [4]float32{red, green, blue, alpha},
constraints: constraints,
// Fill creates a new Fill widget that automatically fills its parent container.
// If no constraints are provided, uses default flexible constraints to fill the parent.
func Fill(red, green, blue, alpha float32, constraints ...Constraints) *Filler {
var c Constraints
if len(constraints) > 0 {
c = constraints[0]
} else {
// Default to filling parent container
c = NewFlexConstraints(0, 0, 1e9, 1e9)
}
}
// NewRigidFill creates a rigid Fill widget with fixed dimensions
func NewRigidFill(red, green, blue, alpha, width, height float32) *Fill {
return &Fill{
return &Filler{
color: [4]float32{red, green, blue, alpha},
constraints: NewRigidConstraints(width, height),
constraints: c,
}
}
// NewFlexFill creates a flexible Fill widget with min/max constraints
func NewFlexFill(red, green, blue, alpha, minWidth, minHeight, maxWidth, maxHeight float32) *Fill {
return &Fill{
func NewFlexFill(red, green, blue, alpha, minWidth, minHeight, maxWidth, maxHeight float32) *Filler {
return &Filler{
color: [4]float32{red, green, blue, alpha},
constraints: NewFlexConstraints(minWidth, minHeight, maxWidth, maxHeight),
}
}
// NewFlexFillAt creates a flexible Fill widget at a specific position
func NewFlexFillAt(red, green, blue, alpha, minWidth, minHeight, maxWidth, maxHeight, top, left float32) *Fill {
return &Fill{
func NewFlexFillAt(red, green, blue, alpha, minWidth, minHeight, maxWidth, maxHeight, top, left float32) *Filler {
return &Filler{
color: [4]float32{red, green, blue, alpha},
constraints: NewFlexConstraintsAt(minWidth, minHeight, maxWidth, maxHeight, top, left),
}
}
// NewRigidFillAt creates a rigid Fill widget at a specific position
func NewRigidFillAt(red, green, blue, alpha, width, height, top, left float32) *Fill {
return &Fill{
func NewRigidFillAt(red, green, blue, alpha, width, height, top, left float32) *Filler {
return &Filler{
color: [4]float32{red, green, blue, alpha},
constraints: NewRigidConstraintsAt(width, height, top, left),
}
}
// SetColor updates the fill color
func (f *Fill) SetColor(red, green, blue, alpha float32) {
func (f *Filler) SetColor(red, green, blue, alpha float32) {
f.color = [4]float32{red, green, blue, alpha}
}
// GetConstraints returns the size constraints for this Fill widget
func (f *Fill) GetConstraints() Constraints {
func (f *Filler) GetConstraints() Constraints {
return f.constraints
}
// Render implements the Widget interface for Fill
func (f *Fill) Render(ctx *Context, box *Box) (usedSize Size, err error) {
func (f *Filler) Render(ctx *Context, box *Box) (usedSize Size, err error) {
// Set scissor test to clip to the box
// Convert from GL coordinates (bottom-left origin) to screen coordinates (top-left origin)
// Window height is ctx.WindowHeight, box Y is from top

View File

@@ -144,18 +144,78 @@ type Container struct {
constraints Constraints
}
// NewContainer creates a new container with the specified direction
func NewContainer(direction Direction, constraints Constraints) *Container {
// Row creates a new row container with default flexible constraints.
// Chain methods like Flex() or Rigid() to add children.
func Row(constraints ...Constraints) *Container {
var c Constraints
if len(constraints) > 0 {
c = constraints[0]
} else {
c = NewFlexConstraints(0, 0, 1e9, 1e9)
}
return &Container{
Direction: direction,
Direction: DirectionRow,
Children: make([]FlexChild, 0),
constraints: constraints,
constraints: c,
}
}
// AddChild adds a child widget to the container
func (c *Container) AddChild(child FlexChild) {
// Column creates a new column container with default flexible constraints.
// Chain methods like Flex() or Rigid() to add children.
func Column(constraints ...Constraints) *Container {
var c Constraints
if len(constraints) > 0 {
c = constraints[0]
} else {
c = NewFlexConstraints(0, 0, 1e9, 1e9)
}
return &Container{
Direction: DirectionColumn,
Children: make([]FlexChild, 0),
constraints: c,
}
}
// NewContainer creates a new container with the specified direction.
// If no constraints are provided, uses default flexible constraints (0, 0, 1e9, 1e9).
func NewContainer(direction Direction, constraints ...Constraints) *Container {
var c Constraints
if len(constraints) > 0 {
c = constraints[0]
} else {
c = NewFlexConstraints(0, 0, 1e9, 1e9)
}
return &Container{
Direction: direction,
Children: make([]FlexChild, 0),
constraints: c,
}
}
// AddChild adds a child widget to the container and returns the container for chaining
func (c *Container) AddChild(child FlexChild) *Container {
c.Children = append(c.Children, child)
return c
}
// Flex adds a flexible child with the specified weight to the container
func (c *Container) Flex(child Widget, weight float32) *Container {
c.Children = append(c.Children, FlexChild{
Widget: child,
Type: FlexTypeFlex,
Weight: weight,
})
return c
}
// Rigid adds a rigid child to the container
func (c *Container) Rigid(child Widget) *Container {
c.Children = append(c.Children, FlexChild{
Widget: child,
Type: FlexTypeRigid,
Weight: 0,
})
return c
}
// GetConstraints returns the container's constraints
@@ -378,17 +438,18 @@ type RootWidget struct {
clearColor [4]float32
}
// NewRootWidget creates a new root widget with the given child
func NewRootWidget(child Widget) *RootWidget {
// Root creates a new root widget with the given child
func Root(child Widget) *RootWidget {
return &RootWidget{
child: child,
clearColor: [4]float32{0.0, 0.0, 0.0, 1.0}, // Default black
}
}
// SetClearColor sets the background clear color for the root widget
func (r *RootWidget) SetClearColor(red, green, blue, alpha float32) {
// SetClearColor sets the background clear color for the root widget and returns the root for chaining
func (r *RootWidget) SetClearColor(red, green, blue, alpha float32) *RootWidget {
r.clearColor = [4]float32{red, green, blue, alpha}
return r
}
// GetConstraints returns unconstrained size (fills canvas)
@@ -459,17 +520,25 @@ type OverlayWidget struct {
constraints Constraints
}
// NewOverlayWidget creates a new overlay widget that renders children in sequence
func NewOverlayWidget(constraints Constraints) *OverlayWidget {
// Overlay creates a new overlay widget that renders children in sequence.
// If no constraints are provided, uses default flexible constraints (0, 0, 1e9, 1e9).
func Overlay(constraints ...Constraints) *OverlayWidget {
var c Constraints
if len(constraints) > 0 {
c = constraints[0]
} else {
c = NewFlexConstraints(0, 0, 1e9, 1e9)
}
return &OverlayWidget{
children: make([]Widget, 0),
constraints: constraints,
constraints: c,
}
}
// AddChild adds a child widget to be rendered on top of previous children
func (o *OverlayWidget) AddChild(child Widget) {
// Child adds a child widget to be rendered on top of previous children and returns the overlay for chaining
func (o *OverlayWidget) Child(child Widget) *OverlayWidget {
o.children = append(o.children, child)
return o
}
// GetConstraints returns the overlay's constraints
@@ -574,15 +643,28 @@ type DirectionWidget struct {
constraints Constraints
}
// NewDirectionWidget creates a new direction widget with the specified gravity
func NewDirectionWidget(child Widget, gravity Gravity, constraints Constraints) *DirectionWidget {
// NewDirectionWidget creates a new direction widget with the specified gravity.
// If no constraints are provided, uses default flexible constraints (0, 0, 1e9, 1e9).
func NewDirectionWidget(child Widget, gravity Gravity, constraints ...Constraints) *DirectionWidget {
var c Constraints
if len(constraints) > 0 {
c = constraints[0]
} else {
c = NewFlexConstraints(0, 0, 1e9, 1e9)
}
return &DirectionWidget{
child: child,
gravity: gravity,
constraints: constraints,
constraints: c,
}
}
// Center creates a direction widget that centers its child.
// Equivalent to NewDirectionWidget(child, GravityCenter).
func Center(child Widget, constraints ...Constraints) *DirectionWidget {
return NewDirectionWidget(child, GravityCenter, constraints...)
}
// GetConstraints returns the direction widget's constraints
func (d *DirectionWidget) GetConstraints() Constraints {
return d.constraints