doodle/pkg/windows/publish_level.go
Noah Petherbridge 79996ccd34 ListBoxes Overhaul
* Overhaul the clunky old alpha Edit Level/Doodad menu with a modernized
  version featuring the new ListBox widget.
* The new level loader is a Window that can be spawned from anywhere instead
  of on a dedicated MenuScene.

Updates to doodad scripts:

* Actor.IsOnScreen() checks whether an actor's visual sprite box is on-screen
  in the level viewport. `Self.IsOnScreen()` will check for the current actor.

Other changes

* PlaySound() to deduplicate the same sound effect from playing at once.
2023-04-08 21:26:08 -07:00

261 lines
5.6 KiB
Go

package windows
import (
"fmt"
"math"
"strings"
"git.kirsle.net/SketchyMaze/doodle/pkg/balance"
"git.kirsle.net/SketchyMaze/doodle/pkg/level"
"git.kirsle.net/SketchyMaze/doodle/pkg/level/publishing"
"git.kirsle.net/SketchyMaze/doodle/pkg/log"
magicform "git.kirsle.net/SketchyMaze/doodle/pkg/uix/magic-form"
"git.kirsle.net/go/render"
"git.kirsle.net/go/ui"
)
// Publish window.
type Publish struct {
// Settings passed in by doodle
Supervisor *ui.Supervisor
Engine render.Engine
Level *level.Level
OnPublish func(builtinToo bool)
OnCancel func()
// Private vars.
includeBuiltins bool // show built-in doodads in checkbox-list.
}
// NewPublishWindow initializes the window.
func NewPublishWindow(cfg Publish) *ui.Window {
var (
windowWidth = 380
windowHeight = 220
page = 1
perPage = 3 // rows of `columns`
pages = 1
maxPageButtons = 12
// columns and sizes to draw the doodad list
columns = 3
btnWidth = 120
btnHeight = 14
)
window := ui.NewWindow("Publish Level")
window.SetButtons(ui.CloseButton)
window.Configure(ui.Config{
Width: windowWidth,
Height: windowHeight,
Background: render.RGBA(200, 200, 255, 255),
})
/////////////
// Custom Doodads checkbox-list.
doodadFrame := ui.NewFrame("Doodads Frame")
doodadFrame.Resize(render.Rect{
W: windowWidth,
H: btnHeight*perPage + 40,
})
// Collect the doodads named in this level.
usedBuiltins, usedCustom := publishing.GetUsedDoodadNames(cfg.Level)
// Helper function to draw the button rows for a set of doodads.
mkDoodadRows := func(filenames []string, builtin bool) []*ui.Frame {
var (
curRow *ui.Frame // = ui.NewFrame("mkDoodadRows 0")
frames = []*ui.Frame{}
)
for i, name := range filenames {
if i%columns == 0 {
curRow = ui.NewFrame(fmt.Sprintf("mkDoodadRows %d", i))
frames = append(frames, curRow)
}
font := balance.UIFont
if builtin {
font.Color = render.Blue
name += "*"
}
btn := ui.NewLabel(ui.Label{
Text: strings.Replace(name, ".doodad", "", 1),
Font: font,
})
btn.Configure(ui.Config{
Width: btnWidth,
Height: btnHeight,
})
curRow.Pack(btn, ui.Pack{
Side: ui.W,
PadX: 2,
PadY: 2,
})
}
return frames
}
// 1. Draw the built-in doodads in use.
var (
btnRows = []*ui.Frame{}
builtinRows = []*ui.Frame{}
customRows = []*ui.Frame{}
)
if len(usedCustom) > 0 {
customRows = mkDoodadRows(usedCustom, false)
btnRows = append(btnRows, customRows...)
}
if len(usedBuiltins) > 0 {
builtinRows = mkDoodadRows(usedBuiltins, true)
btnRows = append(btnRows, builtinRows...)
}
for i, row := range btnRows {
doodadFrame.Pack(row, ui.Pack{
Side: ui.N,
FillX: true,
})
// Hide if too long for 1st page.
if i >= perPage {
row.Hide()
}
}
// Pager for the doodads.
pages = int(
math.Ceil(
float64(len(btnRows)) / float64(perPage),
),
)
pagerOnChange := func(newPage, perPage int) {
page = newPage
log.Info("Page: %d, %d", page, perPage)
// Re-evaluate which rows are shown/hidden for the page we're on.
var (
minRow = (page - 1) * perPage
visible = 0
)
for i, row := range btnRows {
if visible >= perPage {
row.Hide()
continue
}
if i < minRow {
row.Hide()
} else {
row.Show()
visible++
}
}
}
pager := ui.NewPager(ui.Pager{
Name: "Doodads List Pager",
Page: page,
Pages: pages,
PerPage: perPage,
MaxPageButtons: maxPageButtons,
Font: balance.MenuFont,
OnChange: pagerOnChange,
})
_ = pager
/////////////
// Intro text
introFrame := ui.NewFrame("Intro Frame")
window.Pack(introFrame, ui.Pack{
Side: ui.N,
FillX: true,
})
// Render the form, putting it all together.
form := magicform.Form{
Supervisor: cfg.Supervisor,
Engine: cfg.Engine,
Vertical: true,
LabelWidth: 100,
}
form.Create(introFrame, []magicform.Field{
{
Label: "About",
Font: balance.LabelFont,
},
{
Label: "Share your level easily! If you are using custom doodads in\n" +
"your level, you may attach them directly to your level file\n" +
"so it can easily run on another computer!",
Font: balance.UIFont,
},
{
Label: "Attach custom doodads when I save the level",
Font: balance.UIFont,
BoolVariable: &cfg.Level.SaveDoodads,
},
{
Label: "Attach built-in doodads too",
Font: balance.UIFont.Update(render.Text{
Color: render.Red,
}),
BoolVariable: &cfg.Level.SaveBuiltins,
Tooltip: ui.Tooltip{
Edge: ui.Top,
Text: "If enabled, the attached doodads will override the built-ins\n" +
"for this level. Bugfixes or updates to the built-ins will not\n" +
"affect your level, either.",
},
},
{
Label: "The above settings are saved with your level file, and each\n" +
"time you save, custom doodads will be re-attached.",
Font: balance.UIFont,
},
// Pager is broken, Supervisor doesn't pick it up, TODO
{
Label: "Doodads currently used on this level:",
Font: balance.LabelFont,
},
{
Frame: doodadFrame,
},
{
Label: "* Built-in doodad",
Font: balance.UIFont,
},
{
Pager: pager,
},
{
Buttons: []magicform.Field{
{
ButtonStyle: &balance.ButtonPrimary,
Label: "Save Level Now",
OnClick: func() {
if cfg.OnPublish != nil {
cfg.OnPublish(cfg.includeBuiltins)
}
},
},
{
Type: magicform.Button,
Label: "Close",
OnClick: func() {
if cfg.OnCancel != nil {
cfg.OnCancel()
}
},
},
},
},
})
return window
}