doodle/pkg/menu_scene.go
Noah Petherbridge a06787411d Resolve circular import errors for Doodle++ plugin
* pkg/plus/dpp is the main plugin bridge, and defines nothing but an interface
  that defines the Doodle++ surface area (referring to internal game types such
  as doodad.Doodad or level.Level), but not their implementations.
  * dpp.Driver (an interface) is the main API that other parts of the game will
    call, for example "dpp.Driver.IsLevelSigned()"
  * plus_dpp.go and plus_foss.go provide the dpp.Driver implementation for their
    build; with plus_dpp.go generally forwarding function calls directly to the
    proprietary dpp package and plus_foss.go generally returning false/errors.
  * The bootstrap package simply assigns the above stub function to dpp.Driver
* pkg/plus/bootstrap is a package directly imported by main (in the doodle and
  doodad programs) and it works around circular dependency issues: this package
  simply assigns dpp.Driver to the DPP or FOSS version.

Miscellaneous fixes:

* File->Open in the editor and PlayScene will use the new Open Level window
  instead of loading the legacy GotoLoadMenu scene.
* Deprecated legacy scenes: d.GotoLoadMenu() and d.GotoPlayMenu().
* The doodle-admin program depends on the private dpp package, so can not be
  compiled in FOSS mode.
2024-04-18 22:12:56 -07:00

264 lines
6.2 KiB
Go

package doodle
import (
"git.kirsle.net/SketchyMaze/doodle/pkg/enum"
"git.kirsle.net/SketchyMaze/doodle/pkg/level"
"git.kirsle.net/SketchyMaze/doodle/pkg/log"
"git.kirsle.net/SketchyMaze/doodle/pkg/uix"
"git.kirsle.net/SketchyMaze/doodle/pkg/windows"
"git.kirsle.net/go/render"
"git.kirsle.net/go/render/event"
"git.kirsle.net/go/ui"
)
/*
MenuScene holds the main dialog menu UIs for:
* New Level
* Open Level
* Settings
DEPRECATED: migrate these prompts into popup windows to appear
on the MainScene or elsewhere as wanted.
*/
type MenuScene struct {
// Configuration.
StartupMenu string
NewDoodad bool
Supervisor *ui.Supervisor
// Private widgets.
window *ui.Window
// Background wallpaper canvas.
canvas *uix.Canvas
// Values for the New menu
newPageType string
newWallpaper string
// Values for the Load/Play menu.
loadForPlay bool // false = load for edit
}
// Name of the scene.
func (s *MenuScene) Name() string {
return "Menu"
}
// DebugGetWindow surfaces the underlying private window.
func (s *MenuScene) DebugGetWindow() *ui.Window {
return s.window
}
// 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)
}
// GotoNewDoodadMenu loads the MenuScene and shows the "New" window,
// but selected on the Doodad tab by default.
func (d *Doodle) GotoNewDoodadMenu() {
log.Info("Loading the MenuScene to the New window")
scene := &MenuScene{
StartupMenu: "new",
NewDoodad: true,
}
d.Goto(scene)
}
// GotoLoadMenu loads the MenuScene and shows the "Load" window.
//
// DEPRECATED: loads the old menu, in dev console run `$ d.GotoLoadMenu()` to see.
func (d *Doodle) GotoLoadMenu() {
log.Info("Loading the MenuScene to the Load window for Edit Mode")
scene := &MenuScene{
StartupMenu: "load",
}
d.Goto(scene)
}
// GotoPlayMenu loads the MenuScene and shows the "Load" window for playing a
// level, not editing it.
//
// DEPRECATED: loads the old menu, in dev console run `$ d.GotoPlayMenu()` to see.
func (d *Doodle) GotoPlayMenu() {
log.Info("Loading the MenuScene to the Load window for Play Mode")
scene := &MenuScene{
StartupMenu: "load",
loadForPlay: true,
}
d.Goto(scene)
}
// GotoSettingsMenu loads the settings screen.
func (d *Doodle) GotoSettingsMenu() {
log.Info("Loading the MenuScene to the Settings Menu")
scene := &MenuScene{
StartupMenu: "settings",
}
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: d.width,
H: d.height,
})
s.canvas.LoadLevel(&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
}
case "settings":
if err := s.setupSettingsWindow(d); err != nil {
return err
}
default:
d.FlashError("No Valid StartupMenu Given to MenuScene")
}
// Whatever window we got, give it window manager controls under Supervisor.
s.window.Supervise(s.Supervisor)
s.window.Compute(d.Engine)
// Center the window.
s.window.MoveTo(render.Point{
X: (d.width / 2) - (s.window.Size().W / 2),
Y: 60,
})
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(pageType level.PageType, wallpaper string) {
s.canvas.LoadLevel(&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 {
window := windows.NewAddEditLevel(windows.AddEditLevel{
Supervisor: s.Supervisor,
Engine: d.Engine,
NewDoodad: s.NewDoodad,
OnChangePageTypeAndWallpaper: func(pageType level.PageType, wallpaper string) {
log.Info("OnChangePageTypeAndWallpaper called: %+v, %+v", pageType, wallpaper)
s.canvas.Destroy() // clean up old textures
s.configureCanvas(pageType, wallpaper)
},
OnCreateNewLevel: func(lvl *level.Level) {
d.Goto(&EditorScene{
DrawingType: enum.LevelDrawing,
Level: lvl,
})
},
OnCreateNewDoodad: func(width, height int) {
d.NewDoodad(width, height)
},
OnCancel: func() {
d.Goto(&MainScene{})
},
})
s.window = window
window.SetButtons(0)
window.Show()
return nil
}
// setupLoadWindow sets up the UI for the "New" window.
func (s *MenuScene) setupLoadWindow(d *Doodle) error {
window := windows.NewOpenLevelEditor(windows.OpenLevelEditor{
Supervisor: s.Supervisor,
Engine: d.Engine,
LoadForPlay: s.loadForPlay,
OnPlayLevel: func(filename string) {
d.PlayLevel(filename)
},
OnEditLevel: func(filename string) {
d.EditFile(filename)
},
OnCancel: func() {
d.Goto(&MainScene{})
},
})
s.window = window
return nil
}
// setupLoadWindow sets up the UI for the "New" window.
func (s *MenuScene) setupSettingsWindow(d *Doodle) error {
window := windows.NewSettingsWindow(windows.Settings{
Supervisor: s.Supervisor,
Engine: d.Engine,
})
window.SetButtons(0)
s.window = window
return nil
}
// Loop the editor scene.
func (s *MenuScene) Loop(d *Doodle, ev *event.State) error {
s.Supervisor.Loop(ev)
if ev.WindowResized {
log.Info("Resized to %dx%d", d.width, d.height)
s.canvas.Resize(render.Rect{
W: d.width,
H: d.height,
})
}
return nil
}
// Draw the pixels on this frame.
func (s *MenuScene) Draw(d *Doodle) error {
// Draw the background canvas.
s.canvas.Present(d.Engine, render.Origin)
// TODO: if I don't call Compute here, buttons in the Edit Window get all
// bunched up. Investigate why later.
s.window.Compute(d.Engine)
// Draw the window managed by Supervisor.
s.Supervisor.Present(d.Engine)
return nil
}
// Destroy the scene.
func (s *MenuScene) Destroy() error {
// Free (wallpaper) textures.
s.canvas.Destroy()
return nil
}