diff --git a/config.go b/config.go index 4a27bbe..948aef6 100644 --- a/config.go +++ b/config.go @@ -27,6 +27,8 @@ type Config struct { Wrap bool // wether wraparound mode is in place or not ShowVersion bool UseShader bool // to use a shader to render alife cells + Restart bool + StartWithMenu bool // for internal profiling ProfileFile string @@ -209,3 +211,16 @@ func ParseCommandline() (*Config, error) { func (config *Config) TogglePaused() { config.Paused = !config.Paused } + +func (config *Config) ToggleDebugging() { + fmt.Println("DEBUG TOGGLED") + config.Debug = !config.Debug +} + +func (config *Config) ToggleInvert() { + config.Invert = !config.Invert +} + +func (config *Config) ToggleGridlines() { + config.NoGrid = !config.NoGrid +} diff --git a/game.go b/game.go index c4075aa..80cf691 100644 --- a/game.go +++ b/game.go @@ -24,6 +24,7 @@ func NewGame(config *Config, startscene SceneName) *Game { game.CurrentScene = startscene game.Scenes[Play] = NewPlayScene(game, config) game.Scenes[Menu] = NewMenuScene(game, config) + game.Scenes[Options] = NewOptionsScene(game, config) // setup environment ebiten.SetWindowSize(game.ScreenWidth, game.ScreenHeight) diff --git a/main.go b/main.go index abcfd31..2d86bff 100644 --- a/main.go +++ b/main.go @@ -12,6 +12,11 @@ import ( ) func main() { + dau := true + + if len(os.Args) > 1 { + dau = false + } config, err := ParseCommandline() if err != nil { log.Fatal(err) @@ -22,7 +27,11 @@ func main() { os.Exit(0) } - game := NewGame(config, Play) + start := Play + if dau { + start = Menu + } + game := NewGame(config, SceneName(start)) if config.ProfileFile != "" { // enable cpu profiling. Do NOT use q to stop the game but diff --git a/scene-menu.go b/scene-menu.go index a4c45ab..4c03b58 100644 --- a/scene-menu.go +++ b/scene-menu.go @@ -2,6 +2,7 @@ package main import ( "image/color" + "os" "github.com/ebitenui/ebitenui" "github.com/ebitenui/ebitenui/widget" @@ -16,6 +17,7 @@ type SceneMenu struct { Whoami SceneName Ui *ebitenui.UI FontColor color.RGBA + First bool } func NewMenuScene(game *Game, config *Config) Scene { @@ -64,28 +66,54 @@ func (scene *SceneMenu) Draw(screen *ebiten.Image) { } func (scene *SceneMenu) Init() { - rowContainer := NewRowContainer() + rowContainer := NewRowContainer("Main Menu") - pause := NewCheckbox("Pause", *FontRenderer.FontSmall, - func(args *widget.CheckboxChangedEventArgs) { - scene.Config.TogglePaused() + empty := NewMenuButton("Start with empty grid", + func(args *widget.ButtonClickedEventArgs) { + scene.Config.Empty = true + scene.Config.Restart = true + scene.SetNext(Play) }) - copy := NewMenuButton("Save Copy as RLE", *FontRenderer.FontSmall, + random := NewMenuButton("Start with random patterns", + func(args *widget.ButtonClickedEventArgs) { + scene.Config.Restart = true + scene.SetNext(Play) + }) + + copy := NewMenuButton("Save Copy as RLE", func(args *widget.ButtonClickedEventArgs) { scene.Config.Markmode = true scene.Config.Paused = true scene.SetNext(Play) }) - label := widget.NewText( - widget.TextOpts.Text("Menu", *FontRenderer.FontNormal, scene.FontColor), - widget.TextOpts.Position(widget.TextPositionCenter, widget.TextPositionCenter), - ) + options := NewMenuButton("Options", + func(args *widget.ButtonClickedEventArgs) { + scene.SetNext(Options) + }) - rowContainer.AddChild(label) - rowContainer.AddChild(pause) + separator1 := NewSeparator() + separator2 := NewSeparator() + + cancel := NewMenuButton("Close", + func(args *widget.ButtonClickedEventArgs) { + scene.SetNext(Play) + }) + + quit := NewMenuButton("Quit", + func(args *widget.ButtonClickedEventArgs) { + os.Exit(0) + }) + + rowContainer.AddChild(empty) + rowContainer.AddChild(random) + rowContainer.AddChild(separator1) + rowContainer.AddChild(options) rowContainer.AddChild(copy) + rowContainer.AddChild(separator2) + rowContainer.AddChild(cancel) + rowContainer.AddChild(quit) scene.Ui = &ebitenui.UI{ Container: rowContainer.Container(), diff --git a/scene-options.go b/scene-options.go new file mode 100644 index 0000000..0b6ca67 --- /dev/null +++ b/scene-options.go @@ -0,0 +1,114 @@ +package main + +import ( + "image/color" + + "github.com/ebitenui/ebitenui" + "github.com/ebitenui/ebitenui/widget" + "github.com/hajimehoshi/ebiten/v2" + "github.com/hajimehoshi/ebiten/v2/inpututil" +) + +type SceneOptions struct { + Game *Game + Config *Config + Next SceneName + Whoami SceneName + Ui *ebitenui.UI + FontColor color.RGBA +} + +func NewOptionsScene(game *Game, config *Config) Scene { + scene := &SceneOptions{ + Whoami: Options, + Game: game, + Next: Options, + Config: config, + FontColor: color.RGBA{255, 30, 30, 0xff}, + } + + scene.Init() + + return scene +} + +func (scene *SceneOptions) GetNext() SceneName { + return scene.Next +} + +func (scene *SceneOptions) ResetNext() { + scene.Next = scene.Whoami +} + +func (scene *SceneOptions) SetNext(next SceneName) { + scene.Next = next +} + +func (scene *SceneOptions) Clearscreen() bool { + return false +} + +func (scene *SceneOptions) Update() error { + scene.Ui.Update() + + if inpututil.IsKeyJustPressed(ebiten.KeyEscape) || inpututil.IsKeyJustPressed(ebiten.KeyQ) { + scene.SetNext(Play) + } + + return nil + +} + +func (scene *SceneOptions) Draw(screen *ebiten.Image) { + scene.Ui.Draw(screen) +} + +func (scene *SceneOptions) Init() { + rowContainer := NewRowContainer("Options") + + pause := NewCheckbox("Pause", + func(args *widget.CheckboxChangedEventArgs) { + scene.Config.TogglePaused() + }) + + debugging := NewCheckbox("Debugging", + func(args *widget.CheckboxChangedEventArgs) { + scene.Config.ToggleDebugging() + }) + var debug int + if scene.Config.Debug { + debug = 1 + } + debugging.SetState( + widget.WidgetState(debug), + ) + + invert := NewCheckbox("Invert", + func(args *widget.CheckboxChangedEventArgs) { + scene.Config.Invert = true + }) + + gridlines := NewCheckbox("Show grid lines", + func(args *widget.CheckboxChangedEventArgs) { + scene.Config.ToggleGridlines() + }) + + separator := NewSeparator() + + cancel := NewMenuButton("Close", + func(args *widget.ButtonClickedEventArgs) { + scene.SetNext(Menu) + }) + + rowContainer.AddChild(pause) + rowContainer.AddChild(debugging) + rowContainer.AddChild(invert) + rowContainer.AddChild(gridlines) + rowContainer.AddChild(separator) + rowContainer.AddChild(cancel) + + scene.Ui = &ebitenui.UI{ + Container: rowContainer.Container(), + } + +} diff --git a/scene-play.go b/scene-play.go index e654081..ffa5938 100644 --- a/scene-play.go +++ b/scene-play.go @@ -366,6 +366,12 @@ func (scene *ScenePlay) SaveRectRLE() { } func (scene *ScenePlay) Update() error { + if scene.Config.Restart { + scene.Config.Restart = false + scene.Init() + return nil + } + scene.CheckInput() scene.CheckDraggingInput() scene.CheckMarkInput() diff --git a/scene.go b/scene.go index c0fe759..276931f 100644 --- a/scene.go +++ b/scene.go @@ -22,4 +22,5 @@ type Scene interface { const ( Menu = iota // main top level menu Play // actual playing happens here + Options ) diff --git a/widgets.go b/widgets.go index 8e565d8..57bfaf2 100644 --- a/widgets.go +++ b/widgets.go @@ -5,12 +5,10 @@ import ( "github.com/ebitenui/ebitenui/image" "github.com/ebitenui/ebitenui/widget" - "golang.org/x/image/font" ) func NewMenuButton( text string, - face font.Face, action func(args *widget.ButtonClickedEventArgs)) *widget.Button { buttonImage, _ := LoadButtonImage() @@ -27,7 +25,7 @@ func NewMenuButton( widget.ButtonOpts.Image(buttonImage), - widget.ButtonOpts.Text(text, face, &widget.ButtonTextColor{ + widget.ButtonOpts.Text(text, *FontRenderer.FontSmall, &widget.ButtonTextColor{ Idle: color.NRGBA{0xdf, 0xf4, 0xff, 0xff}, }), @@ -44,7 +42,6 @@ func NewMenuButton( func NewCheckbox( text string, - face font.Face, action func(args *widget.CheckboxChangedEventArgs)) *widget.LabeledCheckbox { checkboxImage, _ := LoadCheckboxImage() @@ -52,12 +49,14 @@ func NewCheckbox( return widget.NewLabeledCheckbox( widget.LabeledCheckboxOpts.CheckboxOpts( - widget.CheckboxOpts.ButtonOpts(widget.ButtonOpts.Image(buttonImage)), + widget.CheckboxOpts.ButtonOpts( + widget.ButtonOpts.Image(buttonImage), + ), widget.CheckboxOpts.Image(checkboxImage), widget.CheckboxOpts.StateChangedHandler(action), ), widget.LabeledCheckboxOpts.LabelOpts( - widget.LabelOpts.Text(text, face, + widget.LabelOpts.Text(text, *FontRenderer.FontSmall, &widget.LabelColor{ Idle: color.NRGBA{0xdf, 0xf4, 0xff, 0xff}, }), @@ -65,6 +64,31 @@ func NewCheckbox( ) } +func NewSeparator() widget.PreferredSizeLocateableWidget { + c := widget.NewContainer( + widget.ContainerOpts.Layout(widget.NewRowLayout( + widget.RowLayoutOpts.Direction(widget.DirectionVertical), + widget.RowLayoutOpts.Padding(widget.Insets{ + Top: 20, + Bottom: 20, + }))), + widget.ContainerOpts.WidgetOpts( + widget.WidgetOpts.LayoutData( + widget.RowLayoutData{Stretch: true}))) + + c.AddChild(widget.NewGraphic( + widget.GraphicOpts.WidgetOpts(widget.WidgetOpts.LayoutData(widget.RowLayoutData{ + Stretch: true, + MaxHeight: 2, + })), + widget.GraphicOpts.ImageNineSlice( + image.NewNineSliceColor( + color.NRGBA{0xdf, 0xf4, 0xff, 0xff})), + )) + + return c +} + type RowContainer struct { Root *widget.Container Row *widget.Container @@ -79,11 +103,19 @@ func (container *RowContainer) Container() *widget.Container { } // set arg to false if no background needed -func NewRowContainer() *RowContainer { +func NewRowContainer(title string) *RowContainer { + buttonImageHover := image.NewNineSlice(Assets["button-9slice3"], [3]int{3, 3, 3}, [3]int{3, 3, 3}) + uiContainer := widget.NewContainer( widget.ContainerOpts.Layout(widget.NewAnchorLayout()), ) + titleLabel := widget.NewText( + widget.TextOpts.WidgetOpts(widget.WidgetOpts.LayoutData(widget.RowLayoutData{ + Stretch: true, + })), + widget.TextOpts.Text(title, *FontRenderer.FontNormal, color.NRGBA{0xdf, 0xf4, 0xff, 0xff})) + rowContainer := widget.NewContainer( widget.ContainerOpts.WidgetOpts( widget.WidgetOpts.LayoutData(widget.AnchorLayoutData{ @@ -96,8 +128,11 @@ func NewRowContainer() *RowContainer { widget.RowLayoutOpts.Padding(widget.NewInsetsSimple(20)), widget.RowLayoutOpts.Spacing(0), )), + widget.ContainerOpts.BackgroundImage(buttonImageHover), ) + rowContainer.AddChild(titleLabel) + uiContainer.AddChild(rowContainer) return &RowContainer{