doodle/pkg/windows/publish_level.go
Noah Petherbridge c5e3fc297c Manage Embedded Files In Levels
In the Level Editor, the "Level->Attached files" menu opens the
FileSystem Window, which shows a paginated list of attached files and a
"Delete" button to remove them.

- Custom doodads which also exist locally can be deleted from the
  level's filesystem at any time.
- If a custom doodad does NOT exist locally, and one of them is still
  placed somewhere within the level, you can not delete it.
- You can't delete the custom wallpaper image IF the level is still
  using it. Change to a default wallpaper and then you can delete the
  custom wallpaper image.
2021-06-13 16:03:32 -07:00

297 lines
5.9 KiB
Go

package windows
import (
"fmt"
"math"
"strings"
"git.kirsle.net/apps/doodle/pkg/balance"
"git.kirsle.net/apps/doodle/pkg/level"
"git.kirsle.net/apps/doodle/pkg/level/publishing"
"git.kirsle.net/apps/doodle/pkg/log"
"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 = 400
windowHeight = 300
page = 1
perPage = 4
pages = 1
maxPageButtons = 8
// 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),
})
/////////////
// Intro text
introFrame := ui.NewFrame("Intro Frame")
window.Pack(introFrame, ui.Pack{
Side: ui.N,
FillX: true,
})
lines := []struct {
Text string
Font render.Text
}{
{
Text: "About",
Font: balance.LabelFont,
},
{
Text: "Share your level easily! If you are using custom doodads in\n" +
"your level, you may attach them directly to your\n" +
"level file -- so it can easily run on another computer!",
Font: balance.UIFont,
},
{
Text: "List of Doodads in Your Level",
Font: balance.LabelFont,
},
}
for n, row := range lines {
frame := ui.NewFrame(fmt.Sprintf("Intro Line %d", n))
introFrame.Pack(frame, ui.Pack{
Side: ui.N,
FillX: true,
})
label := ui.NewLabel(ui.Label{
Text: row.Text,
Font: row.Font,
})
frame.Pack(label, ui.Pack{
Side: ui.W,
})
}
/////////////
// Custom Doodads checkbox-list.
doodadFrame := ui.NewFrame("Doodads Frame")
doodadFrame.Resize(render.Rect{
W: windowWidth,
H: btnHeight*perPage + 100,
})
window.Pack(doodadFrame, ui.Pack{
Side: ui.N,
FillX: true,
})
// First, the checkbox to show built-in doodads or not.
builtinRow := ui.NewFrame("Show Builtins Frame")
doodadFrame.Pack(builtinRow, ui.Pack{
Side: ui.N,
FillX: true,
})
builtinCB := ui.NewCheckbox("Show Builtins", &cfg.includeBuiltins, ui.NewLabel(ui.Label{
Text: "Attach built-in* doodads too",
Font: balance.UIFont,
}))
builtinCB.Supervise(cfg.Supervisor)
builtinRow.Pack(builtinCB, ui.Pack{
Side: ui.W,
PadX: 2,
})
// 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()
}
}
/////////////
// Buttons at bottom of window
bottomFrame := ui.NewFrame("Button Frame")
window.Pack(bottomFrame, ui.Pack{
Side: ui.S,
FillX: true,
})
// 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.Compute(cfg.Engine)
pager.Supervise(cfg.Supervisor)
bottomFrame.Place(pager, ui.Place{
Top: 20,
Left: 20,
})
frame := ui.NewFrame("Button frame")
buttons := []struct {
label string
primary bool
f func()
}{
{"Export Level", true, func() {
if cfg.OnPublish != nil {
cfg.OnPublish(cfg.includeBuiltins)
}
}},
{"Close", false, func() {
if cfg.OnCancel != nil {
cfg.OnCancel()
}
}},
}
for _, button := range buttons {
button := button
btn := ui.NewButton(button.label, ui.NewLabel(ui.Label{
Text: button.label,
Font: balance.MenuFont,
}))
if button.primary {
btn.SetStyle(&balance.ButtonPrimary)
}
btn.Handle(ui.Click, func(ed ui.EventData) error {
button.f()
return nil
})
btn.Compute(cfg.Engine)
cfg.Supervisor.Add(btn)
frame.Pack(btn, ui.Pack{
Side: ui.W,
PadX: 4,
Expand: true,
Fill: true,
})
}
bottomFrame.Pack(frame, ui.Pack{
Side: ui.E,
Padding: 8,
})
return window
}