doodle/pkg/menu_scene.go
Noah Petherbridge 3d3561b8e6 Blueprint Theme Palette
* Fix the EditorUI not showing the correct palette baked into the level
  and only showing the default. This was tricky because the palette UI
  can only be configured at setup time but not updated later.
* Add a new default palette for the Blueprint theme. Blueprint has a
  dark background, so the palette colors should be bright. This palette
  is chosen when you start a map with the blueprint wallpaper.
* Add a background Canvas to the MenuScene. In the "New Level" screen,
  the background canvas will update to show the wallpaper settings
  you've chosen as a preview of the level theme you're about to create.
2019-06-25 17:43:23 -07:00

492 lines
11 KiB
Go

package doodle
import (
"fmt"
"git.kirsle.net/apps/doodle/lib/events"
"git.kirsle.net/apps/doodle/lib/render"
"git.kirsle.net/apps/doodle/lib/ui"
"git.kirsle.net/apps/doodle/pkg/balance"
"git.kirsle.net/apps/doodle/pkg/enum"
"git.kirsle.net/apps/doodle/pkg/level"
"git.kirsle.net/apps/doodle/pkg/log"
"git.kirsle.net/apps/doodle/pkg/uix"
"git.kirsle.net/apps/doodle/pkg/userdir"
)
/*
MenuScene holds the main dialog menu UIs for:
* New Level
* Open Level
* Settings
*/
type MenuScene struct {
// Configuration.
StartupMenu string
Supervisor *ui.Supervisor
// Private widgets.
window *ui.Window
// Background wallpaper canvas.
canvas *uix.Canvas
// Values for the New menu
newPageType string
newWallpaper string
}
// Name of the scene.
func (s *MenuScene) Name() string {
return "Menu"
}
// GotoNewMenu loads the MenuScene and shows the "New" window.
func (d *Doodle) GotoNewMenu() {
log.Info("Loading the MenuScene to the New window")
scene := &MenuScene{
StartupMenu: "new",
}
d.Goto(scene)
}
// GotoLoadMenu loads the MenuScene and shows the "Load" window.
func (d *Doodle) GotoLoadMenu() {
log.Info("Loading the MenuScene to the Load window")
scene := &MenuScene{
StartupMenu: "load",
}
d.Goto(scene)
}
// Setup the scene.
func (s *MenuScene) Setup(d *Doodle) error {
s.Supervisor = ui.NewSupervisor()
// Set up the background wallpaper canvas.
s.canvas = uix.NewCanvas(100, false)
s.canvas.Resize(render.Rect{
W: int32(d.width),
H: int32(d.height),
})
s.canvas.LoadLevel(d.Engine, &level.Level{
Chunker: level.NewChunker(100),
Palette: level.NewPalette(),
PageType: level.Bounded,
Wallpaper: "notebook.png",
})
switch s.StartupMenu {
case "new":
if err := s.setupNewWindow(d); err != nil {
return err
}
case "load":
if err := s.setupLoadWindow(d); err != nil {
return err
}
default:
d.Flash("No Valid StartupMenu Given to MenuScene")
}
return nil
}
// configureCanvas updates the settings of the background canvas, so a live
// preview of the wallpaper and wrapping type can be shown.
func (s *MenuScene) configureCanvas(e render.Engine, pageType level.PageType, wallpaper string) {
s.canvas.LoadLevel(e, &level.Level{
Chunker: level.NewChunker(100),
Palette: level.NewPalette(),
PageType: pageType,
Wallpaper: wallpaper,
})
}
// setupNewWindow sets up the UI for the "New" window.
func (s *MenuScene) setupNewWindow(d *Doodle) error {
// Default scene options.
s.newPageType = level.Bounded.String()
s.newWallpaper = "notebook.png"
window := ui.NewWindow("New Drawing")
window.Configure(ui.Config{
Width: int32(float64(d.width) * 0.75),
Height: int32(float64(d.height) * 0.75),
Background: render.Grey,
})
window.Compute(d.Engine)
{
frame := ui.NewFrame("New Level Frame")
window.Pack(frame, ui.Pack{
Anchor: ui.N,
Fill: true,
Expand: true,
})
/******************
* Frame for selecting Page Type
******************/
label1 := ui.NewLabel(ui.Label{
Text: "Page Type",
Font: balance.LabelFont,
})
frame.Pack(label1, ui.Pack{
Anchor: ui.N,
FillX: true,
})
typeFrame := ui.NewFrame("Page Type Options Frame")
frame.Pack(typeFrame, ui.Pack{
Anchor: ui.N,
FillX: true,
})
type typeObj struct {
Name string
Value level.PageType
}
var types = []typeObj{
{"Unbounded", level.Unbounded},
{"Bounded", level.Bounded},
{"No Negative Space", level.NoNegativeSpace},
{"Bordered", level.Bordered},
}
for _, t := range types {
// Hide some options for the free version of the game.
if balance.FreeVersion {
if t.Value != level.Bounded {
continue
}
}
func(t typeObj) {
radio := ui.NewRadioButton(t.Name,
&s.newPageType,
t.Value.String(),
ui.NewLabel(ui.Label{
Text: t.Name,
Font: balance.MenuFont,
}),
)
radio.Handle(ui.Click, func(p render.Point) {
s.configureCanvas(d.Engine, t.Value, s.newWallpaper)
})
s.Supervisor.Add(radio)
typeFrame.Pack(radio, ui.Pack{
Anchor: ui.W,
PadX: 4,
})
}(t)
}
/******************
* Frame for selecting Level Wallpaper
******************/
label2 := ui.NewLabel(ui.Label{
Text: "Wallpaper",
Font: balance.LabelFont,
})
frame.Pack(label2, ui.Pack{
Anchor: ui.N,
FillX: true,
})
wpFrame := ui.NewFrame("Wallpaper Frame")
frame.Pack(wpFrame, ui.Pack{
Anchor: ui.N,
FillX: true,
})
type wallpaperObj struct {
Name string
Value string
}
var wallpapers = []wallpaperObj{
{"Notebook", "notebook.png"},
{"Blueprint", "blueprint.png"},
{"Legal Pad", "legal.png"},
{"Placemat", "placemat.png"},
}
for _, t := range wallpapers {
func(t wallpaperObj) {
radio := ui.NewRadioButton(t.Name, &s.newWallpaper, t.Value, ui.NewLabel(ui.Label{
Text: t.Name,
Font: balance.MenuFont,
}))
radio.Handle(ui.Click, func(p render.Point) {
log.Info("Set wallpaper to %s", t.Value)
if pageType, ok := level.PageTypeFromString(s.newPageType); ok {
s.configureCanvas(d.Engine, pageType, t.Value)
}
})
s.Supervisor.Add(radio)
wpFrame.Pack(radio, ui.Pack{
Anchor: ui.W,
PadX: 4,
})
}(t)
}
/******************
* Confirm/cancel buttons.
******************/
bottomFrame := ui.NewFrame("Button Frame")
// bottomFrame.Configure(ui.Config{
// BorderSize: 1,
// BorderStyle: ui.BorderSunken,
// BorderColor: render.Black,
// })
// bottomFrame.SetBackground(render.Grey)
frame.Pack(bottomFrame, ui.Pack{
Anchor: ui.N,
FillX: true,
PadY: 8,
})
var buttons = []struct {
Label string
F func(render.Point)
}{
{"Continue", func(p render.Point) {
d.Flash("Create new map with %s page type and %s wallpaper", s.newPageType, s.newWallpaper)
pageType, ok := level.PageTypeFromString(s.newPageType)
if !ok {
d.Flash("Invalid Page Type '%s'", s.newPageType)
return
}
lvl := level.New()
lvl.Palette = level.DefaultPalette()
lvl.Wallpaper = s.newWallpaper
lvl.PageType = pageType
// Blueprint theme palette for the dark wallpaper color.
if lvl.Wallpaper == "blueprint.png" {
lvl.Palette = level.NewBlueprintPalette()
}
d.Goto(&EditorScene{
DrawingType: enum.LevelDrawing,
Level: lvl,
})
}},
{"Cancel", func(p render.Point) {
d.Goto(&MainScene{})
}},
}
for _, t := range buttons {
btn := ui.NewButton(t.Label, ui.NewLabel(ui.Label{
Text: t.Label,
Font: balance.MenuFont,
}))
btn.Handle(ui.Click, t.F)
s.Supervisor.Add(btn)
bottomFrame.Pack(btn, ui.Pack{
Anchor: ui.W,
PadX: 4,
PadY: 8,
})
}
}
s.window = window
return nil
}
// setupLoadWindow sets up the UI for the "New" window.
func (s *MenuScene) setupLoadWindow(d *Doodle) error {
window := ui.NewWindow("Open Drawing")
window.Configure(ui.Config{
Width: int32(float64(d.width) * 0.75),
Height: int32(float64(d.height) * 0.75),
Background: render.Grey,
})
window.Compute(d.Engine)
{
frame := ui.NewFrame("Open Drawing Frame")
window.Pack(frame, ui.Pack{
Anchor: ui.N,
Fill: true,
Expand: true,
})
/******************
* Frame for selecting User Levels
******************/
label1 := ui.NewLabel(ui.Label{
Text: "Levels",
Font: balance.LabelFont,
})
frame.Pack(label1, ui.Pack{
Anchor: ui.N,
FillX: true,
})
levels, _ := userdir.ListLevels()
lvlRow := ui.NewFrame("Level Row 0")
frame.Pack(lvlRow, ui.Pack{
Anchor: ui.N,
FillX: true,
PadY: 1,
})
for i, lvl := range levels {
func(i int, lvl string) {
log.Info("Add file %s to row %s", lvl, lvlRow.Name)
btn := ui.NewButton("Level Btn", ui.NewLabel(ui.Label{
Text: lvl,
Font: balance.MenuFont,
}))
btn.Handle(ui.Click, func(p render.Point) {
d.EditFile(lvl)
})
s.Supervisor.Add(btn)
lvlRow.Pack(btn, ui.Pack{
Anchor: ui.W,
Expand: true,
Fill: true,
})
if i > 0 && (i+1)%4 == 0 {
log.Warn("i=%d wrapped at mod 4", i)
lvlRow = ui.NewFrame(fmt.Sprintf("Level Row %d", i))
frame.Pack(lvlRow, ui.Pack{
Anchor: ui.N,
FillX: true,
PadY: 1,
})
}
}(i, lvl)
}
/******************
* Frame for selecting User Doodads
******************/
if !balance.FreeVersion {
label2 := ui.NewLabel(ui.Label{
Text: "Doodads",
Font: balance.LabelFont,
})
frame.Pack(label2, ui.Pack{
Anchor: ui.N,
FillX: true,
})
files, _ := userdir.ListDoodads()
ddRow := ui.NewFrame("Doodad Row 0")
frame.Pack(ddRow, ui.Pack{
Anchor: ui.N,
FillX: true,
PadY: 1,
})
for i, dd := range files {
func(i int, dd string) {
btn := ui.NewButton("Doodad Btn", ui.NewLabel(ui.Label{
Text: dd,
Font: balance.MenuFont,
}))
btn.Handle(ui.Click, func(p render.Point) {
d.EditFile(dd)
})
s.Supervisor.Add(btn)
ddRow.Pack(btn, ui.Pack{
Anchor: ui.W,
Expand: true,
Fill: true,
})
if i > 0 && (i+1)%4 == 0 {
ddRow = ui.NewFrame(fmt.Sprintf("Doodad Row %d", i))
frame.Pack(ddRow, ui.Pack{
Anchor: ui.N,
FillX: true,
PadY: 1,
})
}
}(i, dd)
}
}
/******************
* Confirm/cancel buttons.
******************/
bottomFrame := ui.NewFrame("Button Frame")
// bottomFrame.Configure(ui.Config{
// BorderSize: 1,
// BorderStyle: ui.BorderSunken,
// BorderColor: render.Black,
// })
// bottomFrame.SetBackground(render.Grey)
frame.Pack(bottomFrame, ui.Pack{
Anchor: ui.N,
FillX: true,
PadY: 8,
})
var buttons = []struct {
Label string
F func(render.Point)
}{
{"Cancel", func(p render.Point) {
d.Goto(&MainScene{})
}},
}
for _, t := range buttons {
btn := ui.NewButton(t.Label, ui.NewLabel(ui.Label{
Text: t.Label,
Font: balance.MenuFont,
}))
btn.Handle(ui.Click, t.F)
s.Supervisor.Add(btn)
bottomFrame.Pack(btn, ui.Pack{
Anchor: ui.W,
PadX: 4,
PadY: 8,
})
}
}
s.window = window
return nil
}
// Loop the editor scene.
func (s *MenuScene) Loop(d *Doodle, ev *events.State) error {
s.Supervisor.Loop(ev)
return nil
}
// Draw the pixels on this frame.
func (s *MenuScene) Draw(d *Doodle) error {
// Clear the canvas and fill it with white.
d.Engine.Clear(render.White)
// Draw the background canvas.
s.canvas.Present(d.Engine, render.Origin)
s.window.Compute(d.Engine)
s.window.MoveTo(render.Point{
X: (int32(d.width) / 2) - (s.window.Size().W / 2),
Y: 60,
})
s.window.Present(d.Engine, s.window.Point())
return nil
}
// Destroy the scene.
func (s *MenuScene) Destroy() error {
return nil
}