Compare commits

..

4 Commits

5 changed files with 203 additions and 12 deletions

View File

@ -122,6 +122,8 @@ If you want to use the Allegro backend you can add the build tag `allegro` to th
``` ```
go install opslag.de/schobers/tins2020/cmd/tins2020 -tags static,allegro -ldflags "-s -w" go install opslag.de/schobers/tins2020/cmd/tins2020 -tags static,allegro -ldflags "-s -w"
``` ```
In this case the SDL 2.0 prerequisite is replaced by the Allegro 5.2 (development libraries must be available for your C compiler).
## Sources ## Sources
Can be found at https://opslag.de/schobers/tins2020 (Git repository). Can be found at https://opslag.de/schobers/tins2020 (Git repository).

View File

@ -96,6 +96,7 @@ func (b *BuyFlowerButton) updateTexts(ctx ui.Context) error {
if err := b.priceTexture.Update(textUpdate(ctx.Renderer(), font, color, FmtMoney(b.Flower.BuyPrice))); err != nil { if err := b.priceTexture.Update(textUpdate(ctx.Renderer(), font, color, FmtMoney(b.Flower.BuyPrice))); err != nil {
return err return err
} }
b.Disabled = !b.Flower.Unlocked
b.upToDate = true b.upToDate = true
return nil return nil
} }

140
confirmationdialog.go Normal file
View File

@ -0,0 +1,140 @@
package tins2020
import (
"opslag.de/schobers/geom"
"opslag.de/schobers/zntg"
"opslag.de/schobers/zntg/ui"
)
type confirmationDialog struct {
ui.Proxy
active string
cancel ui.Button
confirm ui.Button
question ui.Paragraph
userDecided ui.Events
}
func newConfirmationDialog(caption, question string) *confirmationDialog {
dialog := &confirmationDialog{}
dialog.active = "confirm"
dialog.cancel.Text = "Cancel"
dialog.cancel.ButtonClicked().AddHandler(func(ctx ui.Context, _ ui.ControlClickedArgs) { dialog.userCanceled(ctx) })
dialog.cancel.Type = ui.ButtonTypeText
dialog.cancel.HoverColor = zntg.MustHexColor(`FFFFFF1F`)
dialog.confirm.Text = "OK"
dialog.confirm.ButtonClicked().AddHandler(func(ctx ui.Context, _ ui.ControlClickedArgs) { dialog.userConfirmed(ctx) })
dialog.confirm.Type = ui.ButtonTypeText
dialog.confirm.HoverColor = zntg.MustHexColor(`FFFFFF1F`)
dialog.question.Text = question
dialog.updateActive()
responses := ui.BuildStackPanel(ui.OrientationHorizontal, func(p *ui.StackPanel) {
p.AddChild(ui.FixedWidth(&dialog.cancel, 160))
p.AddChild(ui.FixedWidth(&dialog.confirm, 160))
})
content := &dialogBase{}
content.Background = zntg.MustHexColor(`#0000007F`)
content.Init(caption, ui.BuildStackPanel(ui.OrientationVertical, func(p *ui.StackPanel) {
p.AddChild(&dialog.question)
p.AddChild(responses)
}))
dialog.Content = ui.Background(ui.BuildSpacing(content, func(s *ui.Spacing) {
s.Width = ui.Fixed(320)
s.Center()
}), zntg.MustHexColor(`#0000007F`))
return dialog
}
func (d *confirmationDialog) toggleActive() {
if d.active == "confirm" {
d.active = "cancel"
} else {
d.active = "confirm"
}
d.updateActive()
}
func (d *confirmationDialog) updateActive() {
d.cancel.Background = nil
d.confirm.Background = nil
switch d.active {
case "cancel":
d.cancel.Background = hoverTransparentColor
case "confirm":
d.confirm.Background = hoverTransparentColor
}
}
func (d *confirmationDialog) userCanceled(ctx ui.Context) {
d.userDecided.Notify(ctx, false)
}
func (d *confirmationDialog) userConfirmed(ctx ui.Context) {
d.userDecided.Notify(ctx, true)
}
func (d *confirmationDialog) Handle(ctx ui.Context, e ui.Event) bool {
if d.Proxy.Handle(ctx, e) {
return true
}
switch e := e.(type) {
case *ui.MouseButtonDownEvent:
if e.Button == ui.MouseButtonRight {
d.userCanceled(ctx)
return true
}
case *ui.MouseMoveEvent:
if d.cancel.IsOver() {
d.active = "cancel"
}
if d.confirm.IsOver() {
d.active = "confirm"
}
d.updateActive()
case *ui.KeyDownEvent:
switch e.Key {
case ui.KeyEscape:
d.userCanceled(ctx)
return true
case ui.KeyEnter:
switch d.active {
case "cancel":
d.userCanceled(ctx)
case "confirm":
d.userConfirmed(ctx)
}
return true
case ui.KeyLeft:
d.toggleActive()
case ui.KeyRight:
d.toggleActive()
case ui.KeyTab:
d.toggleActive()
}
}
return false
}
type dialogBase struct {
ui.StackPanel
caption ui.Label
content ui.Proxy
}
func (d *dialogBase) DesiredSize(ctx ui.Context, size geom.PointF32) geom.PointF32 {
return d.StackPanel.DesiredSize(ctx, size)
}
func (d *dialogBase) Init(caption string, content ui.Control) {
d.caption.Text = caption
d.content.Content = content
d.Children = []ui.Control{&d.caption, &d.content}
}

