2019-06-25 21:57:11 +00:00
|
|
|
package doodle
|
|
|
|
|
|
|
|
import (
|
2019-06-25 22:23:01 +00:00
|
|
|
"fmt"
|
|
|
|
|
2019-06-25 21:57:11 +00:00
|
|
|
"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"
|
2019-06-26 00:43:23 +00:00
|
|
|
"git.kirsle.net/apps/doodle/pkg/uix"
|
2019-06-25 22:23:01 +00:00
|
|
|
"git.kirsle.net/apps/doodle/pkg/userdir"
|
2019-06-25 21:57:11 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
/*
|
|
|
|
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
|
|
|
|
|
2019-06-26 00:43:23 +00:00
|
|
|
// Background wallpaper canvas.
|
|
|
|
canvas *uix.Canvas
|
|
|
|
|
2019-06-25 21:57:11 +00:00
|
|
|
// 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()
|
|
|
|
|
2019-06-26 00:43:23 +00:00
|
|
|
// 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",
|
|
|
|
})
|
|
|
|
|
2019-06-25 21:57:11 +00:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2019-06-26 00:43:23 +00:00
|
|
|
// 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,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2019-06-25 21:57:11 +00:00
|
|
|
// 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{
|
2019-06-26 00:43:23 +00:00
|
|
|
Width: int32(float64(d.width) * 0.75),
|
|
|
|
Height: int32(float64(d.height) * 0.75),
|
2019-06-25 21:57:11 +00:00
|
|
|
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,
|
|
|
|
})
|
|
|
|
|
2019-06-26 00:43:23 +00:00
|
|
|
type typeObj struct {
|
2019-06-25 21:57:11 +00:00
|
|
|
Name string
|
|
|
|
Value level.PageType
|
2019-06-26 00:43:23 +00:00
|
|
|
}
|
|
|
|
var types = []typeObj{
|
2019-06-25 21:57:11 +00:00
|
|
|
{"Unbounded", level.Unbounded},
|
|
|
|
{"Bounded", level.Bounded},
|
|
|
|
{"No Negative Space", level.NoNegativeSpace},
|
2019-06-26 01:10:57 +00:00
|
|
|
// {"Bordered (TODO)", level.Bordered},
|
2019-06-25 21:57:11 +00:00
|
|
|
}
|
|
|
|
for _, t := range types {
|
2019-06-26 01:10:57 +00:00
|
|
|
// TODO: Hide some options for the free version of the game.
|
|
|
|
// - At launch only Bounded and Bordered will be available
|
|
|
|
// in the shareware version.
|
|
|
|
// - For now, only hide Bordered as it's not yet implemented.
|
|
|
|
// --------
|
|
|
|
// if balance.FreeVersion {
|
|
|
|
// if t.Value == level.Bordered {
|
|
|
|
// continue
|
|
|
|
// }
|
|
|
|
// }
|
2019-06-25 21:57:11 +00:00
|
|
|
|
2019-06-26 00:43:23 +00:00
|
|
|
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)
|
2019-06-25 21:57:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/******************
|
|
|
|
* 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,
|
|
|
|
})
|
|
|
|
|
2019-06-26 00:43:23 +00:00
|
|
|
type wallpaperObj struct {
|
2019-06-25 21:57:11 +00:00
|
|
|
Name string
|
|
|
|
Value string
|
2019-06-26 00:43:23 +00:00
|
|
|
}
|
|
|
|
var wallpapers = []wallpaperObj{
|
2019-06-25 21:57:11 +00:00
|
|
|
{"Notebook", "notebook.png"},
|
|
|
|
{"Blueprint", "blueprint.png"},
|
|
|
|
{"Legal Pad", "legal.png"},
|
2019-06-26 01:10:57 +00:00
|
|
|
{"Pure White", "white.png"},
|
|
|
|
// {"Placemat", "placemat.png"},
|
2019-06-25 21:57:11 +00:00
|
|
|
}
|
|
|
|
for _, t := range wallpapers {
|
2019-06-26 00:43:23 +00:00
|
|
|
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)
|
2019-06-25 21:57:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/******************
|
|
|
|
* 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
|
|
|
|
|
2019-06-26 00:43:23 +00:00
|
|
|
// Blueprint theme palette for the dark wallpaper color.
|
|
|
|
if lvl.Wallpaper == "blueprint.png" {
|
|
|
|
lvl.Palette = level.NewBlueprintPalette()
|
|
|
|
}
|
|
|
|
|
2019-06-25 21:57:11 +00:00
|
|
|
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 {
|
2019-06-25 22:23:01 +00:00
|
|
|
window := ui.NewWindow("Open Drawing")
|
|
|
|
window.Configure(ui.Config{
|
2019-06-26 00:43:23 +00:00
|
|
|
Width: int32(float64(d.width) * 0.75),
|
|
|
|
Height: int32(float64(d.height) * 0.75),
|
2019-06-25 22:23:01 +00:00
|
|
|
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,
|
|
|
|
})
|
|
|
|
|
2019-06-27 22:07:34 +00:00
|
|
|
// Get the user's levels.
|
2019-06-25 22:23:01 +00:00
|
|
|
levels, _ := userdir.ListLevels()
|
2019-06-27 22:07:34 +00:00
|
|
|
|
|
|
|
// Embedded levels, TODO
|
|
|
|
sysLevels, _ := level.ListSystemLevels()
|
|
|
|
levels = append(levels, sysLevels...)
|
|
|
|
|
2019-06-25 22:23:01 +00:00
|
|
|
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
|
2019-06-25 21:57:11 +00:00
|
|
|
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)
|
|
|
|
|
2019-06-26 00:43:23 +00:00
|
|
|
// Draw the background canvas.
|
|
|
|
s.canvas.Present(d.Engine, render.Origin)
|
|
|
|
|
2019-06-25 21:57:11 +00:00
|
|
|
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
|
|
|
|
}
|