furex

package module
v2.1.9 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 26, 2022 License: BSD-3-Clause Imports: 8 Imported by: 11

README

Furex

Furex is a minimal GUI framework for Ebitengine that supports a subset of Flex Layout Algorithm.

For now, Furex is not a component library but a framework for positioning and stacking virtual components, handling button and touch events. How they are rendered is completely up to the user.

GoDoc

Motivation

Flexbox is a good mechanism for laying out items of different sizes. I wanted to use the same concept for game UI because I have experience in Web and ReactNative projects. I hope the library helps other people with the same thoughts.

Features

Feature How to use Example
Flexbox layout The layout can be adjusted by settings the properties of a View. You can think of a View as a div in HTML. Views can be tiled or nested. Example
Custom UI It supports any type of UI component. To create one, you can create a handler implements DrawHandler or UpdateHandler interface. Each View can have one handler. Example
Buttons To create a button, you can implement ButtonHandler. It supports both touch and mouse. Example
Touch events To handle touch events and positions, you can implement TouchHandler.
Mouse click events To handle mouse click events, you can implement MouseLeftButtonHandler.
Mouse move events To detect mouse positions, you can implement MouseHandler.
Swipe gestures It supports swipe gestures in four directions. To handle swipe events, you can implement SwipeHandler.
Margins A View can have margins by setting MarginLeft, MarginTop, MarginRight, MarginBottom.
Absolute Positions A View position can be fixed by setting PositionAbsolute to the Position field, Left, and Top positions.

Install

go get github.com/yohamta/furex/v2

Examples

To check all examples, visit here.

Simple example

Full source code

import "github.com/yohamta/furex/v2"

type Game struct {
  init   bool
  screen screen
  gameUI *furex.View
}

func (g *Game) Update() error {
  if !g.init {
    g.init = true
    g.setupUI()
  }
  g.gameUI.UpdateWithSize(ebiten.WindowSize())
  // g.gameUI.Update() // Update() is an alternate method for updating the UI and handling events.
  return nil
}

func (g *Game) setupUI() {
  // create a root view
  g.gameUI = &furex.View{
    Width:        g.screen.Width,
    Height:       g.screen.Height,
    Direction:    furex.Row,
    Justify:      furex.JustifyCenter,
    AlignItems:   furex.AlignItemCenter,
    AlignContent: furex.AlignContentCenter,
    Wrap:         furex.Wrap,
  }

  // create a child view
  for i := 0; i < 20; i++ {
    g.gameUI.AddChild(&furex.View{
      Width:  100,
      Height: 100,
      Handler: &components.Box{
        Color: colors[i%len(colors)],
      },
    })
  }
}

func (g *Game) Draw(screen *ebiten.Image) {
  // Draw the UI tree
  g.gameUI.Draw(screen)
}

var colors = []color.Color{
  color.RGBA{0xaa, 0, 0, 0xff},
  color.RGBA{0, 0xaa, 0, 0xff},
  color.RGBA{0, 0, 0xaa, 0xff},
}
Method chaining

View's AddChild() method returns itself, so it can be chained.

Full source code of the example

func (g *Game) setupUI() {
	newButton := func() *furex.View {
		return (&furex.View{
			Width:        100,
			Height:       100,
			MarginTop:    5,
			MarginBottom: 10,
			MarginLeft:   5,
			MarginRight:  5,
			Handler: &components.Button{
				Text:    "Button",
				OnClick: func() { println("button clicked") },
			},
		})
	}

	g.gameUI = (&furex.View{
		Width:      g.screen.Width,
		Height:     g.screen.Height,
		Direction:  furex.Column,
		Justify:    furex.JustifySpaceBetween,
		AlignItems: furex.AlignItemCenter,
	}).AddChild(
		(&furex.View{
			Width:      g.screen.Width - 20,
			Height:     70,
			Justify:    furex.JustifySpaceBetween,
			AlignItems: furex.AlignItemCenter,
		}).AddChild(
			&furex.View{
				Width:   100,
				Height:  100,
				Handler: &components.Box{Color: color.RGBA{0xff, 0, 0, 0xff}},
			},
			&furex.View{
				Width:   200,
				Height:  60,
				Handler: &components.Box{Color: color.RGBA{0xff, 0xff, 0xff, 0xff}},
			},
			&furex.View{
				Width:   100,
				Height:  100,
				Handler: &components.Box{Color: color.RGBA{0, 0xff, 0, 0xff}},
			},
		),
	).AddChild(&furex.View{
		Width:  200,
		Height: 50,
		Handler: &components.Button{
			Text:    "Button",
			OnClick: func() { println("button clicked") },
		},
	}).AddChild((&furex.View{
		Width:      g.screen.Width,
		Height:     140,
		Justify:    furex.JustifyCenter,
		AlignItems: furex.AlignItemEnd,
	}).AddChild(
		newButton(),
		newButton(),
		newButton(),
		newButton(),
	))
}

