doodle/pkg/main_scene.go
Noah Petherbridge f0101ba048 The Window Manager Update
* Take advantage of the new Window Manager feature of the UI toolkit.
* Move the MenuScene's "New Level" and "Play/Edit Level" windows into
  stand-alone functions in new pkg/windows/ package. The 'windows'
  package is isolated from the rest of Doodle and communicates using
  config variables and callback functions to avoid circular dependency.
* MenuScene calls the window constructors from the new package.
* Add an "Options" button to the Menu Bar in the Editor Scene, which
  opens the "New Level" window to allow changing the wallpaper or
  bounding type of the level currently being edited.
* Move the cheat codes into their own file, cheats.go
2020-04-06 23:21:17 -07:00

265 lines
5.7 KiB
Go

package doodle
import (
"fmt"
"git.kirsle.net/apps/doodle/pkg/balance"
"git.kirsle.net/apps/doodle/pkg/branding"
"git.kirsle.net/apps/doodle/pkg/level"
"git.kirsle.net/apps/doodle/pkg/log"
"git.kirsle.net/apps/doodle/pkg/native"
"git.kirsle.net/apps/doodle/pkg/scripting"
"git.kirsle.net/apps/doodle/pkg/uix"
"git.kirsle.net/apps/doodle/pkg/updater"
"git.kirsle.net/go/render"
"git.kirsle.net/go/render/event"
"git.kirsle.net/go/ui"
)
// MainScene implements the main menu of Doodle.
type MainScene struct {
Supervisor *ui.Supervisor
// Background wallpaper canvas.
scripting *scripting.Supervisor
canvas *uix.Canvas
// UI components.
labelTitle *ui.Label
labelVersion *ui.Label
frame *ui.Frame // Main button frame
// Update check variables.
updateButton *ui.Button
updateInfo updater.VersionInfo
}
// Name of the scene.
func (s *MainScene) Name() string {
return "Main"
}
// Setup the scene.
func (s *MainScene) Setup(d *Doodle) error {
s.Supervisor = ui.NewSupervisor()
if err := s.SetupDemoLevel(d); err != nil {
return err
}
// Main title label
s.labelTitle = ui.NewLabel(ui.Label{
Text: branding.AppName,
Font: render.Text{
Size: 46,
Color: render.Pink,
Stroke: render.SkyBlue,
Shadow: render.Black,
},
})
s.labelTitle.Compute(d.Engine)
// Version label.
var shareware string
if balance.FreeVersion {
shareware = " (shareware)"
}
ver := ui.NewLabel(ui.Label{
Text: fmt.Sprintf("v%s%s", branding.Version, shareware),
Font: render.Text{
Size: 18,
Color: render.Grey,
Shadow: render.Black,
},
})
ver.Compute(d.Engine)
s.labelVersion = ver
// "Update Available" button.
s.updateButton = ui.NewButton("Update Button", ui.NewLabel(ui.Label{
Text: "An update is available!",
Font: render.Text{
FontFilename: "DejaVuSans-Bold.ttf",
Size: 16,
Color: render.Blue,
Padding: 4,
},
}))
s.updateButton.Handle(ui.Click, func(ed ui.EventData) error {
native.OpenURL(s.updateInfo.DownloadURL)
return nil
})
s.updateButton.Compute(d.Engine)
s.updateButton.Hide()
s.Supervisor.Add(s.updateButton)
// Main UI button frame.
frame := ui.NewFrame("frame")
s.frame = frame
var buttons = []struct {
Name string
Func func()
}{
{
Name: "Play a Level",
Func: d.GotoPlayMenu,
},
{
Name: "Create a New Level",
Func: d.GotoNewMenu,
},
{
Name: "Edit a Level",
Func: d.GotoLoadMenu,
},
}
for _, button := range buttons {
button := button
btn := ui.NewButton(button.Name, ui.NewLabel(ui.Label{
Text: button.Name,
Font: balance.StatusFont,
}))
btn.Handle(ui.Click, func(ed ui.EventData) error {
button.Func()
return nil
})
s.Supervisor.Add(btn)
frame.Pack(btn, ui.Pack{
Side: ui.N,
PadY: 8,
// Fill: true,
FillX: true,
})
}
// Check for update in the background.
go s.checkUpdate()
return nil
}
// checkUpdate checks for a version update and shows the button.
func (s *MainScene) checkUpdate() {
info, err := updater.Check()
if err != nil {
log.Error(err.Error())
return
}
if info.LatestVersion != branding.Version {
s.updateInfo = info
s.updateButton.Show()
}
}
// SetupDemoLevel configures the wallpaper behind the New screen,
// which demos a title screen demo level.
func (s *MainScene) SetupDemoLevel(d *Doodle) error {
// Set up the background wallpaper canvas.
s.canvas = uix.NewCanvas(100, false)
s.canvas.Scrollable = true
s.canvas.Resize(render.Rect{
W: d.width,
H: d.height,
})
s.scripting = scripting.NewSupervisor()
s.canvas.SetScriptSupervisor(s.scripting)
// Title screen level to load.
if lvl, err := level.LoadFile("example1.level"); err == nil {
s.canvas.LoadLevel(d.Engine, lvl)
s.canvas.InstallActors(lvl.Actors)
// Load all actor scripts.
if err := s.scripting.InstallScripts(lvl); err != nil {
log.Error("Error with title screen level scripts: %s", err)
}
// Run all actors scripts main function to start them off.
if err := s.canvas.InstallScripts(); err != nil {
log.Error("Error running actor main() functions: %s", err)
}
} else {
log.Error("Error loading title-screen.level: %s", err)
}
return nil
}
// Loop the editor scene.
func (s *MainScene) Loop(d *Doodle, ev *event.State) error {
s.Supervisor.Loop(ev)
if err := s.scripting.Loop(); err != nil {
log.Error("MainScene.Loop: scripting.Loop: %s", err)
}
s.canvas.Loop(ev)
if ev.WindowResized {
w, h := d.Engine.WindowSize()
d.width = w
d.height = h
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 *MainScene) Draw(d *Doodle) error {
// Clear the canvas and fill it with white.
d.Engine.Clear(render.White)
s.canvas.Present(d.Engine, render.Origin)
// Draw a sheen over the level for clarity.
d.Engine.DrawBox(render.RGBA(255, 255, 254, 128), render.Rect{
X: 0,
Y: 0,
W: d.width,
H: d.height,
})
// App title label.
s.labelTitle.MoveTo(render.Point{
X: (d.width / 2) - (s.labelTitle.Size().W / 2),
Y: 120,
})
s.labelTitle.Present(d.Engine, s.labelTitle.Point())
// Version label
s.labelVersion.MoveTo(render.Point{
X: (d.width / 2) - (s.labelVersion.Size().W / 2),
Y: s.labelTitle.Point().Y + s.labelTitle.Size().H + 8,
})
s.labelVersion.Present(d.Engine, s.labelVersion.Point())
// Update button.
s.updateButton.MoveTo(render.Point{
X: 24,
Y: d.height - s.updateButton.Size().H - 24,
})
s.updateButton.Present(d.Engine, s.updateButton.Point())
s.frame.Compute(d.Engine)
s.frame.MoveTo(render.Point{
X: (d.width / 2) - (s.frame.Size().W / 2),
Y: 260,
})
s.frame.Present(d.Engine, s.frame.Point())
return nil
}
// Destroy the scene.
func (s *MainScene) Destroy() error {
return nil
}