View File

@ -67,6 +67,20 @@ func (d *Dialogs) Hidden() {
d.Proxy.Hidden() d.Proxy.Hidden()
} }
func (d *Dialogs) AskConfirmation(ctx ui.Context, caption, question string, confirm, cancel ui.EventFn) {
dialog := newConfirmationDialog(caption, question)
dialog.userDecided.AddHandler(func(ctx ui.Context, state interface{}) {
decision := state.(bool)
if decision {
confirm(ctx, nil)
} else {
cancel(ctx, nil)
}
d.Close(ctx)
})
d.showDialog(ctx, dialog)
}
func (d *Dialogs) ShowIntro(ctx ui.Context) { func (d *Dialogs) ShowIntro(ctx ui.Context) {
d.showDialog(ctx, d.intro) d.showDialog(ctx, d.intro)
} }

View File

@ -32,6 +32,36 @@ func NewGameControls(game *Game, dialogs *Dialogs) *GameControls {
return &GameControls{game: game, dialogs: dialogs} return &GameControls{game: game, dialogs: dialogs}
} }
func (c *GameControls) askUserBeforeLoad(ctx ui.Context) {
c.dialogs.AskConfirmation(ctx,
"Do you want to load?",
"You will lose any progress you made during this session.",
func(ui.Context, interface{}) {
c.game.Load(ctx)
c.updateFlowerControls()
},
func(ui.Context, interface{}) {})
}
func (c *GameControls) askUserBeforeNew(ctx ui.Context) {
c.dialogs.AskConfirmation(ctx,
"Do you want to start a new game?",
"You will lose any progress you made during this session.",
func(ui.Context, interface{}) {
c.game.New(ctx)
c.updateFlowerControls()
},
func(ui.Context, interface{}) {})
}
func (c *GameControls) askUserBeforeSave(ctx ui.Context) {
c.dialogs.AskConfirmation(ctx,
"Do you want to save?",
"Saving will overwrite any previous save game.",
func(ui.Context, interface{}) { c.game.Save() },
func(ui.Context, interface{}) {})
}
func (c *GameControls) Init(ctx ui.Context) { func (c *GameControls) Init(ctx ui.Context) {
ctx.Overlays().AddOnTop(fpsOverlayName, &play.FPS{}, false) ctx.Overlays().AddOnTop(fpsOverlayName, &play.FPS{}, false)
c.game.SpeedChanged().AddHandler(c.speedChanged) c.game.SpeedChanged().AddHandler(c.speedChanged)
@ -76,20 +106,14 @@ func (c *GameControls) Init(ctx ui.Context) {
b.Disabled = true b.Disabled = true
b.DisabledColor = zntg.MustHexColor("#AFAFAF") b.DisabledColor = zntg.MustHexColor("#AFAFAF")
}), }),
NewIconButtonConfigure("control-save", func(ui.Context) { c.game.Save() }, func(b *IconButton) { NewIconButtonConfigure("control-save", c.askUserBeforeSave, func(b *IconButton) {
b.Tooltip = "Save game (overwrites previous save; no confirmation)" b.Tooltip = "Save game"
}), }),
NewIconButtonConfigure("control-load", func(ctx ui.Context) { NewIconButtonConfigure("control-load", c.askUserBeforeLoad, func(b *IconButton) {
c.game.Load(ctx) b.Tooltip = "Load last saved game"
c.updateFlowerControls()
}, func(b *IconButton) {
b.Tooltip = "Load last saved game (no confirmation)"
}), }),
NewIconButtonConfigure("control-new", func(ctx ui.Context) { NewIconButtonConfigure("control-new", c.askUserBeforeNew, func(b *IconButton) {
c.game.New(ctx) b.Tooltip = "Start new game"
c.updateFlowerControls()
}, func(b *IconButton) {
b.Tooltip = "Start new game (no confirmation)"
}), }),
NewIconButtonConfigure("control-information", c.dialogs.ShowIntro, func(b *IconButton) { NewIconButtonConfigure("control-information", c.dialogs.ShowIntro, func(b *IconButton) {
b.Tooltip = "Show information/intro" b.Tooltip = "Show information/intro"
@ -205,6 +229,16 @@ func (c *GameControls) Handle(ctx ui.Context, event ui.Event) bool {
c.game.Debug = !c.game.Debug c.game.Debug = !c.game.Debug
ctx.Overlays().Toggle(fpsOverlayName) ctx.Overlays().Toggle(fpsOverlayName)
} }
if e.Modifiers == ui.KeyModifierControl {
switch e.Key {
case ui.KeyL:
c.askUserBeforeLoad(ctx)
case ui.KeyN:
c.askUserBeforeNew(ctx)
case ui.KeyS:
c.askUserBeforeSave(ctx)
}
}
} }
return false return false
} }