Debug

You can turn on the Debug Mode by setting the variable below.

furex.Debug = true

How to contribute?

Feel free to contribute in any way you want. Share ideas, submit issues, create pull requests, adding examples, or adding components. Thank you!

Documentation

Overview

Referenced code: https://github.com/golang/exp/blob/master/shiny/widget/flex/flex.go

Index

Constants

This section is empty.

Variables

View Source
var (
	Debug = false
)
View Source
var G graphic

Functions

This section is empty.

Types

type AlignContent

type AlignContent uint8

AlignContent is the 'align-content' property. It aligns container lines when there is extra space on the cross-axis.

const (
	AlignContentStart AlignContent = iota
	AlignContentEnd
	AlignContentCenter
	AlignContentSpaceBetween
	AlignContentSpaceAround
	AlignContentStretch
)

type AlignItem

type AlignItem uint8

AlignItem aligns items along the cross axis.

const (
	AlignItemStretch AlignItem = iota
	AlignItemStart
	AlignItemEnd
	AlignItemCenter
)

type ButtonHandler

type ButtonHandler interface {
	// HandlePress handle the event when user just started pressing the button
	// The parameter (x, y) is the location relative to the window (0,0).
	// touchID is the unique ID of the touch.
	// If the button is pressed by a mouse, touchID is -1.
	HandlePress(x, y int, t ebiten.TouchID)

	// HandleRelease handle the event when user just released the button.
	// The parameter (x, y) is the location relative to the window (0,0).
	// The parameter isCancel is true when the touch/left click is released outside of the button.
	HandleRelease(x, y int, isCancel bool)
}

ButtonHandler represents a button component.

type Direction

type Direction uint8

Direction is the direction in which flex items are laid out

const (
	Row Direction = iota
	Column
)

type DrawHandler

type DrawHandler interface {
	// HandleDraw function draws the content of the component inside the frame.
	// The frame parameter represents the location (x,y) and size (width,height) relative to the window (0,0).
	HandleDraw(screen *ebiten.Image, frame image.Rectangle)
}

DrawHandler represents a component that can be added to a container.

type DrawRectOpts

type DrawRectOpts struct {
	Rect        image.Rectangle
	Color       color.Color
	StrokeWidth int
}

type FillRectOpts

type FillRectOpts struct {
	Rect  image.Rectangle
	Color color.Color
}

type FlexAlign

type FlexAlign int

FlexAlign represents align of flex children

const (
	FlexCenter FlexAlign = iota
	FlexStart
	FlexEnd
	FlexSpaceBetween
)

type FlexWrap

type FlexWrap uint8

FlexWrap controls whether the container is single- or multi-line, and the direction in which the lines are laid out.

const (
	NoWrap FlexWrap = iota
	Wrap
	WrapReverse
)

type Justify

type Justify uint8

Justify aligns items along the main axis.

const (
	JustifyStart        Justify = iota // pack to start of line
	JustifyEnd                         // pack to end of line
	JustifyCenter                      // pack to center of line
	JustifySpaceBetween                // even spacing
	JustifySpaceAround                 // even spacing, half-size on each end
)

type MouseHandler

type MouseHandler interface {
	// HandleMouse handles the mouch move and returns true if it handle the mouse move.
	// The parameter (x, y) is the location relative to the window (0,0).
	HandleMouse(x, y int) bool
}

