Compare commits
4 Commits
3474d7d973
...
4b57ace9d6
Author | SHA1 | Date | |
---|---|---|---|
4b57ace9d6 | |||
498021456d | |||
89c8a5225e | |||
28ab816bae |
@ -9,11 +9,10 @@ import (
|
|||||||
// import "github.com/veandco/go-sdl2/sdl"
|
// import "github.com/veandco/go-sdl2/sdl"
|
||||||
|
|
||||||
type ButtonBar struct {
|
type ButtonBar struct {
|
||||||
ui.ContainerBase
|
ui.StackPanel
|
||||||
|
|
||||||
Background color.Color
|
Background color.Color
|
||||||
ButtonLength float32
|
ButtonLength float32
|
||||||
Orientation ui.Orientation
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const buttonBarWidth = 96
|
const buttonBarWidth = 96
|
||||||
|
@ -7,10 +7,13 @@ import (
|
|||||||
|
|
||||||
"opslag.de/schobers/fs/ricefs"
|
"opslag.de/schobers/fs/ricefs"
|
||||||
"opslag.de/schobers/geom"
|
"opslag.de/schobers/geom"
|
||||||
|
"opslag.de/schobers/zntg"
|
||||||
"opslag.de/schobers/zntg/addons/res"
|
"opslag.de/schobers/zntg/addons/res"
|
||||||
_ "opslag.de/schobers/zntg/sdlui" // rendering backend
|
|
||||||
"opslag.de/schobers/zntg/ui"
|
"opslag.de/schobers/zntg/ui"
|
||||||
|
|
||||||
|
_ "opslag.de/schobers/zntg/sdlui" // rendering backend
|
||||||
|
// _ "opslag.de/schobers/zntg/allg5ui" // rendering backend
|
||||||
|
|
||||||
rice "github.com/GeertJohan/go.rice"
|
rice "github.com/GeertJohan/go.rice"
|
||||||
"github.com/veandco/go-sdl2/sdl"
|
"github.com/veandco/go-sdl2/sdl"
|
||||||
"opslag.de/schobers/tins2020"
|
"opslag.de/schobers/tins2020"
|
||||||
@ -81,27 +84,29 @@ func (a *app) Init(ctx ui.Context) error {
|
|||||||
|
|
||||||
content := tins2020.NewContent(a.dialogs)
|
content := tins2020.NewContent(a.dialogs)
|
||||||
content.AddChild(tins2020.NewTerrainRenderer(a.game))
|
content.AddChild(tins2020.NewTerrainRenderer(a.game))
|
||||||
content.AddChild(tins2020.NewGameControls(a.game, a.dialogs))
|
controls := tins2020.NewGameControls(a.game, a.dialogs)
|
||||||
|
content.AddChild(controls)
|
||||||
a.Content = content
|
a.Content = content
|
||||||
|
|
||||||
a.dialogs.Init(ctx)
|
a.dialogs.Init(ctx)
|
||||||
a.game.Reset(ctx)
|
a.game.Reset(ctx)
|
||||||
|
controls.Init(ctx)
|
||||||
a.dialogs.ShowIntro(ctx)
|
a.dialogs.ShowIntro(ctx)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *app) Handle(ctx ui.Context, event ui.Event) bool {
|
func (a *app) Handle(ctx ui.Context, e ui.Event) bool {
|
||||||
// switch e := event.(type) {
|
switch e := e.(type) {
|
||||||
// case *ui.WindowMoved:
|
case *ui.DisplayMoveEvent:
|
||||||
// // x, y := window.GetPosition()
|
location := e.Bounds.Min.ToInt()
|
||||||
// // settings.Window.Location = ptPtr(x, y)
|
a.settings.Window.Location = &location
|
||||||
// case *ui.WindowSizeChanged:
|
case *ui.DisplayResizeEvent:
|
||||||
// w, h := window.GetSize()
|
a.Arrange(ctx, e.Bounds, geom.ZeroPtF32, nil)
|
||||||
// app.Arrange(ctx, geom.RectRelF32(0, 0, w, h))
|
size := e.Bounds.Size().ToInt()
|
||||||
// settings.Window.Size = ptPtr(w, h)
|
a.settings.Window.Size = &size
|
||||||
// }
|
}
|
||||||
return a.Proxy.Handle(ctx, event)
|
return a.Proxy.Handle(ctx, e)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *app) Render(ctx ui.Context) {
|
func (a *app) Render(ctx ui.Context) {
|
||||||
@ -132,6 +137,7 @@ func run() error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
defer settings.Store()
|
||||||
|
|
||||||
if settings.Window.Location == nil {
|
if settings.Window.Location == nil {
|
||||||
settings.Window.Location = ptPtr(sdl.WINDOWPOS_UNDEFINED, sdl.WINDOWPOS_UNDEFINED)
|
settings.Window.Location = ptPtr(sdl.WINDOWPOS_UNDEFINED, sdl.WINDOWPOS_UNDEFINED)
|
||||||
@ -144,6 +150,7 @@ func run() error {
|
|||||||
settings.Window.VSync = &vsync
|
settings.Window.VSync = &vsync
|
||||||
}
|
}
|
||||||
renderer, err := ui.NewRenderer("Botanim - TINS 2020", settings.Window.Size.X, settings.Window.Size.Y, ui.NewRendererOptions{
|
renderer, err := ui.NewRenderer("Botanim - TINS 2020", settings.Window.Size.X, settings.Window.Size.Y, ui.NewRendererOptions{
|
||||||
|
Location: &geom.PointF32{X: float32(settings.Window.Location.X), Y: float32(settings.Window.Location.Y)},
|
||||||
Resizable: true,
|
Resizable: true,
|
||||||
VSync: *settings.Window.VSync,
|
VSync: *settings.Window.VSync,
|
||||||
})
|
})
|
||||||
@ -159,5 +166,20 @@ func run() error {
|
|||||||
dialogs: tins2020.NewDialogs(game),
|
dialogs: tins2020.NewDialogs(game),
|
||||||
settings: settings,
|
settings: settings,
|
||||||
}
|
}
|
||||||
return ui.Run(renderer, nil, app)
|
style := ui.DefaultStyle()
|
||||||
|
style.Palette = &ui.Palette{
|
||||||
|
Background: zntg.MustHexColor(`#5388C3`),
|
||||||
|
Primary: zntg.MustHexColor(`#5388C3`),
|
||||||
|
PrimaryDark: zntg.MustHexColor(`#15569F`),
|
||||||
|
PrimaryLight: zntg.MustHexColor(`#ABCAED`),
|
||||||
|
Secondary: zntg.MustHexColor(`#4AC69A`),
|
||||||
|
SecondaryDark: zntg.MustHexColor(`#0AA36D`),
|
||||||
|
SecondaryLight: zntg.MustHexColor(`#A6EED4`),
|
||||||
|
Text: color.White,
|
||||||
|
TextOnPrimary: color.White,
|
||||||
|
TextOnSecondary: color.White,
|
||||||
|
TextNegative: zntg.MustHexColor(`F3590E`),
|
||||||
|
TextPositive: zntg.MustHexColor(`65D80D`),
|
||||||
|
}
|
||||||
|
return ui.Run(renderer, style, app)
|
||||||
}
|
}
|
||||||
|
137
dial.go
Normal file
137
dial.go
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
package tins2020
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"opslag.de/schobers/geom"
|
||||||
|
"opslag.de/schobers/zntg/ui"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Dial struct {
|
||||||
|
ui.ContainerBase
|
||||||
|
|
||||||
|
dialer Dialer
|
||||||
|
|
||||||
|
typing string // current digit
|
||||||
|
digitCount int // number of times the digit is pressed
|
||||||
|
digits []DialDigit // digits
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDial(dialer Dialer) *Dial {
|
||||||
|
dial := &Dial{dialer: dialer}
|
||||||
|
dial.digits = make([]DialDigit, 10)
|
||||||
|
|
||||||
|
for i := range dial.digits {
|
||||||
|
j := i
|
||||||
|
dial.digits[i].Value = strconv.Itoa(i)
|
||||||
|
dial.digits[i].ControlClicked().AddHandler(func(ctx ui.Context, _ ui.ControlClickedArgs) {
|
||||||
|
dial.userTyped(ctx, j)
|
||||||
|
})
|
||||||
|
dial.AddChild(&dial.digits[i])
|
||||||
|
}
|
||||||
|
return dial
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Dial) userTyped(ctx ui.Context, i int) {
|
||||||
|
d.digits[i].Blink()
|
||||||
|
digit := strconv.Itoa(i)
|
||||||
|
if len(d.typing) == 0 || digit != d.typing {
|
||||||
|
d.typing = digit
|
||||||
|
d.digitCount = 1
|
||||||
|
} else {
|
||||||
|
d.digitCount++
|
||||||
|
}
|
||||||
|
|
||||||
|
if !d.dialer.CanUserType(i) {
|
||||||
|
d.typing = ""
|
||||||
|
d.digitCount = 0
|
||||||
|
d.dialer.UserGaveWrongInput()
|
||||||
|
} else if d.digitCount == i || d.digitCount == 10 {
|
||||||
|
d.typing = ""
|
||||||
|
d.digitCount = 0
|
||||||
|
d.dialer.UserTyped(ctx, i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Dial) Arrange(ctx ui.Context, bounds geom.RectangleF32, offset geom.PointF32, parent ui.Control) {
|
||||||
|
d.ControlBase.Arrange(ctx, bounds, offset, parent)
|
||||||
|
|
||||||
|
center := bounds.Center()
|
||||||
|
size := bounds.Size()
|
||||||
|
|
||||||
|
distance := size.Y * .3
|
||||||
|
for i := range d.digits {
|
||||||
|
angle := (float32((10-i)%10)*0.16 + .2) * math.Pi
|
||||||
|
pos := geom.PtF32(distance*geom.Cos32(angle), .8*distance*geom.Sin32(angle))
|
||||||
|
digitCenter := center.Add(pos)
|
||||||
|
d.digits[i].Arrange(ctx, geom.RectRelF32(digitCenter.X-24, digitCenter.Y-24, 48, 48), offset, d)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Dial) DesiredSize(ctx ui.Context, size geom.PointF32) geom.PointF32 {
|
||||||
|
return geom.PtF32(size.X, geom.NaN32())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Dial) Handle(ctx ui.Context, event ui.Event) bool {
|
||||||
|
if d.ContainerBase.Handle(ctx, event) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
switch e := event.(type) {
|
||||||
|
case *ui.KeyDownEvent:
|
||||||
|
switch e.Key {
|
||||||
|
case ui.Key0:
|
||||||
|
d.userTyped(ctx, 0)
|
||||||
|
case ui.KeyPad0:
|
||||||
|
d.userTyped(ctx, 0)
|
||||||
|
case ui.Key1:
|
||||||
|
d.userTyped(ctx, 1)
|
||||||
|
case ui.KeyPad1:
|
||||||
|
d.userTyped(ctx, 1)
|
||||||
|
case ui.Key2:
|
||||||
|
d.userTyped(ctx, 2)
|
||||||
|
case ui.KeyPad2:
|
||||||
|
d.userTyped(ctx, 2)
|
||||||
|
case ui.Key3:
|
||||||
|
d.userTyped(ctx, 3)
|
||||||
|
case ui.KeyPad3:
|
||||||
|
d.userTyped(ctx, 3)
|
||||||
|
case ui.Key4:
|
||||||
|
d.userTyped(ctx, 4)
|
||||||
|
case ui.KeyPad4:
|
||||||
|
d.userTyped(ctx, 4)
|
||||||
|
case ui.Key5:
|
||||||
|
d.userTyped(ctx, 5)
|
||||||
|
case ui.KeyPad5:
|
||||||
|
d.userTyped(ctx, 5)
|
||||||
|
case ui.Key6:
|
||||||
|
d.userTyped(ctx, 6)
|
||||||
|
case ui.KeyPad6:
|
||||||
|
d.userTyped(ctx, 6)
|
||||||
|
case ui.Key7:
|
||||||
|
d.userTyped(ctx, 7)
|
||||||
|
case ui.KeyPad7:
|
||||||
|
d.userTyped(ctx, 7)
|
||||||
|
case ui.Key8:
|
||||||
|
d.userTyped(ctx, 8)
|
||||||
|
case ui.KeyPad8:
|
||||||
|
d.userTyped(ctx, 8)
|
||||||
|
case ui.Key9:
|
||||||
|
d.userTyped(ctx, 9)
|
||||||
|
case ui.KeyPad9:
|
||||||
|
d.userTyped(ctx, 9)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Dial) Reset() {
|
||||||
|
d.typing = ""
|
||||||
|
d.digitCount = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Dial) Tick() {
|
||||||
|
for i := range d.digits {
|
||||||
|
d.digits[i].Tick()
|
||||||
|
}
|
||||||
|
}
|
34
dialdigit.go
Normal file
34
dialdigit.go
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
package tins2020
|
||||||
|
|
||||||
|
import (
|
||||||
|
"opslag.de/schobers/geom"
|
||||||
|
"opslag.de/schobers/zntg"
|
||||||
|
"opslag.de/schobers/zntg/ui"
|
||||||
|
)
|
||||||
|
|
||||||
|
type DialDigit struct {
|
||||||
|
ui.ControlBase
|
||||||
|
|
||||||
|
Value string
|
||||||
|
|
||||||
|
highlight int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DialDigit) Blink() {
|
||||||
|
d.highlight = 4
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DialDigit) Render(ctx ui.Context) {
|
||||||
|
color := zntg.MustHexColor(`#FFFFFF`)
|
||||||
|
if d.highlight > 0 {
|
||||||
|
color = zntg.MustHexColor(`#15569F`)
|
||||||
|
}
|
||||||
|
bounds := d.Bounds()
|
||||||
|
ctx.Fonts().TextAlign("title", geom.PtF32(bounds.Center().X, bounds.Min.Y), color, d.Value, ui.AlignCenter)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DialDigit) Tick() {
|
||||||
|
if d.highlight > 0 {
|
||||||
|
d.highlight--
|
||||||
|
}
|
||||||
|
}
|
76
dialogs.go
76
dialogs.go
@ -5,66 +5,80 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Dialogs struct {
|
type Dialogs struct {
|
||||||
intro ui.Overlay
|
ui.Proxy
|
||||||
settings ui.Overlay
|
|
||||||
research ui.Overlay
|
|
||||||
|
|
||||||
open string
|
intro ui.Overlay
|
||||||
|
research ui.Overlay
|
||||||
|
settings ui.Overlay
|
||||||
|
nothing ui.Control
|
||||||
|
|
||||||
closed ui.Events
|
closed ui.Events
|
||||||
opened ui.Events
|
opened ui.Events
|
||||||
}
|
}
|
||||||
|
|
||||||
const introDialogName = "dialog-intro"
|
const dialogsOverlayName = "dialogs"
|
||||||
const settingsDialogName = "dialog-settings"
|
|
||||||
const researchDialogName = "dialog-research"
|
|
||||||
|
|
||||||
func NewDialogs(game *Game) *Dialogs {
|
func NewDialogs(game *Game) *Dialogs {
|
||||||
return &Dialogs{
|
intro := NewIntro()
|
||||||
intro: NewIntro(),
|
research := NewResearch(game)
|
||||||
settings: &LargeDialog{},
|
settings := NewLargeDialog("Settings", &ui.Label{})
|
||||||
research: NewResearch(game),
|
|
||||||
|
dialogs := &Dialogs{
|
||||||
|
intro: intro,
|
||||||
|
settings: settings,
|
||||||
|
research: research,
|
||||||
|
nothing: &ui.ControlBase{},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
intro.CloseRequested().AddHandlerEmpty(dialogs.Close)
|
||||||
|
research.CloseRequested().AddHandlerEmpty(dialogs.Close)
|
||||||
|
settings.CloseRequested().AddHandlerEmpty(dialogs.Close)
|
||||||
|
|
||||||
|
return dialogs
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Dialogs) Init(ctx ui.Context) {
|
func (d *Dialogs) Init(ctx ui.Context) {
|
||||||
overlays := ctx.Overlays()
|
overlays := ctx.Overlays()
|
||||||
|
overlays.AddOnTop(dialogsOverlayName, d, false)
|
||||||
|
|
||||||
overlays.AddOnTop(introDialogName, d.intro, false)
|
d.Content = d.nothing
|
||||||
overlays.AddOnTop(settingsDialogName, d.settings, false)
|
|
||||||
overlays.AddOnTop(researchDialogName, d.research, false)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Dialogs) showDialog(ctx ui.Context, name string) {
|
func (d *Dialogs) showDialog(ctx ui.Context, control ui.Control) {
|
||||||
d.Close(ctx)
|
if control == nil {
|
||||||
|
ctx.Overlays().Hide(dialogsOverlayName)
|
||||||
ctx.Overlays().Show(name)
|
d.closed.Notify(ctx, control)
|
||||||
d.open = name
|
d.Content = d.nothing
|
||||||
|
} else {
|
||||||
d.opened.Notify(ctx, name)
|
d.Content = control
|
||||||
|
ctx.Overlays().Show(dialogsOverlayName)
|
||||||
|
d.opened.Notify(ctx, control)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Dialogs) Close(ctx ui.Context) {
|
func (d *Dialogs) Close(ctx ui.Context) {
|
||||||
name := d.open
|
d.showDialog(ctx, nil)
|
||||||
if name == "" {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
ctx.Overlays().Hide(name)
|
|
||||||
d.open = ""
|
|
||||||
d.closed.Notify(ctx, name)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Dialogs) DialogClosed() ui.EventHandler { return &d.closed }
|
func (d *Dialogs) DialogClosed() ui.EventHandler { return &d.closed }
|
||||||
func (d *Dialogs) DialogOpened() ui.EventHandler { return &d.opened }
|
func (d *Dialogs) DialogOpened() ui.EventHandler { return &d.opened }
|
||||||
|
|
||||||
|
func (d *Dialogs) Hidden() {
|
||||||
|
d.Proxy.Hidden()
|
||||||
|
}
|
||||||
|
|
||||||
func (d *Dialogs) ShowIntro(ctx ui.Context) {
|
func (d *Dialogs) ShowIntro(ctx ui.Context) {
|
||||||
d.showDialog(ctx, introDialogName)
|
d.showDialog(ctx, d.intro)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Dialogs) Shown() {
|
||||||
|
d.Proxy.Shown()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Dialogs) ShowResearch(ctx ui.Context) {
|
func (d *Dialogs) ShowResearch(ctx ui.Context) {
|
||||||
d.showDialog(ctx, researchDialogName)
|
d.showDialog(ctx, d.research)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Dialogs) ShowSettings(ctx ui.Context) {
|
func (d *Dialogs) ShowSettings(ctx ui.Context) {
|
||||||
d.showDialog(ctx, settingsDialogName)
|
d.showDialog(ctx, d.settings)
|
||||||
}
|
}
|
||||||
|
@ -26,8 +26,10 @@ type GameControls struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewGameControls(game *Game, dialogs *Dialogs) *GameControls {
|
func NewGameControls(game *Game, dialogs *Dialogs) *GameControls {
|
||||||
c := &GameControls{game: game, dialogs: dialogs}
|
return &GameControls{game: game, dialogs: dialogs}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *GameControls) Init(ctx ui.Context) {
|
||||||
c.game.SpeedChanged().AddHandler(c.speedChanged)
|
c.game.SpeedChanged().AddHandler(c.speedChanged)
|
||||||
c.game.ToolChanged().AddHandler(c.toolChanged)
|
c.game.ToolChanged().AddHandler(c.toolChanged)
|
||||||
c.dialogs.DialogOpened().AddHandlerEmpty(func(ctx ui.Context) { c.game.Pause(ctx) })
|
c.dialogs.DialogOpened().AddHandlerEmpty(func(ctx ui.Context) { c.game.Pause(ctx) })
|
||||||
@ -105,8 +107,6 @@ func NewGameControls(game *Game, dialogs *Dialogs) *GameControls {
|
|||||||
c.AddChild(&c.top)
|
c.AddChild(&c.top)
|
||||||
c.AddChild(&c.flowers)
|
c.AddChild(&c.flowers)
|
||||||
c.AddChild(&c.otherTools)
|
c.AddChild(&c.otherTools)
|
||||||
|
|
||||||
return c
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *GameControls) createBuyFlowerButton(id string) *BuyFlowerButton {
|
func (c *GameControls) createBuyFlowerButton(id string) *BuyFlowerButton {
|
||||||
|
@ -19,7 +19,6 @@ type IconButton struct {
|
|||||||
ui.Button
|
ui.Button
|
||||||
|
|
||||||
IconDisabled string
|
IconDisabled string
|
||||||
IconHeight int32
|
|
||||||
// IconScale Scale
|
// IconScale Scale
|
||||||
// IconWidth int32
|
// IconWidth int32
|
||||||
|
|
||||||
|
9
intro.go
9
intro.go
@ -1,13 +1,18 @@
|
|||||||
package tins2020
|
package tins2020
|
||||||
|
|
||||||
import "opslag.de/schobers/zntg/ui"
|
import (
|
||||||
|
"image/color"
|
||||||
|
|
||||||
|
"opslag.de/schobers/zntg/ui"
|
||||||
|
)
|
||||||
|
|
||||||
type Intro struct {
|
type Intro struct {
|
||||||
ui.Paragraph
|
ui.Paragraph
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewIntro() ui.Overlay {
|
func NewIntro() *LargeDialog {
|
||||||
i := &Intro{}
|
i := &Intro{}
|
||||||
|
i.Font.Color = color.White
|
||||||
i.Text =
|
i.Text =
|
||||||
"Welcome to Botanim!\n\n" +
|
"Welcome to Botanim!\n\n" +
|
||||||
"In Botanim you play the role of botanist and your goal is to cultivate flowers in an open landscape.\n\n" +
|
"In Botanim you play the role of botanist and your goal is to cultivate flowers in an open landscape.\n\n" +
|
||||||
|
149
largedialog.go
149
largedialog.go
@ -1,64 +1,26 @@
|
|||||||
package tins2020
|
package tins2020
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"image/color"
|
||||||
|
|
||||||
|
"opslag.de/schobers/geom"
|
||||||
"opslag.de/schobers/zntg"
|
"opslag.de/schobers/zntg"
|
||||||
"opslag.de/schobers/zntg/ui"
|
"opslag.de/schobers/zntg/ui"
|
||||||
)
|
)
|
||||||
|
|
||||||
// type DialogBase struct {
|
|
||||||
// }
|
|
||||||
|
|
||||||
// type Dialog interface {
|
|
||||||
// CloseDialog()
|
|
||||||
// OnShow() zntg.EventHandler
|
|
||||||
// ShowDialog(ui.Context, zntg.EventFn)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// func (d *DialogBase) CloseDialog() {
|
|
||||||
// close := d.close
|
|
||||||
// if close != nil {
|
|
||||||
// close()
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// func (d *DialogBase) Init(ctx ui.Context) error {
|
|
||||||
// d.AddChild(&d.content)
|
|
||||||
// return d.Container.Init(ctx)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// func (d *DialogBase) OnShow() zntg.EventHandler {
|
|
||||||
// if d.onShow == nil {
|
|
||||||
// d.onShow = NewEvents()
|
|
||||||
// }
|
|
||||||
// return d.onShow
|
|
||||||
// }
|
|
||||||
|
|
||||||
// func (d *DialogBase) SetContent(control ui.Control) {
|
|
||||||
// d.content.Proxied = control
|
|
||||||
// }
|
|
||||||
|
|
||||||
// func (d *DialogBase) ShowDialog(ctx ui.Context, close zntg.EventFn) {
|
|
||||||
// d.close = close
|
|
||||||
// if d.onShow != nil {
|
|
||||||
// d.onShow.Notify(ctx)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
type LargeDialog struct {
|
type LargeDialog struct {
|
||||||
ui.StackPanel
|
ui.StackPanel
|
||||||
|
|
||||||
titleBar *LargeDialogTitleBar
|
titleBar *LargeDialogTitleBar
|
||||||
content ui.OverlayProxy
|
content ui.Proxy
|
||||||
|
|
||||||
closeRequested ui.Events
|
closeRequested ui.Events
|
||||||
|
|
||||||
onShow zntg.Events
|
|
||||||
close zntg.EventFn
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewLargeDialog(title string, content ui.Control) *LargeDialog {
|
func NewLargeDialog(title string, content ui.Control) *LargeDialog {
|
||||||
dialog := &LargeDialog{}
|
dialog := &LargeDialog{}
|
||||||
|
|
||||||
|
dialog.Orientation = ui.OrientationVertical
|
||||||
dialog.titleBar = NewLargeDialogTitleBar(title, func(ctx ui.Context, state interface{}) {
|
dialog.titleBar = NewLargeDialogTitleBar(title, func(ctx ui.Context, state interface{}) {
|
||||||
dialog.closeRequested.Notify(ctx, state)
|
dialog.closeRequested.Notify(ctx, state)
|
||||||
})
|
})
|
||||||
@ -68,8 +30,39 @@ func NewLargeDialog(title string, content ui.Control) *LargeDialog {
|
|||||||
return dialog
|
return dialog
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *LargeDialog) CloseRequested() ui.EventHandler { return &d.closeRequested }
|
||||||
|
|
||||||
|
// func (d *LargeDialog) Arrange(ctx ui.Context, bounds geom.RectangleF32, offset geom.PointF32, parent ui.Control) {
|
||||||
|
// d.titleBar.Arrange(ctx, bounds.Min.RectRel2D(bounds.Dx(), titleHeight), offset, d)
|
||||||
|
// d.content.Arrange(ctx, geom.RectRelF32(bounds.Min.X+titleHeight, bounds.Min.Y, bounds.Dx(), bounds.Dy()-titleHeight), offset, d)
|
||||||
|
// }
|
||||||
|
|
||||||
|
func (d *LargeDialog) Handle(ctx ui.Context, e ui.Event) bool {
|
||||||
|
if d.StackPanel.Handle(ctx, e) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
switch e := e.(type) {
|
||||||
|
case *ui.KeyDownEvent:
|
||||||
|
switch e.Key {
|
||||||
|
case ui.KeyEscape:
|
||||||
|
d.closeRequested.Notify(ctx, nil)
|
||||||
|
return true
|
||||||
|
case ui.KeyEnter:
|
||||||
|
d.closeRequested.Notify(ctx, nil)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
func (d *LargeDialog) Hidden() { d.content.Hidden() }
|
func (d *LargeDialog) Hidden() { d.content.Hidden() }
|
||||||
|
|
||||||
|
func (d *LargeDialog) Render(ctx ui.Context) {
|
||||||
|
ctx.Renderer().Clear(zntg.MustHexColor("#356DAD"))
|
||||||
|
d.StackPanel.Render(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
func (d *LargeDialog) Shown() { d.content.Shown() }
|
func (d *LargeDialog) Shown() { d.content.Shown() }
|
||||||
|
|
||||||
type LargeDialogTitleBar struct {
|
type LargeDialogTitleBar struct {
|
||||||
@ -85,57 +78,27 @@ func NewLargeDialogTitleBar(title string, closeRequested ui.EventFn) *LargeDialo
|
|||||||
titleBar.close.ButtonClicked().AddHandler(func(ctx ui.Context, args ui.ControlClickedArgs) {
|
titleBar.close.ButtonClicked().AddHandler(func(ctx ui.Context, args ui.ControlClickedArgs) {
|
||||||
closeRequested(ctx, args)
|
closeRequested(ctx, args)
|
||||||
})
|
})
|
||||||
|
titleBar.title.Font.Color = color.White
|
||||||
|
titleBar.title.Font.Name = "title"
|
||||||
|
titleBar.title.Text = title
|
||||||
|
titleBar.title.TextAlignment = ui.AlignCenter
|
||||||
|
|
||||||
|
titleBar.close.Icon = "control-cancel"
|
||||||
|
titleBar.close.IconHeight = 32
|
||||||
|
titleBar.close.Type = ui.ButtonTypeIcon
|
||||||
|
|
||||||
return titleBar
|
return titleBar
|
||||||
}
|
}
|
||||||
|
|
||||||
// func (d *LargeDialog) Arrange(ctx ui.Context, bounds Rectangle) {
|
func (b *LargeDialogTitleBar) Arrange(ctx ui.Context, bounds geom.RectangleF32, offset geom.PointF32, parent ui.Control) {
|
||||||
// const titleHeight = 64
|
b.ControlBase.Arrange(ctx, bounds, offset, parent)
|
||||||
// d.ControlBase.Arrange(ctx, bounds)
|
b.title.Arrange(ctx, bounds, offset, parent)
|
||||||
// d.title.Arrange(ctx, Rect(bounds.X, bounds.Y, bounds.W, titleHeight))
|
height := bounds.Dy()
|
||||||
// d.close.Arrange(ctx, Rect(bounds.W-64, 0, 64, 64))
|
b.close.Arrange(ctx, geom.RectRelF32(bounds.Max.X-height, bounds.Min.Y, height, height), offset, parent)
|
||||||
// d.content.Arrange(ctx, Rect(bounds.X+titleHeight, 96, bounds.W-2*titleHeight, bounds.H-titleHeight))
|
b.close.HoverColor = ctx.Style().Palette.PrimaryDark
|
||||||
// }
|
}
|
||||||
|
|
||||||
// func (d *LargeDialog) Init(ctx ui.Context) error {
|
func (b *LargeDialogTitleBar) DesiredSize(ctx ui.Context, size geom.PointF32) geom.PointF32 {
|
||||||
// d.title.Text = "Botanim"
|
const titleHeight = 64
|
||||||
// d.title.FontName = "title"
|
return geom.PtF32(size.X, titleHeight)
|
||||||
// d.title.Alignment = TextAlignmentCenter
|
}
|
||||||
|
|
||||||
// d.close = IconButton{
|
|
||||||
// Icon: "control-cancel",
|
|
||||||
// IconHover: HoverEffectColor,
|
|
||||||
// IconWidth: 32,
|
|
||||||
// }
|
|
||||||
// d.close.OnLeftMouseButtonClick = EmptyEvent(d.CloseDialog)
|
|
||||||
// d.AddChild(&d.title)
|
|
||||||
// d.AddChild(&d.close)
|
|
||||||
// return d.DialogBase.Init(ctx)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// func (d *LargeDialog) Handle(ctx ui.Context, event sdl.Event) bool {
|
|
||||||
// if d.DialogBase.Handle(ctx, event) {
|
|
||||||
// return true
|
|
||||||
// }
|
|
||||||
|
|
||||||
// switch e := event.(type) {
|
|
||||||
// case *sdl.KeyboardEvent:
|
|
||||||
// if e.Type == sdl.KEYDOWN {
|
|
||||||
// switch e.Keysym.Sym {
|
|
||||||
// case sdl.K_ESCAPE:
|
|
||||||
// d.CloseDialog()
|
|
||||||
// return true
|
|
||||||
// case sdl.K_RETURN:
|
|
||||||
// d.CloseDialog()
|
|
||||||
// return true
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// return false
|
|
||||||
// }
|
|
||||||
|
|
||||||
// func (d *LargeDialog) Render(ctx ui.Context) {
|
|
||||||
// SetDrawColor(ctx.Renderer, MustHexColor("#356DAD"))
|
|
||||||
// ctx.Renderer.FillRect(d.Bounds.SDLPtr())
|
|
||||||
|
|
||||||
// d.DialogBase.Render(ctx)
|
|
||||||
// }
|
|
||||||
|
192
research.go
192
research.go
@ -2,7 +2,6 @@ package tins2020
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@ -15,185 +14,68 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Research struct {
|
type Research struct {
|
||||||
ui.ContainerBase
|
ui.StackPanel
|
||||||
|
|
||||||
game *Game
|
game *Game
|
||||||
botanist Specialist
|
botanist Specialist
|
||||||
farmer Specialist
|
farmer Specialist
|
||||||
|
|
||||||
typing string
|
|
||||||
digitCount int
|
|
||||||
|
|
||||||
close func()
|
|
||||||
description ui.Paragraph
|
description ui.Paragraph
|
||||||
specialists ui.Paragraph
|
specialists ui.Paragraph
|
||||||
|
dial *Dial
|
||||||
input ui.Label
|
input ui.Label
|
||||||
digits []Digit
|
|
||||||
animate zntg.Animation
|
animate zntg.Animation
|
||||||
|
closeRequested ui.Events
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewResearch(game *Game) ui.Overlay {
|
type Dialer interface {
|
||||||
|
CanUserType(int) bool
|
||||||
|
UserGaveWrongInput()
|
||||||
|
UserTyped(ui.Context, int)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewResearch(game *Game) *LargeDialog {
|
||||||
research := &Research{game: game}
|
research := &Research{game: game}
|
||||||
research.animate.Interval = 20 * time.Millisecond
|
research.animate.Interval = 20 * time.Millisecond
|
||||||
|
research.animate.Start()
|
||||||
research.Children = []ui.Control{&research.description, &research.specialists, &research.input}
|
|
||||||
|
|
||||||
research.description.Text = "Call a specialist to conduct research with."
|
research.description.Text = "Call a specialist to conduct research with."
|
||||||
research.digits = make([]Digit, 10)
|
research.dial = NewDial(research)
|
||||||
for i := range research.digits {
|
research.Children = []ui.Control{&research.description, &research.specialists, research.dial, &research.input}
|
||||||
j := i
|
|
||||||
research.digits[i].Value = strconv.Itoa(i)
|
dialog := NewLargeDialog("Research", ui.Stretch(research))
|
||||||
research.digits[i].ControlClicked().AddHandler(func(ctx ui.Context, _ ui.ControlClickedArgs) {
|
research.closeRequested.AddHandlerEmpty(func(ctx ui.Context) { dialog.closeRequested.Notify(ctx, nil) })
|
||||||
research.userTyped(ctx, j)
|
|
||||||
})
|
|
||||||
research.AddChild(&research.digits[i])
|
|
||||||
}
|
|
||||||
dialog := NewLargeDialog("Research", research)
|
|
||||||
// dialog.OnShow().RegisterItf(func(state interface{}) {
|
|
||||||
// research.onShow(state.(ui.Context))
|
|
||||||
// })
|
|
||||||
// research.close = func() { dialog.CloseDialog() }
|
|
||||||
return dialog
|
return dialog
|
||||||
}
|
}
|
||||||
|
|
||||||
type Digit struct {
|
|
||||||
ui.ControlBase
|
|
||||||
|
|
||||||
Value string
|
|
||||||
|
|
||||||
highlight int
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *Digit) Blink() {
|
|
||||||
d.highlight = 4
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *Digit) Render(ctx ui.Context) {
|
|
||||||
color := zntg.MustHexColor(`#FFFFFF`)
|
|
||||||
if d.highlight > 0 {
|
|
||||||
color = zntg.MustHexColor(`#15569F`)
|
|
||||||
}
|
|
||||||
bounds := d.Bounds()
|
|
||||||
ctx.Fonts().TextAlign("title", geom.PtF32(bounds.Center().X, bounds.Min.Y), color, d.Value, ui.AlignCenter)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *Digit) Tick() {
|
|
||||||
if d.highlight > 0 {
|
|
||||||
d.highlight--
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type Specialist struct {
|
type Specialist struct {
|
||||||
Cost int
|
Cost int
|
||||||
Number string
|
Number string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Research) Arrange(ctx ui.Context, bounds geom.RectangleF32, offset geom.PointF32, parent ui.Control) {
|
func (r *Research) Arrange(ctx ui.Context, bounds geom.RectangleF32, offset geom.PointF32, parent ui.Control) {
|
||||||
r.ContainerBase.Arrange(ctx, bounds, offset, parent)
|
|
||||||
|
|
||||||
size := bounds.Size()
|
|
||||||
r.specialists.Arrange(ctx, geom.RectRelF32(bounds.Min.X, bounds.Min.Y+40, size.X, size.Y-40), offset, r)
|
|
||||||
r.input.Arrange(ctx, geom.RectRelF32(bounds.Min.X, bounds.Min.X+size.Y-48, size.X, 24), offset, r)
|
|
||||||
r.input.TextAlignment = ui.AlignCenter
|
r.input.TextAlignment = ui.AlignCenter
|
||||||
|
r.StackPanel.Arrange(ctx, bounds, offset, parent)
|
||||||
|
|
||||||
center := bounds.Center()
|
// size := bounds.Size()
|
||||||
|
// r.specialists.Arrange(ctx, geom.RectRelF32(bounds.Min.X, bounds.Min.Y+40, size.X, size.Y-40), offset, r)
|
||||||
distance := size.Y * .3
|
// r.input.Arrange(ctx, geom.RectRelF32(bounds.Min.X, bounds.Min.X+size.Y-48, size.X, 24), offset, r)
|
||||||
for i := range r.digits {
|
|
||||||
angle := (float32((10-i)%10)*0.16 + .2) * math.Pi
|
|
||||||
pos := geom.PtF32(distance*geom.Cos32(angle), .8*distance*geom.Sin32(angle))
|
|
||||||
digitCenter := center.Add(pos)
|
|
||||||
r.digits[i].Arrange(ctx, geom.RectRelF32(digitCenter.X-24, digitCenter.Y-24, 48, 48), offset, r)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Research) userTyped(ctx ui.Context, i int) {
|
func (r *Research) CanUserType(digit int) bool {
|
||||||
r.digits[i].Blink()
|
typing := strconv.Itoa(digit)
|
||||||
digit := strconv.Itoa(i)
|
return strings.HasPrefix(r.botanist.Number, r.input.Text+typing)
|
||||||
if len(r.typing) == 0 || digit != r.typing {
|
|
||||||
r.typing = digit
|
|
||||||
r.digitCount = 1
|
|
||||||
} else {
|
|
||||||
r.digitCount++
|
|
||||||
}
|
|
||||||
|
|
||||||
if !strings.HasPrefix(r.botanist.Number, r.input.Text+r.typing) {
|
|
||||||
r.input.Text = ""
|
|
||||||
r.typing = ""
|
|
||||||
r.digitCount = 0
|
|
||||||
} else if r.digitCount == i || r.digitCount == 10 {
|
|
||||||
r.input.Text += digit
|
|
||||||
r.typing = ""
|
|
||||||
r.digitCount = 0
|
|
||||||
|
|
||||||
if r.input.Text == r.botanist.Number {
|
|
||||||
r.game.UnlockNextFlower(ctx)
|
|
||||||
r.close()
|
|
||||||
r.input.Text = ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Research) Handle(ctx ui.Context, event ui.Event) bool {
|
func (r *Research) Hidden() {}
|
||||||
if r.ContainerBase.Handle(ctx, event) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
switch e := event.(type) {
|
|
||||||
case *ui.KeyDownEvent:
|
|
||||||
switch e.Key {
|
|
||||||
case ui.Key0:
|
|
||||||
r.userTyped(ctx, 0)
|
|
||||||
case ui.KeyPad0:
|
|
||||||
r.userTyped(ctx, 0)
|
|
||||||
case ui.Key1:
|
|
||||||
r.userTyped(ctx, 1)
|
|
||||||
case ui.KeyPad1:
|
|
||||||
r.userTyped(ctx, 1)
|
|
||||||
case ui.Key2:
|
|
||||||
r.userTyped(ctx, 2)
|
|
||||||
case ui.KeyPad2:
|
|
||||||
r.userTyped(ctx, 2)
|
|
||||||
case ui.Key3:
|
|
||||||
r.userTyped(ctx, 3)
|
|
||||||
case ui.KeyPad3:
|
|
||||||
r.userTyped(ctx, 3)
|
|
||||||
case ui.Key4:
|
|
||||||
r.userTyped(ctx, 4)
|
|
||||||
case ui.KeyPad4:
|
|
||||||
r.userTyped(ctx, 4)
|
|
||||||
case ui.Key5:
|
|
||||||
r.userTyped(ctx, 5)
|
|
||||||
case ui.KeyPad5:
|
|
||||||
r.userTyped(ctx, 5)
|
|
||||||
case ui.Key6:
|
|
||||||
r.userTyped(ctx, 6)
|
|
||||||
case ui.KeyPad6:
|
|
||||||
r.userTyped(ctx, 6)
|
|
||||||
case ui.Key7:
|
|
||||||
r.userTyped(ctx, 7)
|
|
||||||
case ui.KeyPad7:
|
|
||||||
r.userTyped(ctx, 7)
|
|
||||||
case ui.Key8:
|
|
||||||
r.userTyped(ctx, 8)
|
|
||||||
case ui.KeyPad8:
|
|
||||||
r.userTyped(ctx, 8)
|
|
||||||
case ui.Key9:
|
|
||||||
r.userTyped(ctx, 9)
|
|
||||||
case ui.KeyPad9:
|
|
||||||
r.userTyped(ctx, 9)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *Research) Render(ctx ui.Context) {
|
func (r *Research) Render(ctx ui.Context) {
|
||||||
for i := range r.digits {
|
r.animate.AnimateFn(r.dial.Tick)
|
||||||
r.digits[i].Tick()
|
r.StackPanel.Render(ctx)
|
||||||
}
|
|
||||||
r.ContainerBase.Render(ctx)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Research) onShow(ctx ui.Context) {
|
func (r *Research) Shown() {
|
||||||
generateNumber := func() string {
|
generateNumber := func() string {
|
||||||
var number string
|
var number string
|
||||||
for i := 0; i < 3; i++ {
|
for i := 0; i < 3; i++ {
|
||||||
@ -201,8 +83,9 @@ func (r *Research) onShow(ctx ui.Context) {
|
|||||||
}
|
}
|
||||||
return number
|
return number
|
||||||
}
|
}
|
||||||
r.digitCount = 0
|
|
||||||
r.input.Text = ""
|
r.input.Text = ""
|
||||||
|
r.dial.Reset()
|
||||||
|
|
||||||
var specialists string
|
var specialists string
|
||||||
defer func() {
|
defer func() {
|
||||||
@ -226,3 +109,16 @@ func (r *Research) onShow(ctx ui.Context) {
|
|||||||
specialists += fmt.Sprintf("Botanist: no. %s (unlocks next flower; $ %d)\n", r.botanist.Number, r.botanist.Cost)
|
specialists += fmt.Sprintf("Botanist: no. %s (unlocks next flower; $ %d)\n", r.botanist.Number, r.botanist.Cost)
|
||||||
specialists += "Farmer: no. **unavailable** (fertilizes land; $ ---)\n"
|
specialists += "Farmer: no. **unavailable** (fertilizes land; $ ---)\n"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *Research) UserGaveWrongInput() {
|
||||||
|
r.input.Text = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Research) UserTyped(ctx ui.Context, digit int) {
|
||||||
|
r.input.Text += strconv.Itoa(digit)
|
||||||
|
if r.input.Text == r.botanist.Number {
|
||||||
|
r.game.UnlockNextFlower(ctx)
|
||||||
|
r.input.Text = ""
|
||||||
|
r.closeRequested.Notify(ctx, nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user