Noah Petherbridge
3d3561b8e6
* 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.
492 lines
11 KiB
Go
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
|
|
}
|