MouseHandler represents a component that handle mouse move.

type MouseLeftButtonHandler

type MouseLeftButtonHandler interface {
	// HandleJustPressedMouseButtonLeft handle left mouse button click just pressed.
	// The parameter (x, y) is the location relative to the window (0,0).
	// It returns true if it handles the mouse move.
	HandleJustPressedMouseButtonLeft(x, y int) bool
	// HandleJustReleasedTouchID handles the touchID just released.
	// The parameter (x, y) is the location relative to the window (0,0).
	HandleJustReleasedMouseButtonLeft(x, y int)
}

MouseLeftButtonHandler represents a component that handle mouse button left click.

type Position

type Position uint8

Position is the 'position' property

const (
	PositionStatic Position = iota
	PositionAbsolute
)

type SwipeDirection added in v2.1.4

type SwipeDirection int

SwipeHandler represents different swipe directions.

const (
	SwipeDirectionLeft SwipeDirection = iota
	SwipeDirectionRight
	SwipeDirectionUp
	SwipeDirectionDown
)

type SwipeHandler added in v2.1.4

type SwipeHandler interface {
	// HandleSwipe handles swipes.
	HandleSwipe(dir SwipeDirection)
}

SwipeHandler represents a component that handle swipe.

type TouchHandler

type TouchHandler interface {
	// HandleJustPressedTouchID handles the touchID just pressed and returns true if it handles the TouchID
	HandleJustPressedTouchID(touch ebiten.TouchID, x, y int) bool
	// HandleJustReleasedTouchID handles the touchID just released
	// Should be called only when it handled the TouchID when pressed
	HandleJustReleasedTouchID(touch ebiten.TouchID, x, y int)
}

TouchHandler represents a component that handle touches.

type UpdateHandler

type UpdateHandler interface {
	// Updater updates the state of the component by one tick.
	HandleUpdate()
}

UpdateHandler represents a component that updates by one tick.

type View

type View struct {
	Left         int
	Top          int
	Width        int
	Height       int
	MarginLeft   int
	MarginTop    int
	MarginRight  int
	MarginBottom int
	Position     Position
	Handler      DrawHandler
	Direction    Direction
	Wrap         FlexWrap
	Justify      Justify
	AlignItems   AlignItem
	AlignContent AlignContent
	Grow         float64
	Shrink       float64
	// contains filtered or unexported fields
}

View represents a UI element. You can set flex options, size, position and so on. Handlers can be set to create custom component such as button or list.

func (*View) AddChild

func (v *View) AddChild(views ...*View) *View

AddChild adds one or multiple child views

func (*View) AddTo added in v2.1.2

func (v *View) AddTo(parent *View) *View

AddTo add itself to a parent view

func (*View) Draw

func (v *View) Draw(screen *ebiten.Image)

Draw draws the view

func (*View) HandleJustPressedMouseButtonLeft

func (ct *View) HandleJustPressedMouseButtonLeft(x, y int) bool

func (*View) HandleJustPressedTouchID

func (ct *View) HandleJustPressedTouchID(
	touchID ebiten.TouchID, x, y int,
) bool

func (*View) HandleJustReleasedMouseButtonLeft

func (ct *View) HandleJustReleasedMouseButtonLeft(x, y int)

func (*View) HandleJustReleasedTouchID

func (ct *View) HandleJustReleasedTouchID(touchID ebiten.TouchID, x, y int)

func (*View) HandleMouse

func (ct *View) HandleMouse(x, y int) bool

func (*View) PopChild

func (v *View) PopChild() *View

PopChild remove the last child view add to this view

func (*View) RemoveAll added in v2.1.1

func (v *View) RemoveAll()

RemoveAll removes all children view

func (*View) RemoveChild

func (v *View) RemoveChild(cv *View) bool

RemoveChild removes a specified view

func (*View) Update

func (v *View) Update()

Update updates the view

func (*View) UpdateWithSize added in v2.1.6

func (v *View) UpdateWithSize(width, height int)

UpdateWithSize the view with modified height and width

Directories

Path Synopsis
examples

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL