Skip to content

Commit

Permalink
Introduce Function Components (#56)
Browse files Browse the repository at this point in the history
* update right bottom field type

* add register component API

* fix bug

* fix example

* update config struct

* fix bug

* add functional compoonent

* rename global function

* update example

* udpate comments

* add explanation on components
  • Loading branch information
yohamta authored Apr 30, 2023
1 parent 06b95f7 commit fbf79ba
Show file tree
Hide file tree
Showing 8 changed files with 286 additions and 163 deletions.
26 changes: 24 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,12 @@ Full source code of the example is [here](examples/game/main.go).
- [Motivation](#motivation)
- [Features](#features)
- [Getting Started](#getting-started)
- [Usage](#usage)
- [Basic Usage](#basic-usage)
- [Building UI with HTML](#building-ui-with-html)
- [CSS Properties](#css-properties)
- [HTML Attributes](#html-attributes)
- [Component Types](#component-types)
- [Global Components](#global-components)
- [Debugging](#debugging)
- [Contributions](#contributions)

Expand Down Expand Up @@ -53,7 +55,7 @@ To get started with Furex, install Furex using the following command:
go get github.com/yohamta/furex/v2
```

## Usage
## Basic Usage

Here's a simple example of how to use Furex to create an UI in your game:

Expand Down Expand Up @@ -223,6 +225,26 @@ The following table lists the available HTML attributes:
| `id` | string | Any string value |
| `hidden` | bool | `true`, `false` |

### Component Types

There are three types of components you can create in Furex:

- **Handler Instance**: A `furex.Handler` instance, such as `DrawHandler`.
- **Factory Function**: A function that returns a `furex.Handler` instance. This is useful when you want to create separate handler instances for each HTML tag.
- **Function Component**: A function that returns a `*furex.View instance`. This is an alternative way to create components that encapsulate their own behavior and styles.

### Global Components

To register a custom component globally, use the furex.RegisterComponents function. This should be called during the package initialization. In the given example, the following components are registered globally:

```go
func init() {
furex.RegisterComponents(furex.ComponentsMap{
"button": &widgets.Button{},
"sprite": &widgets.Sprite{},
})
}
```
## Debugging

You can enable Debug Mode by setting the variable below.
Expand Down
86 changes: 34 additions & 52 deletions examples/game/assets/html/main.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@

<head>
<style>
game-ui {
.game-ui {
flex-direction: column;
justify-content: space-between;
align-items: stretch;
align-content: stretch;
}

container {
.container {
justify-content: center;
align-items: center;
margin-top: 50px;
Expand All @@ -35,15 +35,15 @@
height: 200px;
}

gauge-container {
.gauge-container {
width: 180px;
height: 38px;
align-items: flex-start;
justify-content: flex-start;
flex-direction: column;
}

gauge-container2 {
.gauge-container2 {
width: 180px;
height: 38px;
align-items: flex-start;
Expand All @@ -52,18 +52,12 @@
margin-top: 30px;
}

gauge-text {
width: 180px;
height: 20px;
margin-bottom: 2px;
}

.gauge {
width: 180px;
height: 18px;
}

buttons {
.buttons {
flex-direction: row;
align-items: center;
justify-content: center;
Expand All @@ -83,17 +77,19 @@
margin-left: 10;
}

bottom-buttons {
.bottom-buttons {
height: 140px;
width: 480px;
justify-content: center;
align-items: flex-end;
margin-bottom: 20px;
}

bottom-button {
width: 45px;
height: 49px;
.gauge-text {
margin-bottom: 2px;
}

.bottom-button {
margin-top: 5px;
margin-bottom: 10px;
margin-left: 20px;
Expand All @@ -114,7 +110,7 @@
top: 17
}

play-game-container {
.play-game-container {
position: absolute;
left: 20;
top: 52;
Expand All @@ -128,72 +124,58 @@
justify-content: center;
}

play-game-text {
width: 100px;
height: 8px;
margin-bottom: 20px;
flex-direction: row;
align-items: center;
justify-content: center;
}

play-game-buttons {
.play-game-buttons {
width: 100;
height: 50;
flex-direction: row;
align-items: center;
justify-content: center;
}

panel-button {
width: 100;
height: 50;
}

</style>
</head>

<body>
<game-ui>
<container>
<div class="game-ui">
<div class="container">
<panel class="panel-outer" sprite="panel_brown.png">
<panel class="panel-inner" sprite="panelInset_beige.png">
<gauge-container>
<div class="gauge-container">
<gauge-text class="gauge-text">Health</gauge-text>
<gauge class="gauge" color="Green"></gauge>
</gauge-container>
<gauge-container2>
</div>
<div class="gauge-container2">
<gauge-text class="gauge-text">Mana</gauge-text>
<gauge class="gauge" color="Blue"></gauge>
</gauge-container2>
</div>
</panel>
<buttons>
<div class="buttons">
<button sprite="buttonLong_blue.png" sprite_pressed="buttonLong_blue_pressed.png" class="button-inventory">Inventory</button>
<button sprite="buttonSquare_blue.png" sprite_pressed="buttonSquare_blue_pressed.png" class="button-ok">OK</button>
</buttons>
</div>
<button class="close-button" sprite="buttonRound_blue.png">
<sprite sprite="iconCross_beige.png" class="close-button-sprite"></sprite>
</button>
</panel>
</container>
</div>

<bottom-buttons>
<bottom-button sprite="buttonSquare_brown.png" sprite_pressed="buttonSquare_brown_pressed.png">A</bottom-button>
<bottom-button sprite="buttonSquare_brown.png" sprite_pressed="buttonSquare_brown_pressed.png">B</bottom-button>
<bottom-button sprite="buttonSquare_brown.png" sprite_pressed="buttonSquare_brown_pressed.png">C</bottom-button>
<bottom-button sprite="buttonSquare_brown.png" sprite_pressed="buttonSquare_brown_pressed.png">D</bottom-button>
</bottom-buttons>
<div class="bottom-buttons">
<bottom-button class="bottom-button" sprite="buttonSquare_brown.png" sprite_pressed="buttonSquare_brown_pressed.png">A</bottom-button>
<bottom-button class="bottom-button" sprite="buttonSquare_brown.png" sprite_pressed="buttonSquare_brown_pressed.png">B</bottom-button>
<bottom-button class="bottom-button" sprite="buttonSquare_brown.png" sprite_pressed="buttonSquare_brown_pressed.png">C</bottom-button>
<bottom-button class="bottom-button" sprite="buttonSquare_brown.png" sprite_pressed="buttonSquare_brown_pressed.png">D</bottom-button>
</div>

<play-game-container>
<div class="play-game-container">
<panel class="play-game-panel" sprite="glassPanel_corners.png">
<play-game-text>PLAY THE GAME?</play-game-text>
<play-game-buttons>
<play-game-text style="margin-bottom: 20px;">PLAY THE GAME?</play-game-text>
<div class="play-game-buttons">
<panel-button sprite="glassPanel_projection.png">YES</panel-button>
<panel-button sprite="glassPanel_projection.png" style="margin-left: 20px;">NO</panel-button>
</play-game-buttons>
</div>
</panel>
</play-game-container>
</game-ui>
</div>
</div>
</body>

</html>
64 changes: 45 additions & 19 deletions examples/game/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,7 @@ type screen struct {
}

func (g *Game) Update() error {
g.initOnce.Do(func() {
g.setupUI()
})
g.initOnce.Do(func() { g.setupUI() })
g.gameUI.Update()
return nil
}
Expand Down Expand Up @@ -83,31 +81,59 @@ func NewGame() (*Game, error) {
//go:embed assets/html/main.html
var mainHTML string

func init() {
furex.RegisterComponents(furex.ComponentsMap{
"panel": &widgets.Panel{},
"sprite": &widgets.Sprite{},
})
}

func (g *Game) setupUI() {
g.gameUI = furex.Parse(mainHTML, &furex.ParseOptions{
Width: g.screen.Width,
Height: g.screen.Height,
Components: map[string]furex.Component{
"panel": &widgets.Panel{},
"gauge-text": &widgets.Text{Color: color.RGBA{50, 48, 41, 255}},
"gauge": func() furex.Handler { return &widgets.Bar{Value: .8} },
Components: furex.ComponentsMap{
"panel": &widgets.Panel{},
"gauge-text": func() *furex.View {
return &furex.View{
Width: 180,
Height: 20,
Handler: &widgets.Text{Color: color.RGBA{50, 48, 41, 255}},
}
},
"gauge": func() furex.Handler { return &widgets.Bar{Value: .8} },
"button": func() furex.Handler {
return &widgets.Button{OnClick: func() { println("button clicked") }}
},
"sprite": &widgets.Sprite{},
"bottom-button": func() furex.Handler {
return &widgets.Button{
Color: color.RGBA{210, 178, 144, 255},
OnClick: func() { println("button clicked") },
}
"bottom-button": func() *furex.View {
return &furex.View{
Width: 45,
Height: 49,
Handler: &widgets.Button{
Color: color.RGBA{210, 178, 144, 255},
OnClick: func() { println("button clicked") },
}}
},
"panel-button": func() furex.Handler {
return &widgets.Panel{OnClick: func() { println("button clicked") }}
"panel-button": func() *furex.View {
return &furex.View{
Width: 100,
Height: 50,
Handler: &widgets.Panel{OnClick: func() { println("button clicked") }},
}
},
"play-game-text": &widgets.Text{
Color: color.RGBA{45, 73, 94, 255},
HorzAlign: etxt.XCenter,
VertAlign: etxt.YCenter,
"play-game-text": func() *furex.View {
return &furex.View{
Width: 100,
Height: 8,
Direction: furex.Row,
AlignItems: furex.AlignItemCenter,
Justify: furex.JustifyCenter,
Handler: &widgets.Text{
Color: color.RGBA{45, 73, 94, 255},
HorzAlign: etxt.XCenter,
VertAlign: etxt.YCenter,
},
}
},
},
})
Expand Down
8 changes: 4 additions & 4 deletions flex.go
Original file line number Diff line number Diff line change
Expand Up @@ -216,14 +216,14 @@ func (f *flexEmbed) layout(width, height int, container *containerEmbed) {
x := container.frame.Min.X
if c.item.Left != 0 {
x = container.frame.Min.X + c.item.Left
} else if c.item.Right != 0 {
x = container.frame.Max.X - c.item.Right - c.item.Width
} else if c.item.Right != nil {
x = container.frame.Max.X - *c.item.Right - c.item.Width
}
y := container.frame.Min.Y
if c.item.Top != 0 {
y = container.frame.Min.Y + c.item.Top
} else if c.item.Bottom != 0 {
y = container.frame.Max.Y - c.item.Bottom - c.item.Height
} else if c.item.Bottom != nil {
y = container.frame.Max.Y - *c.item.Bottom - c.item.Height
}
c.bounds = image.Rect(x, y, x+c.item.Width, y+c.item.Height)
c.item.frame = c.bounds
Expand Down
2 changes: 1 addition & 1 deletion flex_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ func TestAbsolutePosRightBottom(t *testing.T) {
mock := mockHandler{}

f1 := (&View{Width: 100, Height: 100}).addChild(
&View{Position: PositionAbsolute, Width: 10, Height: 10, Right: 40, Bottom: 50, Handler: &mock},
&View{Position: PositionAbsolute, Width: 10, Height: 10, Right: Int(40), Bottom: Int(50), Handler: &mock},
)

f1.Update()
Expand Down
Loading

0 comments on commit fbf79ba

Please sign in to comment.