WIP LevelPack UI + Landscape Mode Title Screen
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.
This commit is contained in:
parent
a75b7208ca
commit
678326540b
|
@ -12,6 +12,10 @@ var (
|
|||
Width = 1024
|
||||
Height = 768
|
||||
|
||||
// Title screen height needed for the main menu. Phones in landscape
|
||||
// mode will switch to the horizontal layout if less than this height.
|
||||
TitleScreenResponsiveHeight = 600
|
||||
|
||||
// Speed to scroll a canvas with arrow keys in Edit Mode.
|
||||
CanvasScrollSpeed = 8
|
||||
FollowActorMaxScrollSpeed = 64
|
||||
|
|
|
@ -15,4 +15,5 @@ const (
|
|||
const (
|
||||
LevelExt = ".level"
|
||||
DoodadExt = ".doodad"
|
||||
LevelPackExt = ".levelpack"
|
||||
)
|
||||
|
|
|
@ -29,6 +29,7 @@ var (
|
|||
SystemDoodadsPath = filepath.Join("assets", "doodads")
|
||||
SystemLevelsPath = filepath.Join("assets", "levels")
|
||||
SystemCampaignsPath = filepath.Join("assets", "campaigns")
|
||||
SystemLevelPacksPath = filepath.Join("assets", "levelpacks")
|
||||
)
|
||||
|
||||
// MakeHeader creates the binary file header.
|
||||
|
|
|
@ -7,8 +7,14 @@ import (
|
|||
"errors"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"git.kirsle.net/apps/doodle/assets"
|
||||
"git.kirsle.net/apps/doodle/pkg/enum"
|
||||
"git.kirsle.net/apps/doodle/pkg/filesystem"
|
||||
"git.kirsle.net/apps/doodle/pkg/userdir"
|
||||
)
|
||||
|
||||
// LevelPack describes the contents of a levelpack file.
|
||||
|
@ -63,6 +69,42 @@ func LoadFile(filename string) (LevelPack, error) {
|
|||
return lp, nil
|
||||
}
|
||||
|
||||
// ListFiles lists all the discoverable levelpack files, starting from
|
||||
// the game's built-ins all the way to user levelpacks.
|
||||
func ListFiles() ([]string, error) {
|
||||
var names []string
|
||||
|
||||
// List levelpacks embedded into the binary.
|
||||
if files, err := assets.AssetDir("assets/levelpacks"); err == nil {
|
||||
names = append(names, files...)
|
||||
}
|
||||
|
||||
// WASM stops here, no filesystem access.
|
||||
if runtime.GOOS == "js" {
|
||||
return names, nil
|
||||
}
|
||||
|
||||
// Read system-level levelpacks.
|
||||
files, _ := ioutil.ReadDir(filesystem.SystemLevelPacksPath)
|
||||
for _, file := range files {
|
||||
name := file.Name()
|
||||
if strings.HasSuffix(name, enum.LevelPackExt) {
|
||||
names = append(names, name)
|
||||
}
|
||||
}
|
||||
|
||||
// Append user levelpacks.
|
||||
files, _ = ioutil.ReadDir(userdir.LevelPackDirectory)
|
||||
for _, file := range files {
|
||||
name := file.Name()
|
||||
if strings.HasSuffix(name, enum.LevelPackExt) {
|
||||
names = append(names, name)
|
||||
}
|
||||
}
|
||||
|
||||
return names, nil
|
||||
}
|
||||
|
||||
// WriteFile saves the metadata to a .json file on disk.
|
||||
func (l LevelPack) WriteFile(filename string) error {
|
||||
out, err := json.Marshal(l)
|
||||
|
|
|
@ -38,6 +38,7 @@ type MainScene struct {
|
|||
btnRegister *ui.Button
|
||||
winRegister *ui.Window
|
||||
winSettings *ui.Window
|
||||
winLevelPacks *ui.Window
|
||||
|
||||
// Update check variables.
|
||||
updateButton *ui.Button
|
||||
|
@ -47,6 +48,12 @@ type MainScene struct {
|
|||
lazyScrollBounce bool
|
||||
lazyScrollTrajectory render.Point
|
||||
lazyScrollLastValue render.Point
|
||||
|
||||
// Landscape mode: if the screen isn't tall enough to see the main
|
||||
// menu we redo the layout to be landscape friendly. NOTE: this only
|
||||
// happens one time, and does not re-adapt when the window is made
|
||||
// tall enough again.
|
||||
landscapeMode bool
|
||||
}
|
||||
|
||||
// Name of the scene.
|
||||
|
@ -161,10 +168,22 @@ func (s *MainScene) Setup(d *Doodle) error {
|
|||
Func func()
|
||||
Style *style.Button
|
||||
}{
|
||||
// {
|
||||
// Name: "Story Mode",
|
||||
// Func: d.GotoStoryMenu,
|
||||
// },
|
||||
{
|
||||
Name: "Story Mode",
|
||||
Func: func() {
|
||||
if s.winLevelPacks == nil {
|
||||
s.winLevelPacks = windows.NewLevelPackWindow(windows.LevelPack{
|
||||
Supervisor: s.Supervisor,
|
||||
Engine: d.Engine,
|
||||
})
|
||||
}
|
||||
s.winLevelPacks.MoveTo(render.Point{
|
||||
X: (d.width / 2) - (s.winLevelPacks.Size().W / 2),
|
||||
Y: (d.height / 2) - (s.winLevelPacks.Size().H / 2),
|
||||
})
|
||||
s.winLevelPacks.Show()
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Play a Level",
|
||||
Func: d.GotoPlayMenu,
|
||||
|
@ -229,6 +248,10 @@ func (s *MainScene) Setup(d *Doodle) error {
|
|||
}
|
||||
}()
|
||||
|
||||
// Trigger our "Window Resized" function so we can check if the
|
||||
// layout needs to be switched to landscape mode for mobile.
|
||||
s.Resized(d.width, d.height)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -310,16 +333,121 @@ func (s *MainScene) Loop(d *Doodle, ev *event.State) error {
|
|||
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,
|
||||
})
|
||||
s.Resized(w, h)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Resized the app window.
|
||||
func (s *MainScene) Resized(width, height int) {
|
||||
log.Info("Resized to %dx%d", width, height)
|
||||
|
||||
// If the height is not tall enough for the menu, switch to the horizontal layout.
|
||||
if height < balance.TitleScreenResponsiveHeight {
|
||||
log.Error("Switch to landscape mode")
|
||||
s.landscapeMode = true
|
||||
} else {
|
||||
s.landscapeMode = false
|
||||
}
|
||||
|
||||
s.canvas.Resize(render.Rect{
|
||||
W: width,
|
||||
H: height,
|
||||
})
|
||||
}
|
||||
|
||||
// Move things into position for the main menu. This function arranges
|
||||
// the Title, Subtitle, Buttons, etc. into screen relative positions every
|
||||
// tick. This function sets their 'default' values, but if the window is
|
||||
// not tall enough and needs the landscape orientation, positionMenuLandscape()
|
||||
// will override these defaults.
|
||||
func (s *MainScene) positionMenuPortrait(d *Doodle) {
|
||||
// App title label.
|
||||
s.labelTitle.MoveTo(render.Point{
|
||||
X: (d.width / 2) - (s.labelTitle.Size().W / 2),
|
||||
Y: 120,
|
||||
})
|
||||
|
||||
// App subtitle label (byline).
|
||||
s.labelSubtitle.MoveTo(render.Point{
|
||||
X: (d.width / 2) - (s.labelSubtitle.Size().W / 2),
|
||||
Y: s.labelTitle.Point().Y + s.labelTitle.Size().H + 8,
|
||||
})
|
||||
|
||||
// Version label
|
||||
s.labelVersion.MoveTo(render.Point{
|
||||
X: (d.width) - (s.labelVersion.Size().W) - 20,
|
||||
Y: 20,
|
||||
})
|
||||
|
||||
// Hint label.
|
||||
s.labelHint.MoveTo(render.Point{
|
||||
X: (d.width / 2) - (s.labelHint.Size().W / 2),
|
||||
Y: d.height - s.labelHint.Size().H - 32,
|
||||
})
|
||||
|
||||
// Update button.
|
||||
s.updateButton.MoveTo(render.Point{
|
||||
X: 24,
|
||||
Y: d.height - s.updateButton.Size().H - 24,
|
||||
})
|
||||
|
||||
// Button frame.
|
||||
s.frame.MoveTo(render.Point{
|
||||
X: (d.width / 2) - (s.frame.Size().W / 2),
|
||||
Y: 260,
|
||||
})
|
||||
|
||||
// Register button.
|
||||
s.btnRegister.MoveTo(render.Point{
|
||||
X: d.width - s.btnRegister.Size().W - 24,
|
||||
Y: d.height - s.btnRegister.Size().H - 24,
|
||||
})
|
||||
}
|
||||
|
||||
func (s *MainScene) positionMenuLandscape(d *Doodle) {
|
||||
s.positionMenuPortrait(d)
|
||||
|
||||
var (
|
||||
col1 = render.Rect{
|
||||
X: 0,
|
||||
Y: 0,
|
||||
W: d.width / 2,
|
||||
H: d.height,
|
||||
}
|
||||
col2 = render.Rect{
|
||||
X: d.width,
|
||||
Y: 0,
|
||||
W: d.width - col1.W,
|
||||
H: d.height,
|
||||
}
|
||||
)
|
||||
|
||||
// Title and subtitle move to the left.
|
||||
s.labelTitle.MoveTo(render.Point{
|
||||
X: (col1.W / 2) - (s.labelTitle.Size().W / 2),
|
||||
Y: s.labelTitle.Point().Y,
|
||||
})
|
||||
s.labelSubtitle.MoveTo(render.Point{
|
||||
X: (col1.W / 2) - (s.labelSubtitle.Size().W / 2),
|
||||
Y: s.labelTitle.Point().Y + s.labelTitle.Size().H + 8,
|
||||
})
|
||||
|
||||
// Button frame to the right.
|
||||
s.frame.MoveTo(render.Point{
|
||||
X: (col2.X+col2.W)/2 - (s.frame.Size().W / 2),
|
||||
Y: (d.height / 2) - (s.frame.Size().H / 2),
|
||||
})
|
||||
|
||||
// Register button to the top left.
|
||||
// TODO: not ideal, move into main button list?
|
||||
s.btnRegister.MoveTo(render.Point{
|
||||
X: 20,
|
||||
Y: 20,
|
||||
})
|
||||
}
|
||||
|
||||
// LoopLazyScroll gently scrolls the title screen demo level, called each Loop.
|
||||
func (s *MainScene) LoopLazyScroll() {
|
||||
// The v1 basic sauce algorithm:
|
||||
|
@ -399,53 +527,32 @@ func (s *MainScene) Draw(d *Doodle) error {
|
|||
}
|
||||
}
|
||||
|
||||
// Arrange the main widgets by Portrait or Landscape mode.
|
||||
if s.landscapeMode {
|
||||
s.positionMenuLandscape(d)
|
||||
} else {
|
||||
s.positionMenuPortrait(d)
|
||||
}
|
||||
|
||||
// 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())
|
||||
|
||||
// App subtitle label (byline).
|
||||
s.labelSubtitle.MoveTo(render.Point{
|
||||
X: (d.width / 2) - (s.labelSubtitle.Size().W / 2),
|
||||
Y: s.labelTitle.Point().Y + s.labelTitle.Size().H + 8,
|
||||
})
|
||||
s.labelSubtitle.Present(d.Engine, s.labelSubtitle.Point())
|
||||
|
||||
// Version label
|
||||
s.labelVersion.MoveTo(render.Point{
|
||||
X: (d.width) - (s.labelVersion.Size().W) - 20,
|
||||
Y: 20,
|
||||
})
|
||||
s.labelVersion.Present(d.Engine, s.labelVersion.Point())
|
||||
|
||||
// Hint label.
|
||||
s.labelHint.MoveTo(render.Point{
|
||||
X: (d.width / 2) - (s.labelHint.Size().W / 2),
|
||||
Y: d.height - s.labelHint.Size().H - 32,
|
||||
})
|
||||
s.labelHint.Present(d.Engine, s.labelHint.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())
|
||||
|
||||
// Register button.
|
||||
s.btnRegister.MoveTo(render.Point{
|
||||
X: d.width - s.btnRegister.Size().W - 24,
|
||||
Y: d.height - s.btnRegister.Size().H - 24,
|
||||
})
|
||||
s.btnRegister.Present(d.Engine, s.btnRegister.Point())
|
||||
|
||||
// Present supervised windows.
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"git.kirsle.net/apps/doodle/pkg/level"
|
||||
"git.kirsle.net/apps/doodle/pkg/log"
|
||||
"git.kirsle.net/apps/doodle/pkg/uix"
|
||||
"git.kirsle.net/apps/doodle/pkg/windows"
|
||||
"git.kirsle.net/go/render"
|
||||
"git.kirsle.net/go/render/event"
|
||||
"git.kirsle.net/go/ui"
|
||||
|
@ -23,7 +24,7 @@ type StoryScene struct {
|
|||
// UI widgets.
|
||||
supervisor *ui.Supervisor
|
||||
campaignFrame *ui.Frame // Select a Campaign screen
|
||||
levelSelectFrame *ui.Frame // Select a level in the campaign screen
|
||||
levelSelectFrame *ui.Window // Select a level in the campaign screen
|
||||
|
||||
// Pointer to the currently active frame.
|
||||
activeFrame *ui.Frame
|
||||
|
@ -59,7 +60,13 @@ func (s *StoryScene) Setup(d *Doodle) error {
|
|||
|
||||
// Set up the sub-screens of this scene.
|
||||
s.campaignFrame = s.setupCampaignFrame()
|
||||
s.levelSelectFrame = s.setupLevelSelectFrame()
|
||||
s.levelSelectFrame = windows.NewLevelPackWindow(windows.LevelPack{
|
||||
Supervisor: s.supervisor,
|
||||
Engine: d.Engine,
|
||||
|
||||
OnPlayLevel: func(levelpack, filename string) {},
|
||||
})
|
||||
s.levelSelectFrame.Show()
|
||||
|
||||
s.activeFrame = s.campaignFrame
|
||||
|
||||
|
@ -100,13 +107,6 @@ func (s *StoryScene) setupCampaignFrame() *ui.Frame {
|
|||
return frame
|
||||
}
|
||||
|
||||
// setupLevelSelectFrame sets up the Level Select screen.
|
||||
func (s *StoryScene) setupLevelSelectFrame() *ui.Frame {
|
||||
var frame = ui.NewFrame("List Frame")
|
||||
|
||||
return frame
|
||||
}
|
||||
|
||||
// Loop the story scene.
|
||||
func (s *StoryScene) Loop(d *Doodle, ev *event.State) error {
|
||||
s.supervisor.Loop(ev)
|
||||
|
@ -135,6 +135,8 @@ func (s *StoryScene) Draw(d *Doodle) error {
|
|||
// Draw the active screen.
|
||||
s.activeFrame.Present(d.Engine, render.Origin)
|
||||
|
||||
s.supervisor.Present(d.Engine)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@ var (
|
|||
|
||||
ProfileDirectory string
|
||||
LevelDirectory string
|
||||
LevelPackDirectory string
|
||||
DoodadDirectory string
|
||||
CampaignDirectory string
|
||||
ScreenshotDirectory string
|
||||
|
@ -35,6 +36,7 @@ func init() {
|
|||
// Profile directory contains the user's levels and doodads.
|
||||
ProfileDirectory = configdir.LocalConfig(ConfigDirectoryName)
|
||||
LevelDirectory = configdir.LocalConfig(ConfigDirectoryName, "levels")
|
||||
LevelPackDirectory = configdir.LocalConfig(ConfigDirectoryName, "levelpacks")
|
||||
DoodadDirectory = configdir.LocalConfig(ConfigDirectoryName, "doodads")
|
||||
CampaignDirectory = configdir.LocalConfig(ConfigDirectoryName, "campaigns")
|
||||
ScreenshotDirectory = configdir.LocalConfig(ConfigDirectoryName, "screenshots")
|
||||
|
@ -47,6 +49,7 @@ func init() {
|
|||
// WASM: do not make paths in wasm.
|
||||
if runtime.GOOS != "js" {
|
||||
configdir.MakePath(LevelDirectory)
|
||||
configdir.MakePath(LevelPackDirectory)
|
||||
configdir.MakePath(DoodadDirectory)
|
||||
configdir.MakePath(CampaignDirectory)
|
||||
configdir.MakePath(FontDirectory)
|
||||
|
|
258
pkg/windows/levelpack_open.go
Normal file
258
pkg/windows/levelpack_open.go
Normal file
|
@ -0,0 +1,258 @@
|
|||
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
|
||||
}
|
Loading…
Reference in New Issue
Block a user