WIP Publish Dialog + UI Improvements
* File->Publish Level in the Level Editor opens the Publish window, where you can embed custom doodads into your level and export a portable .level file you can share with others. * Currently does not actually export a level file yet. * The dialog lists all unique doodad names in use in your level, and designates which are built-ins and which are custom (paginated). * A checkbox would let the user embed built-in doodads into their level, as well, locking it in to those versions and not using updated versions from future game releases. UI Improvements: * Added styling for a "Primary" UI button, rendered in deep blue. * Pop-up modals (Alert, Confirm) color their Ok button as Primary. * The Enter key pressed during an Alert or Confirm modal will invoke its default button and close the modal, corresponding to its Primary button. * The developer console is now opened with the tilde/grave key ` instead of the Enter key, so that the Enter key is free to click through modals. * In the "Open/Edit Drawing" window, a "Browse..." button is added to the level and doodad sections, spawning a native File Open dialog to pick a .level or .doodad outside the config root.
This commit is contained in:
parent
eb24858830
commit
d9bca2152a
|
@ -2,9 +2,12 @@ package balance
|
|||
|
||||
// Feature Flags to turn on/off experimental content.
|
||||
var Feature = feature{
|
||||
Zoom: false,
|
||||
CustomWallpaper: true,
|
||||
ChangePalette: false,
|
||||
Zoom: false, // enable the zoom in/out feature (very buggy rn)
|
||||
CustomWallpaper: true, // attach custom wallpaper img to levels
|
||||
ChangePalette: false, // reset your palette after level creation to a diff preset
|
||||
|
||||
// Allow embedded doodads in levels.
|
||||
EmbeddableDoodads: true,
|
||||
}
|
||||
|
||||
// FeaturesOn turns on all feature flags, from CLI --experimental option.
|
||||
|
@ -18,4 +21,5 @@ type feature struct {
|
|||
Zoom bool
|
||||
CustomWallpaper bool
|
||||
ChangePalette bool
|
||||
EmbeddableDoodads bool
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ package balance
|
|||
import (
|
||||
"git.kirsle.net/go/render"
|
||||
"git.kirsle.net/go/ui"
|
||||
"git.kirsle.net/go/ui/style"
|
||||
)
|
||||
|
||||
// Theme and appearance variables.
|
||||
|
@ -97,4 +98,15 @@ var (
|
|||
DoodadButtonSize = 64
|
||||
DoodadDropperCols = 6 // rows/columns of buttons
|
||||
DoodadDropperRows = 3
|
||||
|
||||
// Button styles, customized in init().
|
||||
ButtonPrimary = style.DefaultButton
|
||||
)
|
||||
|
||||
func init() {
|
||||
// Customize button styles.
|
||||
ButtonPrimary.Background = render.RGBA(0, 60, 153, 255)
|
||||
ButtonPrimary.Foreground = render.RGBA(255, 255, 254, 255)
|
||||
ButtonPrimary.HoverBackground = render.RGBA(0, 153, 255, 255)
|
||||
ButtonPrimary.HoverForeground = ButtonPrimary.Foreground
|
||||
}
|
||||
|
|
|
@ -41,6 +41,11 @@ func (c Command) Run(d *Doodle) error {
|
|||
case "alert":
|
||||
modal.Alert(c.ArgsLiteral)
|
||||
return nil
|
||||
case "confirm":
|
||||
modal.Confirm(c.ArgsLiteral).Then(func() {
|
||||
d.Flash("Confirmed.")
|
||||
})
|
||||
return nil
|
||||
case "new":
|
||||
return c.New(d)
|
||||
case "save":
|
||||
|
|
|
@ -63,6 +63,49 @@ func ListDoodads() ([]string, error) {
|
|||
return result, err
|
||||
}
|
||||
|
||||
// ListBuiltin returns a listing of all built-in doodads.
|
||||
// Exactly like ListDoodads() but doesn't return user home folder doodads.
|
||||
func ListBuiltin() ([]string, error) {
|
||||
var names []string
|
||||
|
||||
// List doodads embedded into the binary.
|
||||
if files, err := bindata.AssetDir("assets/doodads"); err == nil {
|
||||
names = append(names, files...)
|
||||
}
|
||||
|
||||
// WASM
|
||||
if runtime.GOOS == "js" {
|
||||
// Return the array of doodads embedded in the bindata.
|
||||
// TODO: append user doodads to the list.
|
||||
return names, nil
|
||||
}
|
||||
|
||||
// Read system-level doodads first. Ignore errors, if the system path is
|
||||
// empty we still go on to read the user directory.
|
||||
files, _ := ioutil.ReadDir(filesystem.SystemDoodadsPath)
|
||||
|
||||
for _, file := range files {
|
||||
name := file.Name()
|
||||
if strings.HasSuffix(strings.ToLower(name), enum.DoodadExt) {
|
||||
names = append(names, name)
|
||||
}
|
||||
}
|
||||
|
||||
// Deduplicate names.
|
||||
var uniq = map[string]interface{}{}
|
||||
var result []string
|
||||
for _, name := range names {
|
||||
if _, ok := uniq[name]; !ok {
|
||||
uniq[name] = nil
|
||||
result = append(result, name)
|
||||
}
|
||||
}
|
||||
|
||||
sort.Strings(result)
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// LoadFile reads a doodad file from disk, checking a few locations.
|
||||
func LoadFile(filename string) (*Doodad, error) {
|
||||
if !strings.HasSuffix(filename, enum.DoodadExt) {
|
||||
|
|
|
@ -134,10 +134,9 @@ func (d *Doodle) Run() error {
|
|||
|
||||
// Command line shell.
|
||||
if d.shell.Open {
|
||||
} else if ev.Enter {
|
||||
} else if keybind.ShellKey(ev) {
|
||||
log.Debug("Shell: opening shell")
|
||||
d.shell.Open = true
|
||||
ev.Enter = false
|
||||
} else {
|
||||
// Global event handlers.
|
||||
if keybind.Shutdown(ev) {
|
||||
|
|
|
@ -49,6 +49,7 @@ type EditorUI struct {
|
|||
doodadWindow *ui.Window
|
||||
paletteEditor *ui.Window
|
||||
layersWindow *ui.Window
|
||||
publishWindow *ui.Window
|
||||
|
||||
// Palette window.
|
||||
Palette *ui.Window
|
||||
|
@ -522,6 +523,13 @@ func (u *EditorUI) SetupMenuBar(d *Doodle) *ui.MenuBar {
|
|||
}
|
||||
})
|
||||
})
|
||||
|
||||
if balance.Feature.EmbeddableDoodads && drawingType == "level" {
|
||||
fileMenu.AddItem("Publish level", func() {
|
||||
u.OpenPublishWindow()
|
||||
})
|
||||
}
|
||||
|
||||
fileMenu.AddItemAccel("Open...", "Ctrl-O*", func() {
|
||||
u.Scene.ConfirmUnload(func() {
|
||||
d.GotoLoadMenu()
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"git.kirsle.net/apps/doodle/pkg/doodads"
|
||||
"git.kirsle.net/apps/doodle/pkg/level"
|
||||
"git.kirsle.net/apps/doodle/pkg/log"
|
||||
"git.kirsle.net/apps/doodle/pkg/modal"
|
||||
"git.kirsle.net/apps/doodle/pkg/windows"
|
||||
"git.kirsle.net/go/render"
|
||||
"git.kirsle.net/go/ui"
|
||||
|
@ -43,6 +44,14 @@ func (u *EditorUI) OpenDoodadDropper() {
|
|||
u.doodadWindow.Show()
|
||||
}
|
||||
|
||||
// OpenPublishWindow opens the Publisher window.
|
||||
func (u *EditorUI) OpenPublishWindow() {
|
||||
u.publishWindow.Hide()
|
||||
u.publishWindow = nil
|
||||
u.SetupPopups(u.d)
|
||||
u.publishWindow.Show()
|
||||
}
|
||||
|
||||
// SetupPopups preloads popup windows like the DoodadDropper.
|
||||
func (u *EditorUI) SetupPopups(d *Doodle) {
|
||||
// Common window configure function.
|
||||
|
@ -56,6 +65,8 @@ func (u *EditorUI) SetupPopups(d *Doodle) {
|
|||
X: (d.width / 2) - (size.W / 2),
|
||||
Y: (d.height / 2) - (size.H / 2),
|
||||
})
|
||||
|
||||
window.Hide()
|
||||
}
|
||||
|
||||
// Doodad Dropper.
|
||||
|
@ -94,6 +105,30 @@ func (u *EditorUI) SetupPopups(d *Doodle) {
|
|||
configure(u.levelSettingsWindow)
|
||||
}
|
||||
|
||||
// Publish Level (embed doodads)
|
||||
if u.publishWindow == nil {
|
||||
scene, _ := d.Scene.(*EditorScene)
|
||||
|
||||
u.publishWindow = windows.NewPublishWindow(windows.Publish{
|
||||
Supervisor: u.Supervisor,
|
||||
Engine: d.Engine,
|
||||
Level: scene.Level,
|
||||
|
||||
OnPublish: func() {
|
||||
modal.Alert("Not Yet Implemented")
|
||||
// filename, err := native.SaveFile("Save your level", "*.level")
|
||||
// if err != nil {
|
||||
// modal.Alert(err.Error())
|
||||
// }
|
||||
// log.Info("Write to: %s", filename)
|
||||
},
|
||||
OnCancel: func() {
|
||||
u.publishWindow.Hide()
|
||||
},
|
||||
})
|
||||
configure(u.publishWindow)
|
||||
}
|
||||
|
||||
// Palette Editor.
|
||||
if u.paletteEditor == nil {
|
||||
scene, _ := d.Scene.(*EditorScene)
|
||||
|
|
|
@ -107,6 +107,20 @@ func DoodadDropper(ev *event.State) bool {
|
|||
return ev.KeyDown("d")
|
||||
}
|
||||
|
||||
// ShellKey (`) opens the developer console.
|
||||
func ShellKey(ev *event.State) bool {
|
||||
v := ev.KeyDown("`")
|
||||
ev.SetKeyDown("`", false)
|
||||
return v
|
||||
}
|
||||
|
||||
// Enter key.
|
||||
func Enter(ev *event.State) bool {
|
||||
v := ev.Enter
|
||||
ev.Enter = false
|
||||
return v
|
||||
}
|
||||
|
||||
// Shift key.
|
||||
func Shift(ev *event.State) bool {
|
||||
return ev.Shift
|
||||
|
|
|
@ -54,6 +54,7 @@ func makeAlert(m *Modal) *ui.Window {
|
|||
Text: "Ok",
|
||||
Font: balance.MenuFont,
|
||||
}))
|
||||
button.SetStyle(&balance.ButtonPrimary)
|
||||
button.Handle(ui.Click, func(ev ui.EventData) error {
|
||||
log.Info("clicked!")
|
||||
m.Dismiss(true)
|
||||
|
|
|
@ -78,6 +78,11 @@ func makeConfirm(m *Modal) *ui.Window {
|
|||
button.Compute(engine)
|
||||
supervisor.Add(button)
|
||||
|
||||
// OK Button is primary.
|
||||
if btn.Label == "Ok" {
|
||||
button.SetStyle(&balance.ButtonPrimary)
|
||||
}
|
||||
|
||||
btnBar.Pack(button, ui.Pack{
|
||||
Side: ui.W,
|
||||
PadX: 2,
|
||||
|
|
|
@ -3,6 +3,7 @@ package modal
|
|||
|
||||
import (
|
||||
"git.kirsle.net/apps/doodle/pkg/balance"
|
||||
"git.kirsle.net/apps/doodle/pkg/keybind"
|
||||
"git.kirsle.net/go/render"
|
||||
"git.kirsle.net/go/render/event"
|
||||
"git.kirsle.net/go/ui"
|
||||
|
@ -48,6 +49,12 @@ func Handled(ev *event.State) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
// Enter key submits the default button.
|
||||
if keybind.Enter(ev) {
|
||||
current.Dismiss(true)
|
||||
return true
|
||||
}
|
||||
|
||||
supervisor.Loop(ev)
|
||||
|
||||
// Has the window changed size?
|
||||
|
|
|
@ -3,8 +3,9 @@
|
|||
package native
|
||||
|
||||
import (
|
||||
"github.com/gen2brain/dlgs"
|
||||
"errors"
|
||||
|
||||
"github.com/gen2brain/dlgs"
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
@ -28,3 +29,21 @@ func OpenFile(title string, filter string) (string, error) {
|
|||
}
|
||||
return "", errors.New("canceled")
|
||||
}
|
||||
|
||||
// SaveFile invokes a native File Chooser dialog with the title
|
||||
// and a set of file filters. The filters are a sequence of label
|
||||
// and comma-separated file extensions.
|
||||
//
|
||||
// Example:
|
||||
// SaveFile("Pick a file", "Images", "png,gif,jpg", "Audio", "mp3")
|
||||
func SaveFile(title string, filter string) (string, error) {
|
||||
filename, ok, err := dlgs.File(title, filter, false)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if ok {
|
||||
return filename, nil
|
||||
}
|
||||
return "", errors.New("canceled")
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"strings"
|
||||
|
||||
"git.kirsle.net/apps/doodle/pkg/balance"
|
||||
"git.kirsle.net/apps/doodle/pkg/keybind"
|
||||
"git.kirsle.net/apps/doodle/pkg/log"
|
||||
"git.kirsle.net/apps/doodle/pkg/shmem"
|
||||
"git.kirsle.net/go/render"
|
||||
|
@ -215,7 +216,7 @@ func (s *Shell) Draw(d *Doodle, ev *event.State) error {
|
|||
if ev.Escape {
|
||||
s.Close()
|
||||
return nil
|
||||
} else if ev.Enter {
|
||||
} else if keybind.Enter(ev) {
|
||||
s.Execute(s.Text)
|
||||
|
||||
// Auto-close the console unless in REPL mode.
|
||||
|
@ -223,7 +224,6 @@ func (s *Shell) Draw(d *Doodle, ev *event.State) error {
|
|||
s.Close()
|
||||
}
|
||||
|
||||
ev.Enter = false
|
||||
return nil
|
||||
} else if (ev.Up || ev.Down) && len(s.History) > 0 {
|
||||
// Paging through history.
|
||||
|
|
|
@ -5,6 +5,8 @@ import (
|
|||
|
||||
"git.kirsle.net/apps/doodle/pkg/balance"
|
||||
"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/userdir"
|
||||
"git.kirsle.net/go/render"
|
||||
"git.kirsle.net/go/ui"
|
||||
|
@ -103,6 +105,40 @@ func NewOpenLevelEditor(config OpenLevelEditor) *ui.Window {
|
|||
}(i, lvl)
|
||||
}
|
||||
|
||||
// Browse button for local filesystem.
|
||||
browseLevelFrame := ui.NewFrame("Browse Level Frame")
|
||||
frame.Pack(browseLevelFrame, ui.Pack{
|
||||
Side: ui.N,
|
||||
Expand: true,
|
||||
FillX: true,
|
||||
PadY: 1,
|
||||
})
|
||||
|
||||
browseLevelButton := ui.NewButton("Browse Level", ui.NewLabel(ui.Label{
|
||||
Text: "Browse...",
|
||||
Font: balance.MenuFont,
|
||||
}))
|
||||
browseLevelButton.SetStyle(&balance.ButtonPrimary)
|
||||
browseLevelFrame.Pack(browseLevelButton, ui.Pack{
|
||||
Side: ui.W,
|
||||
})
|
||||
|
||||
browseLevelButton.Handle(ui.Click, func(ed ui.EventData) error {
|
||||
filename, err := native.OpenFile("Choose a .level file", "*.level")
|
||||
if err != nil {
|
||||
log.Error("Couldn't show file dialog: %s", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
if config.LoadForPlay {
|
||||
config.OnPlayLevel(filename)
|
||||
} else {
|
||||
config.OnEditLevel(filename)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
config.Supervisor.Add(browseLevelButton)
|
||||
|
||||
/******************
|
||||
* Frame for selecting User Doodads
|
||||
******************/
|
||||
|
@ -155,6 +191,40 @@ func NewOpenLevelEditor(config OpenLevelEditor) *ui.Window {
|
|||
}
|
||||
}
|
||||
|
||||
// Browse button for local filesystem.
|
||||
browseDoodadFrame := ui.NewFrame("Browse Doodad Frame")
|
||||
frame.Pack(browseDoodadFrame, ui.Pack{
|
||||
Side: ui.N,
|
||||
Expand: true,
|
||||
FillX: true,
|
||||
PadY: 1,
|
||||
})
|
||||
|
||||
browseDoodadButton := ui.NewButton("Browse Doodad", ui.NewLabel(ui.Label{
|
||||
Text: "Browse...",
|
||||
Font: balance.MenuFont,
|
||||
}))
|
||||
browseDoodadButton.SetStyle(&balance.ButtonPrimary)
|
||||
browseDoodadFrame.Pack(browseDoodadButton, ui.Pack{
|
||||
Side: ui.W,
|
||||
})
|
||||
|
||||
browseDoodadButton.Handle(ui.Click, func(ed ui.EventData) error {
|
||||
filename, err := native.OpenFile("Choose a .doodad file", "*.doodad")
|
||||
if err != nil {
|
||||
log.Error("Couldn't show file dialog: %s", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
if config.LoadForPlay {
|
||||
config.OnPlayLevel(filename)
|
||||
} else {
|
||||
config.OnEditLevel(filename)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
config.Supervisor.Add(browseDoodadButton)
|
||||
|
||||
/******************
|
||||
* Confirm/cancel buttons.
|
||||
******************/
|
||||
|
|
328
pkg/windows/publish_level.go
Normal file
328
pkg/windows/publish_level.go
Normal file
|
@ -0,0 +1,328 @@
|
|||
package windows
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"git.kirsle.net/apps/doodle/pkg/balance"
|
||||
"git.kirsle.net/apps/doodle/pkg/doodads"
|
||||
"git.kirsle.net/apps/doodle/pkg/level"
|
||||
"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()
|
||||
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 all the doodad names in use in this level.
|
||||
unique := map[string]interface{}{}
|
||||
names := []string{}
|
||||
if cfg.Level != nil {
|
||||
for _, actor := range cfg.Level.Actors {
|
||||
if _, ok := unique[actor.Filename]; ok {
|
||||
continue
|
||||
}
|
||||
unique[actor.Filename] = nil
|
||||
names = append(names, actor.Filename)
|
||||
}
|
||||
}
|
||||
|
||||
sort.Strings(names)
|
||||
|
||||
// Identify which of the doodads are built-ins.
|
||||
usedBuiltins := []string{}
|
||||
builtinMap := map[string]interface{}{}
|
||||
usedCustom := []string{}
|
||||
if builtins, err := doodads.ListBuiltin(); err == nil {
|
||||
for _, filename := range builtins {
|
||||
if _, ok := unique[filename]; ok {
|
||||
usedBuiltins = append(usedBuiltins, filename)
|
||||
builtinMap[filename] = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, name := range names {
|
||||
if _, ok := builtinMap[name]; ok {
|
||||
continue
|
||||
}
|
||||
usedCustom = append(usedCustom, name)
|
||||
}
|
||||
|
||||
// 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(names) > 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()
|
||||
}
|
||||
}},
|
||||
{"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
|
||||
}
|
Loading…
Reference in New Issue
Block a user