Noah Petherbridge
678326540b
The title screen is now responsive to landscape mode. If the window is not tall enough to show all the menu buttons (~600px) it will switch to a horizontal layout with the title on the left and buttons on the right. WIP "Story Mode" button that brings up a Level Packs selection window.
259 lines
5.4 KiB
Go
259 lines
5.4 KiB
Go
package windows
|
|
|
|
import (
|
|
"fmt"
|
|
"math"
|
|
|
|
"git.kirsle.net/apps/doodle/pkg/balance"
|
|
"git.kirsle.net/apps/doodle/pkg/levelpack"
|
|
"git.kirsle.net/apps/doodle/pkg/log"
|
|
"git.kirsle.net/go/render"
|
|
"git.kirsle.net/go/ui"
|
|
)
|
|
|
|
// LevelPack window lets the user open and play a level from a pack.
|
|
type LevelPack struct {
|
|
Supervisor *ui.Supervisor
|
|
Engine render.Engine
|
|
|
|
// Callback functions.
|
|
OnPlayLevel func(levelpack, filename string)
|
|
|
|
// Internal variables
|
|
window *ui.Window
|
|
gotoIndex func() // return to index screen
|
|
}
|
|
|
|
// NewLevelPackWindow initializes the window.
|
|
func NewLevelPackWindow(config LevelPack) *ui.Window {
|
|
// Default options.
|
|
var (
|
|
title = "Select a Level"
|
|
|
|
// size of the popup window
|
|
width = 320
|
|
height = 300
|
|
)
|
|
|
|
window := ui.NewWindow(title)
|
|
window.SetButtons(ui.CloseButton)
|
|
window.Configure(ui.Config{
|
|
Width: width,
|
|
Height: height,
|
|
Background: render.Grey,
|
|
})
|
|
config.window = window
|
|
|
|
frame := ui.NewFrame("Window Body Frame")
|
|
window.Pack(frame, ui.Pack{
|
|
Side: ui.N,
|
|
Fill: true,
|
|
Expand: true,
|
|
})
|
|
|
|
// We'll divide this window into "Screens", where the default
|
|
// screen shows the available level packs and then each level
|
|
// pack gets its own screen showing its levels.
|
|
var indexScreen *ui.Frame
|
|
config.gotoIndex = func() {
|
|
indexScreen.Show()
|
|
}
|
|
indexScreen = config.makeIndexScreen(width, height, func(screen *ui.Frame) {
|
|
// Callback for user choosing a level pack.
|
|
// Hide the index screen and show the screen for this pack.
|
|
indexScreen.Hide()
|
|
screen.Show()
|
|
})
|
|
window.Pack(indexScreen, ui.Pack{
|
|
Side: ui.N,
|
|
Fill: true,
|
|
Expand: true,
|
|
})
|
|
|
|
window.Supervise(config.Supervisor)
|
|
window.Hide()
|
|
return window
|
|
}
|
|
|
|
// Index screen for the LevelPack window.
|
|
func (config LevelPack) makeIndexScreen(width, height int, onChoose func(*ui.Frame)) *ui.Frame {
|
|
var (
|
|
buttonHeight = 60 // height of each LevelPack button
|
|
buttonWidth = width - 40
|
|
|
|
// pagination values
|
|
page = 1
|
|
pages int
|
|
perPage = 3
|
|
maxPageButtons = 10
|
|
)
|
|
frame := ui.NewFrame("Index Screen")
|
|
|
|
label := ui.NewLabel(ui.Label{
|
|
Text: "Select from a Level Pack below:",
|
|
Font: balance.LabelFont,
|
|
})
|
|
frame.Pack(label, ui.Pack{
|
|
Side: ui.N,
|
|
PadX: 8,
|
|
PadY: 8,
|
|
})
|
|
|
|
// Get the available .levelpack files.
|
|
lpFiles, err := levelpack.ListFiles()
|
|
if err != nil {
|
|
log.Error("Couldn't list levelpack files: %s", err)
|
|
}
|
|
|
|
pages = int(
|
|
math.Ceil(
|
|
float64(len(lpFiles)) / float64(perPage),
|
|
),
|
|
)
|
|
|
|
var buttons []*ui.Button
|
|
for i, filename := range lpFiles {
|
|
lp, err := levelpack.LoadFile(filename)
|
|
if err != nil {
|
|
log.Error("Couldn't read %s: %s", filename, err)
|
|
continue
|
|
}
|
|
_ = lp
|
|
|
|
// Make a frame to hold a complex button layout.
|
|
btnFrame := ui.NewFrame("Frame")
|
|
btnFrame.Resize(render.Rect{
|
|
W: buttonWidth,
|
|
H: buttonHeight,
|
|
})
|
|
|
|
// Draw labels...
|
|
label := ui.NewLabel(ui.Label{
|
|
Text: lp.Title,
|
|
Font: balance.LabelFont,
|
|
})
|
|
btnFrame.Pack(label, ui.Pack{
|
|
Side: ui.N,
|
|
})
|
|
|
|
description := lp.Description
|
|
if description == "" {
|
|
description = "(No description)"
|
|
}
|
|
|
|
byline := ui.NewLabel(ui.Label{
|
|
Text: description,
|
|
Font: balance.MenuFont,
|
|
})
|
|
btnFrame.Pack(byline, ui.Pack{
|
|
Side: ui.N,
|
|
})
|
|
|
|
numLevels := ui.NewLabel(ui.Label{
|
|
Text: fmt.Sprintf("[%d levels]", len(lp.Levels)),
|
|
Font: balance.MenuFont,
|
|
})
|
|
btnFrame.Pack(numLevels, ui.Pack{
|
|
Side: ui.N,
|
|
})
|
|
|
|
// Generate the detail screen (Frame) for this level pack.
|
|
// Should the user click our button, this screen is shown.
|
|
screen := config.makeDetailScreen(width, height, lp)
|
|
screen.Hide()
|
|
config.window.Pack(screen, ui.Pack{
|
|
Side: ui.N,
|
|
Fill: true,
|
|
Expand: true,
|
|
})
|
|
|
|
button := ui.NewButton(filename, btnFrame)
|
|
button.Handle(ui.Click, func(ed ui.EventData) error {
|
|
onChoose(screen)
|
|
return nil
|
|
})
|
|
|
|
frame.Pack(button, ui.Pack{
|
|
Side: ui.N,
|
|
PadY: 2,
|
|
})
|
|
config.Supervisor.Add(button)
|
|
|
|
if i > perPage {
|
|
button.Hide()
|
|
}
|
|
buttons = append(buttons, button)
|
|
}
|
|
|
|
pager := ui.NewPager(ui.Pager{
|
|
Name: "LevelPack Pager",
|
|
Page: page,
|
|
Pages: pages,
|
|
MaxPageButtons: maxPageButtons,
|
|
Font: balance.MenuFont,
|
|
OnChange: 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 buttons {
|
|
if visible >= perPage {
|
|
row.Hide()
|
|
continue
|
|
}
|
|
|
|
if i < minRow {
|
|
row.Hide()
|
|
} else {
|
|
row.Show()
|
|
visible++
|
|
}
|
|
}
|
|
},
|
|
})
|
|
pager.Compute(config.Engine)
|
|
pager.Supervise(config.Supervisor)
|
|
frame.Pack(pager, ui.Pack{
|
|
Side: ui.N,
|
|
PadY: 2,
|
|
})
|
|
|
|
return frame
|
|
}
|
|
|
|
// Detail screen for a given levelpack.
|
|
func (config LevelPack) makeDetailScreen(width, height int, lp levelpack.LevelPack) *ui.Frame {
|
|
frame := ui.NewFrame("Detail Screen")
|
|
|
|
label := ui.NewLabel(ui.Label{
|
|
Text: "HELLO " + lp.Title,
|
|
Font: balance.LabelFont,
|
|
})
|
|
frame.Pack(label, ui.Pack{
|
|
Side: ui.N,
|
|
PadX: 8,
|
|
PadY: 8,
|
|
})
|
|
|
|
backButton := ui.NewButton("Back", ui.NewLabel(ui.Label{
|
|
Text: "< Back to Level Packs",
|
|
Font: ui.MenuFont,
|
|
}))
|
|
backButton.Handle(ui.Click, func(ed ui.EventData) error {
|
|
frame.Hide()
|
|
config.gotoIndex()
|
|
return nil
|
|
})
|
|
config.Supervisor.Add(backButton)
|
|
frame.Pack(backButton, ui.Pack{
|
|
Side: ui.N,
|
|
PadY: 2,
|
|
})
|
|
|
|
return frame
|
|
}
|