The Window Manager Update
* Take advantage of the new Window Manager feature of the UI toolkit. * Move the MenuScene's "New Level" and "Play/Edit Level" windows into stand-alone functions in new pkg/windows/ package. The 'windows' package is isolated from the rest of Doodle and communicates using config variables and callback functions to avoid circular dependency. * MenuScene calls the window constructors from the new package. * Add an "Options" button to the Menu Bar in the Editor Scene, which opens the "New Level" window to allow changing the wallpaper or bounding type of the level currently being edited. * Move the cheat codes into their own file, cheats.go
This commit is contained in:
parent
2bd420ff54
commit
f0101ba048
93
pkg/cheats.go
Normal file
93
pkg/cheats.go
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
package doodle
|
||||||
|
|
||||||
|
// cheatCommand is a subroutine of the Command.Run() method of the Doodle
|
||||||
|
// developer shell (commands.go). It looks for special cheat codes entered
|
||||||
|
// into the command shell and executes them.
|
||||||
|
//
|
||||||
|
// Returns true if a cheat was intercepted, false if the command is not a cheat.
|
||||||
|
func (c Command) cheatCommand(d *Doodle) bool {
|
||||||
|
// Some cheats only work in Play Mode.
|
||||||
|
playScene, isPlay := d.Scene.(*PlayScene)
|
||||||
|
|
||||||
|
// Cheat codes
|
||||||
|
switch c.Raw {
|
||||||
|
case "unleash the beast":
|
||||||
|
if fpsDoNotCap {
|
||||||
|
d.Flash("Reset frame rate throttle to factory default FPS")
|
||||||
|
} else {
|
||||||
|
d.Flash("Unleashing as many frames as we can render!")
|
||||||
|
}
|
||||||
|
fpsDoNotCap = !fpsDoNotCap
|
||||||
|
|
||||||
|
case "don't edit and drive":
|
||||||
|
if isPlay {
|
||||||
|
playScene.drawing.Editable = true
|
||||||
|
d.Flash("Level canvas is now editable. Don't edit and drive!")
|
||||||
|
} else {
|
||||||
|
d.Flash("Use this cheat in Play Mode to make the level canvas editable.")
|
||||||
|
}
|
||||||
|
|
||||||
|
case "scroll scroll scroll your boat":
|
||||||
|
if isPlay {
|
||||||
|
playScene.drawing.Scrollable = true
|
||||||
|
d.Flash("Level canvas is now scrollable with the arrow keys.")
|
||||||
|
} else {
|
||||||
|
d.Flash("Use this cheat in Play Mode to make the level scrollable.")
|
||||||
|
}
|
||||||
|
|
||||||
|
case "import antigravity":
|
||||||
|
if isPlay {
|
||||||
|
playScene.antigravity = !playScene.antigravity
|
||||||
|
playScene.Player.SetGravity(!playScene.antigravity)
|
||||||
|
|
||||||
|
if playScene.antigravity {
|
||||||
|
d.Flash("Gravity disabled for player character.")
|
||||||
|
} else {
|
||||||
|
d.Flash("Gravity restored for player character.")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
d.Flash("Use this cheat in Play Mode to disable gravity for the player character.")
|
||||||
|
}
|
||||||
|
|
||||||
|
case "ghost mode":
|
||||||
|
if isPlay {
|
||||||
|
playScene.noclip = !playScene.noclip
|
||||||
|
playScene.Player.SetNoclip(playScene.noclip)
|
||||||
|
|
||||||
|
playScene.antigravity = playScene.noclip
|
||||||
|
playScene.Player.SetGravity(!playScene.antigravity)
|
||||||
|
|
||||||
|
if playScene.noclip {
|
||||||
|
d.Flash("Clipping disabled for player character.")
|
||||||
|
} else {
|
||||||
|
d.Flash("Clipping and gravity restored for player character.")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
d.Flash("Use this cheat in Play Mode to disable clipping for the player character.")
|
||||||
|
}
|
||||||
|
|
||||||
|
case "give all keys":
|
||||||
|
if isPlay {
|
||||||
|
playScene.Player.AddItem("key-red.doodad", 0)
|
||||||
|
playScene.Player.AddItem("key-blue.doodad", 0)
|
||||||
|
playScene.Player.AddItem("key-green.doodad", 0)
|
||||||
|
playScene.Player.AddItem("key-yellow.doodad", 0)
|
||||||
|
d.Flash("Given all keys to the player character.")
|
||||||
|
} else {
|
||||||
|
d.Flash("Use this cheat in Play Mode to get all colored keys.")
|
||||||
|
}
|
||||||
|
|
||||||
|
case "drop all items":
|
||||||
|
if isPlay {
|
||||||
|
playScene.Player.ClearInventory()
|
||||||
|
d.Flash("Cleared inventory of player character.")
|
||||||
|
} else {
|
||||||
|
d.Flash("Use this cheat in Play Mode to clear your inventory.")
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
|
@ -25,60 +25,7 @@ func (c Command) Run(d *Doodle) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cheat codes
|
// Cheat codes
|
||||||
if c.Raw == "unleash the beast" {
|
if cheat := c.cheatCommand(d); cheat {
|
||||||
if fpsDoNotCap {
|
|
||||||
d.Flash("Reset frame rate throttle to factory default FPS")
|
|
||||||
} else {
|
|
||||||
d.Flash("Unleashing as many frames as we can render!")
|
|
||||||
}
|
|
||||||
fpsDoNotCap = !fpsDoNotCap
|
|
||||||
return nil
|
|
||||||
} else if c.Raw == "don't edit and drive" {
|
|
||||||
if playScene, ok := d.Scene.(*PlayScene); ok {
|
|
||||||
playScene.drawing.Editable = true
|
|
||||||
d.Flash("Level canvas is now editable. Don't edit and drive!")
|
|
||||||
} else {
|
|
||||||
d.Flash("Use this cheat in Play Mode to make the level canvas editable.")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
} else if c.Raw == "scroll scroll scroll your boat" {
|
|
||||||
if playScene, ok := d.Scene.(*PlayScene); ok {
|
|
||||||
playScene.drawing.Scrollable = true
|
|
||||||
d.Flash("Level canvas is now scrollable with the arrow keys.")
|
|
||||||
} else {
|
|
||||||
d.Flash("Use this cheat in Play Mode to make the level scrollable.")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
} else if c.Raw == "import antigravity" {
|
|
||||||
if playScene, ok := d.Scene.(*PlayScene); ok {
|
|
||||||
playScene.antigravity = !playScene.antigravity
|
|
||||||
playScene.Player.SetGravity(!playScene.antigravity)
|
|
||||||
|
|
||||||
if playScene.antigravity {
|
|
||||||
d.Flash("Gravity disabled for player character.")
|
|
||||||
} else {
|
|
||||||
d.Flash("Gravity restored for player character.")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
d.Flash("Use this cheat in Play Mode to disable gravity for the player character.")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
} else if c.Raw == "ghost mode" {
|
|
||||||
if playScene, ok := d.Scene.(*PlayScene); ok {
|
|
||||||
playScene.noclip = !playScene.noclip
|
|
||||||
playScene.Player.SetNoclip(playScene.noclip)
|
|
||||||
|
|
||||||
playScene.antigravity = playScene.noclip
|
|
||||||
playScene.Player.SetGravity(!playScene.antigravity)
|
|
||||||
|
|
||||||
if playScene.noclip {
|
|
||||||
d.Flash("Clipping disabled for player character.")
|
|
||||||
} else {
|
|
||||||
d.Flash("Clipping and gravity restored for player character.")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
d.Flash("Use this cheat in Play Mode to disable clipping for the player character.")
|
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@ import (
|
||||||
"git.kirsle.net/apps/doodle/pkg/level"
|
"git.kirsle.net/apps/doodle/pkg/level"
|
||||||
"git.kirsle.net/apps/doodle/pkg/log"
|
"git.kirsle.net/apps/doodle/pkg/log"
|
||||||
"git.kirsle.net/apps/doodle/pkg/uix"
|
"git.kirsle.net/apps/doodle/pkg/uix"
|
||||||
|
"git.kirsle.net/apps/doodle/pkg/windows"
|
||||||
"git.kirsle.net/go/render"
|
"git.kirsle.net/go/render"
|
||||||
"git.kirsle.net/go/render/event"
|
"git.kirsle.net/go/render/event"
|
||||||
"git.kirsle.net/go/ui"
|
"git.kirsle.net/go/ui"
|
||||||
|
@ -43,6 +44,9 @@ type EditorUI struct {
|
||||||
ToolBar *ui.Frame
|
ToolBar *ui.Frame
|
||||||
PlayButton *ui.Button
|
PlayButton *ui.Button
|
||||||
|
|
||||||
|
// Popup windows.
|
||||||
|
levelSettingsWindow *ui.Window
|
||||||
|
|
||||||
// Palette window.
|
// Palette window.
|
||||||
Palette *ui.Window
|
Palette *ui.Window
|
||||||
PaletteTab *ui.Frame
|
PaletteTab *ui.Frame
|
||||||
|
@ -98,8 +102,9 @@ func NewEditorUI(d *Doodle, s *EditorScene) *EditorUI {
|
||||||
Text: "Play (P)",
|
Text: "Play (P)",
|
||||||
Font: balance.PlayButtonFont,
|
Font: balance.PlayButtonFont,
|
||||||
}))
|
}))
|
||||||
u.PlayButton.Handle(ui.Click, func(ed ui.EventData) {
|
u.PlayButton.Handle(ui.Click, func(ed ui.EventData) error {
|
||||||
u.Scene.Playtest()
|
u.Scene.Playtest()
|
||||||
|
return nil
|
||||||
})
|
})
|
||||||
u.Supervisor.Add(u.PlayButton)
|
u.Supervisor.Add(u.PlayButton)
|
||||||
|
|
||||||
|
@ -302,6 +307,9 @@ func (u *EditorUI) Present(e render.Engine) {
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Draw any windows being managed by Supervisor.
|
||||||
|
u.Supervisor.Present(e)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetupWorkspace configures the main Workspace frame that takes up the full
|
// SetupWorkspace configures the main Workspace frame that takes up the full
|
||||||
|
@ -354,7 +362,7 @@ func (u *EditorUI) SetupCanvas(d *Doodle) *uix.Canvas {
|
||||||
// Set up the drop handler for draggable doodads.
|
// Set up the drop handler for draggable doodads.
|
||||||
// NOTE: The drag event begins at editor_ui_doodad.go when configuring the
|
// NOTE: The drag event begins at editor_ui_doodad.go when configuring the
|
||||||
// Doodad Palette buttons.
|
// Doodad Palette buttons.
|
||||||
drawing.Handle(ui.Drop, func(ed ui.EventData) {
|
drawing.Handle(ui.Drop, func(ed ui.EventData) error {
|
||||||
log.Info("Drawing canvas has received a drop!")
|
log.Info("Drawing canvas has received a drop!")
|
||||||
var P = ui.AbsolutePosition(drawing)
|
var P = ui.AbsolutePosition(drawing)
|
||||||
|
|
||||||
|
@ -363,7 +371,7 @@ func (u *EditorUI) SetupCanvas(d *Doodle) *uix.Canvas {
|
||||||
log.Info("Actor is a %s", actor.doodad.Filename)
|
log.Info("Actor is a %s", actor.doodad.Filename)
|
||||||
if u.Scene.Level == nil {
|
if u.Scene.Level == nil {
|
||||||
u.d.Flash("Can't drop doodads onto doodad drawings!")
|
u.d.Flash("Can't drop doodads onto doodad drawings!")
|
||||||
return
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -391,6 +399,8 @@ func (u *EditorUI) SetupCanvas(d *Doodle) *uix.Canvas {
|
||||||
log.Error("Error installing actor onDrop to canvas: %s", err)
|
log.Error("Error installing actor onDrop to canvas: %s", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
})
|
})
|
||||||
u.Supervisor.Add(drawing)
|
u.Supervisor.Add(drawing)
|
||||||
return drawing
|
return drawing
|
||||||
|
@ -439,18 +449,19 @@ func (u *EditorUI) SetupMenuBar(d *Doodle) *ui.Frame {
|
||||||
|
|
||||||
type menuButton struct {
|
type menuButton struct {
|
||||||
Text string
|
Text string
|
||||||
Click func(ui.EventData)
|
Click func(ui.EventData) error
|
||||||
}
|
}
|
||||||
buttons := []menuButton{
|
buttons := []menuButton{
|
||||||
menuButton{
|
menuButton{
|
||||||
Text: "New Level",
|
Text: "New Level",
|
||||||
Click: func(ed ui.EventData) {
|
Click: func(ed ui.EventData) error {
|
||||||
d.GotoNewMenu()
|
d.GotoNewMenu()
|
||||||
|
return nil
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
menuButton{
|
menuButton{
|
||||||
Text: "New Doodad",
|
Text: "New Doodad",
|
||||||
Click: func(ed ui.EventData) {
|
Click: func(ed ui.EventData) error {
|
||||||
d.Prompt("Doodad size [100]>", func(answer string) {
|
d.Prompt("Doodad size [100]>", func(answer string) {
|
||||||
size := balance.DoodadSize
|
size := balance.DoodadSize
|
||||||
if answer != "" {
|
if answer != "" {
|
||||||
|
@ -463,11 +474,13 @@ func (u *EditorUI) SetupMenuBar(d *Doodle) *ui.Frame {
|
||||||
}
|
}
|
||||||
d.NewDoodad(size)
|
d.NewDoodad(size)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
return nil
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
menuButton{
|
menuButton{
|
||||||
Text: "Save",
|
Text: "Save",
|
||||||
Click: func(ed ui.EventData) {
|
Click: func(ed ui.EventData) error {
|
||||||
if u.Scene.filename != "" {
|
if u.Scene.filename != "" {
|
||||||
saveFunc(u.Scene.filename)
|
saveFunc(u.Scene.filename)
|
||||||
} else {
|
} else {
|
||||||
|
@ -477,22 +490,64 @@ func (u *EditorUI) SetupMenuBar(d *Doodle) *ui.Frame {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
menuButton{
|
menuButton{
|
||||||
Text: "Save as...",
|
Text: "Save as...",
|
||||||
Click: func(ed ui.EventData) {
|
Click: func(ed ui.EventData) error {
|
||||||
d.Prompt("Save as filename>", func(answer string) {
|
d.Prompt("Save as filename>", func(answer string) {
|
||||||
if answer != "" {
|
if answer != "" {
|
||||||
saveFunc(answer)
|
saveFunc(answer)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
return nil
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
menuButton{
|
menuButton{
|
||||||
Text: "Load",
|
Text: "Load",
|
||||||
Click: func(ed ui.EventData) {
|
Click: func(ed ui.EventData) error {
|
||||||
d.GotoLoadMenu()
|
d.GotoLoadMenu()
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
menuButton{
|
||||||
|
Text: "Options",
|
||||||
|
Click: func(ed ui.EventData) error {
|
||||||
|
scene, _ := d.Scene.(*EditorScene)
|
||||||
|
log.Info("Opening the window")
|
||||||
|
|
||||||
|
// Open the New Level window in edit-settings mode.
|
||||||
|
if u.levelSettingsWindow == nil {
|
||||||
|
u.levelSettingsWindow = windows.NewAddEditLevel(windows.AddEditLevel{
|
||||||
|
Supervisor: u.Supervisor,
|
||||||
|
Engine: d.Engine,
|
||||||
|
EditLevel: scene.Level,
|
||||||
|
|
||||||
|
OnChangePageTypeAndWallpaper: func(pageType level.PageType, wallpaper string) {
|
||||||
|
log.Info("OnChangePageTypeAndWallpaper called: %+v, %+v", pageType, wallpaper)
|
||||||
|
scene.Level.PageType = pageType
|
||||||
|
scene.Level.Wallpaper = wallpaper
|
||||||
|
u.Canvas.LoadLevel(d.Engine, scene.Level)
|
||||||
|
},
|
||||||
|
OnCancel: func() {
|
||||||
|
u.levelSettingsWindow.Hide()
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
u.levelSettingsWindow.Compute(d.Engine)
|
||||||
|
u.levelSettingsWindow.Supervise(u.Supervisor)
|
||||||
|
|
||||||
|
// Center the window.
|
||||||
|
u.levelSettingsWindow.MoveTo(render.Point{
|
||||||
|
X: (d.width / 2) - (u.levelSettingsWindow.Size().W / 2),
|
||||||
|
Y: 60,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
u.levelSettingsWindow.Show()
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,8 +77,9 @@ func (u *EditorUI) setupDoodadFrame(e render.Engine, window *ui.Window) (*ui.Fra
|
||||||
Text: "<",
|
Text: "<",
|
||||||
Font: balance.MenuFont,
|
Font: balance.MenuFont,
|
||||||
}))
|
}))
|
||||||
leftBtn.Handle(ui.Click, func(ed ui.EventData) {
|
leftBtn.Handle(ui.Click, func(ed ui.EventData) error {
|
||||||
u.scrollDoodadFrame(-1)
|
u.scrollDoodadFrame(-1)
|
||||||
|
return nil
|
||||||
})
|
})
|
||||||
u.Supervisor.Add(leftBtn)
|
u.Supervisor.Add(leftBtn)
|
||||||
pager.Pack(leftBtn, ui.Pack{
|
pager.Pack(leftBtn, ui.Pack{
|
||||||
|
@ -100,8 +101,9 @@ func (u *EditorUI) setupDoodadFrame(e render.Engine, window *ui.Window) (*ui.Fra
|
||||||
Text: ">",
|
Text: ">",
|
||||||
Font: balance.MenuFont,
|
Font: balance.MenuFont,
|
||||||
}))
|
}))
|
||||||
rightBtn.Handle(ui.Click, func(ed ui.EventData) {
|
rightBtn.Handle(ui.Click, func(ed ui.EventData) error {
|
||||||
u.scrollDoodadFrame(1)
|
u.scrollDoodadFrame(1)
|
||||||
|
return nil
|
||||||
})
|
})
|
||||||
u.Supervisor.Add(rightBtn)
|
u.Supervisor.Add(rightBtn)
|
||||||
pager.Pack(rightBtn, ui.Pack{
|
pager.Pack(rightBtn, ui.Pack{
|
||||||
|
@ -188,9 +190,10 @@ func (u *EditorUI) setupDoodadFrame(e render.Engine, window *ui.Window) (*ui.Fra
|
||||||
// Begin the drag event to grab this Doodad.
|
// Begin the drag event to grab this Doodad.
|
||||||
// NOTE: The drag target is the EditorUI.Canvas in
|
// NOTE: The drag target is the EditorUI.Canvas in
|
||||||
// editor_ui.go#SetupCanvas()
|
// editor_ui.go#SetupCanvas()
|
||||||
btn.Handle(ui.MouseDown, func(ed ui.EventData) {
|
btn.Handle(ui.MouseDown, func(ed ui.EventData) error {
|
||||||
log.Warn("MouseDown on doodad %s (%s)", doodad.Filename, doodad.Title)
|
log.Warn("MouseDown on doodad %s (%s)", doodad.Filename, doodad.Title)
|
||||||
u.startDragActor(doodad, nil)
|
u.startDragActor(doodad, nil)
|
||||||
|
return nil
|
||||||
})
|
})
|
||||||
u.Supervisor.Add(btn)
|
u.Supervisor.Add(btn)
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ import (
|
||||||
func (u *EditorUI) SetupPalette(d *Doodle) *ui.Window {
|
func (u *EditorUI) SetupPalette(d *Doodle) *ui.Window {
|
||||||
window := ui.NewWindow("Palette")
|
window := ui.NewWindow("Palette")
|
||||||
window.ConfigureTitle(balance.TitleConfig)
|
window.ConfigureTitle(balance.TitleConfig)
|
||||||
window.TitleBar().Font = balance.TitleFont
|
// window.TitleBar().Font = balance.TitleFont
|
||||||
window.Configure(ui.Config{
|
window.Configure(ui.Config{
|
||||||
Background: balance.WindowBackground,
|
Background: balance.WindowBackground,
|
||||||
BorderColor: balance.WindowBorder,
|
BorderColor: balance.WindowBorder,
|
||||||
|
@ -53,15 +53,16 @@ func (u *EditorUI) setupPaletteFrame(window *ui.Window) *ui.Frame {
|
||||||
frame.SetBackground(balance.WindowBackground)
|
frame.SetBackground(balance.WindowBackground)
|
||||||
|
|
||||||
// Handler function for the radio buttons being clicked.
|
// Handler function for the radio buttons being clicked.
|
||||||
onClick := func(ed ui.EventData) {
|
onClick := func(ed ui.EventData) error {
|
||||||
name := u.selectedSwatch
|
name := u.selectedSwatch
|
||||||
swatch, ok := u.Canvas.Palette.Get(name)
|
swatch, ok := u.Canvas.Palette.Get(name)
|
||||||
if !ok {
|
if !ok {
|
||||||
log.Error("Palette onClick: couldn't get swatch named '%s' from palette", name)
|
log.Error("Palette onClick: couldn't get swatch named '%s' from palette", name)
|
||||||
return
|
return nil
|
||||||
}
|
}
|
||||||
log.Info("Set swatch: %s", swatch)
|
log.Info("Set swatch: %s", swatch)
|
||||||
u.Canvas.SetSwatch(swatch)
|
u.Canvas.SetSwatch(swatch)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw the radio buttons for the palette.
|
// Draw the radio buttons for the palette.
|
||||||
|
|
|
@ -148,8 +148,9 @@ func (u *EditorUI) SetupToolbar(d *Doodle) *ui.Frame {
|
||||||
var btnSize = btn.BoxThickness(2) + toolbarSpriteSize
|
var btnSize = btn.BoxThickness(2) + toolbarSpriteSize
|
||||||
btn.Resize(render.NewRect(btnSize, btnSize))
|
btn.Resize(render.NewRect(btnSize, btnSize))
|
||||||
|
|
||||||
btn.Handle(ui.Click, func(ed ui.EventData) {
|
btn.Handle(ui.Click, func(ed ui.EventData) error {
|
||||||
button.Click()
|
button.Click()
|
||||||
|
return nil
|
||||||
})
|
})
|
||||||
u.Supervisor.Add(btn)
|
u.Supervisor.Add(btn)
|
||||||
|
|
||||||
|
@ -256,8 +257,9 @@ func (u *EditorUI) SetupToolbar(d *Doodle) *ui.Frame {
|
||||||
Text: button.Label,
|
Text: button.Label,
|
||||||
Font: balance.SmallMonoFont,
|
Font: balance.SmallMonoFont,
|
||||||
}))
|
}))
|
||||||
btn.Handle(ui.Click, func(ed ui.EventData) {
|
btn.Handle(ui.Click, func(ed ui.EventData) error {
|
||||||
button.F()
|
button.F()
|
||||||
|
return nil
|
||||||
})
|
})
|
||||||
u.Supervisor.Add(btn)
|
u.Supervisor.Add(btn)
|
||||||
sizeBtnFrame.Pack(btn, ui.Pack{
|
sizeBtnFrame.Pack(btn, ui.Pack{
|
||||||
|
|
|
@ -87,8 +87,9 @@ func (s *GUITestScene) Setup(d *Doodle) error {
|
||||||
Text: label,
|
Text: label,
|
||||||
Font: balance.StatusFont,
|
Font: balance.StatusFont,
|
||||||
}))
|
}))
|
||||||
btn.Handle(ui.Click, func(ed ui.EventData) {
|
btn.Handle(ui.Click, func(ed ui.EventData) error {
|
||||||
d.Flash("%s clicked", btn)
|
d.Flash("%s clicked", btn)
|
||||||
|
return nil
|
||||||
})
|
})
|
||||||
s.Supervisor.Add(btn)
|
s.Supervisor.Add(btn)
|
||||||
leftFrame.Pack(btn, ui.Pack{
|
leftFrame.Pack(btn, ui.Pack{
|
||||||
|
@ -138,8 +139,9 @@ func (s *GUITestScene) Setup(d *Doodle) error {
|
||||||
Height: 20,
|
Height: 20,
|
||||||
BorderStyle: ui.BorderRaised,
|
BorderStyle: ui.BorderRaised,
|
||||||
})
|
})
|
||||||
btn.Handle(ui.Click, func(ed ui.EventData) {
|
btn.Handle(ui.Click, func(ed ui.EventData) error {
|
||||||
d.Flash("%s clicked", btn)
|
d.Flash("%s clicked", btn)
|
||||||
|
return nil
|
||||||
})
|
})
|
||||||
rowFrame.Pack(btn, ui.Pack{
|
rowFrame.Pack(btn, ui.Pack{
|
||||||
Side: ui.W,
|
Side: ui.W,
|
||||||
|
@ -215,8 +217,9 @@ func (s *GUITestScene) Setup(d *Doodle) error {
|
||||||
Font: balance.StatusFont,
|
Font: balance.StatusFont,
|
||||||
}))
|
}))
|
||||||
button1.SetBackground(render.Blue)
|
button1.SetBackground(render.Blue)
|
||||||
button1.Handle(ui.Click, func(ed ui.EventData) {
|
button1.Handle(ui.Click, func(ed ui.EventData) error {
|
||||||
d.NewMap()
|
d.NewMap()
|
||||||
|
return nil
|
||||||
})
|
})
|
||||||
|
|
||||||
log.Info("Button1 bg: %s", button1.Background())
|
log.Info("Button1 bg: %s", button1.Background())
|
||||||
|
@ -225,10 +228,11 @@ func (s *GUITestScene) Setup(d *Doodle) error {
|
||||||
Text: "Load Map",
|
Text: "Load Map",
|
||||||
Font: balance.StatusFont,
|
Font: balance.StatusFont,
|
||||||
}))
|
}))
|
||||||
button2.Handle(ui.Click, func(ed ui.EventData) {
|
button2.Handle(ui.Click, func(ed ui.EventData) error {
|
||||||
d.Prompt("Map name>", func(name string) {
|
d.Prompt("Map name>", func(name string) {
|
||||||
d.EditDrawing(name)
|
d.EditDrawing(name)
|
||||||
})
|
})
|
||||||
|
return nil
|
||||||
})
|
})
|
||||||
|
|
||||||
var align = ui.W
|
var align = ui.W
|
||||||
|
|
|
@ -85,8 +85,9 @@ func (s *MainScene) Setup(d *Doodle) error {
|
||||||
Padding: 4,
|
Padding: 4,
|
||||||
},
|
},
|
||||||
}))
|
}))
|
||||||
s.updateButton.Handle(ui.Click, func(ed ui.EventData) {
|
s.updateButton.Handle(ui.Click, func(ed ui.EventData) error {
|
||||||
native.OpenURL(s.updateInfo.DownloadURL)
|
native.OpenURL(s.updateInfo.DownloadURL)
|
||||||
|
return nil
|
||||||
})
|
})
|
||||||
s.updateButton.Compute(d.Engine)
|
s.updateButton.Compute(d.Engine)
|
||||||
s.updateButton.Hide()
|
s.updateButton.Hide()
|
||||||
|
@ -119,8 +120,9 @@ func (s *MainScene) Setup(d *Doodle) error {
|
||||||
Text: button.Name,
|
Text: button.Name,
|
||||||
Font: balance.StatusFont,
|
Font: balance.StatusFont,
|
||||||
}))
|
}))
|
||||||
btn.Handle(ui.Click, func(ed ui.EventData) {
|
btn.Handle(ui.Click, func(ed ui.EventData) error {
|
||||||
button.Func()
|
button.Func()
|
||||||
|
return nil
|
||||||
})
|
})
|
||||||
s.Supervisor.Add(btn)
|
s.Supervisor.Add(btn)
|
||||||
frame.Pack(btn, ui.Pack{
|
frame.Pack(btn, ui.Pack{
|
||||||
|
|
|
@ -1,14 +1,11 @@
|
||||||
package doodle
|
package doodle
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"git.kirsle.net/apps/doodle/pkg/balance"
|
|
||||||
"git.kirsle.net/apps/doodle/pkg/enum"
|
"git.kirsle.net/apps/doodle/pkg/enum"
|
||||||
"git.kirsle.net/apps/doodle/pkg/level"
|
"git.kirsle.net/apps/doodle/pkg/level"
|
||||||
"git.kirsle.net/apps/doodle/pkg/log"
|
"git.kirsle.net/apps/doodle/pkg/log"
|
||||||
"git.kirsle.net/apps/doodle/pkg/uix"
|
"git.kirsle.net/apps/doodle/pkg/uix"
|
||||||
"git.kirsle.net/apps/doodle/pkg/userdir"
|
"git.kirsle.net/apps/doodle/pkg/windows"
|
||||||
"git.kirsle.net/go/render"
|
"git.kirsle.net/go/render"
|
||||||
"git.kirsle.net/go/render/event"
|
"git.kirsle.net/go/render/event"
|
||||||
"git.kirsle.net/go/ui"
|
"git.kirsle.net/go/ui"
|
||||||
|
@ -105,6 +102,16 @@ func (s *MenuScene) Setup(d *Doodle) error {
|
||||||
d.Flash("No Valid StartupMenu Given to MenuScene")
|
d.Flash("No Valid StartupMenu Given to MenuScene")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Whatever window we got, give it window manager controls under Supervisor.
|
||||||
|
s.window.Supervise(s.Supervisor)
|
||||||
|
s.window.Compute(d.Engine)
|
||||||
|
|
||||||
|
// Center the window.
|
||||||
|
s.window.MoveTo(render.Point{
|
||||||
|
X: (d.width / 2) - (s.window.Size().W / 2),
|
||||||
|
Y: 60,
|
||||||
|
})
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -121,373 +128,43 @@ func (s *MenuScene) configureCanvas(e render.Engine, pageType level.PageType, wa
|
||||||
|
|
||||||
// setupNewWindow sets up the UI for the "New" window.
|
// setupNewWindow sets up the UI for the "New" window.
|
||||||
func (s *MenuScene) setupNewWindow(d *Doodle) error {
|
func (s *MenuScene) setupNewWindow(d *Doodle) error {
|
||||||
// Default scene options.
|
window := windows.NewAddEditLevel(windows.AddEditLevel{
|
||||||
s.newPageType = level.Bounded.String()
|
Supervisor: s.Supervisor,
|
||||||
s.newWallpaper = "notebook.png"
|
Engine: d.Engine,
|
||||||
|
OnChangePageTypeAndWallpaper: func(pageType level.PageType, wallpaper string) {
|
||||||
window := ui.NewWindow("New Drawing")
|
log.Info("OnChangePageTypeAndWallpaper called: %+v, %+v", pageType, wallpaper)
|
||||||
window.Configure(ui.Config{
|
s.configureCanvas(d.Engine, pageType, wallpaper)
|
||||||
Width: int(float64(d.width) * 0.75),
|
},
|
||||||
Height: int(float64(d.height) * 0.75),
|
OnCreateNewLevel: func(lvl *level.Level) {
|
||||||
Background: render.Grey,
|
d.Goto(&EditorScene{
|
||||||
})
|
DrawingType: enum.LevelDrawing,
|
||||||
window.Compute(d.Engine)
|
Level: lvl,
|
||||||
|
|
||||||
{
|
|
||||||
frame := ui.NewFrame("New Level Frame")
|
|
||||||
window.Pack(frame, ui.Pack{
|
|
||||||
Side: ui.N,
|
|
||||||
Fill: true,
|
|
||||||
Expand: true,
|
|
||||||
})
|
|
||||||
|
|
||||||
/******************
|
|
||||||
* Frame for selecting Page Type
|
|
||||||
******************/
|
|
||||||
|
|
||||||
label1 := ui.NewLabel(ui.Label{
|
|
||||||
Text: "Page Type",
|
|
||||||
Font: balance.LabelFont,
|
|
||||||
})
|
|
||||||
frame.Pack(label1, ui.Pack{
|
|
||||||
Side: ui.N,
|
|
||||||
FillX: true,
|
|
||||||
})
|
|
||||||
|
|
||||||
typeFrame := ui.NewFrame("Page Type Options Frame")
|
|
||||||
frame.Pack(typeFrame, ui.Pack{
|
|
||||||
Side: ui.N,
|
|
||||||
FillX: true,
|
|
||||||
})
|
|
||||||
|
|
||||||
type typeObj struct {
|
|
||||||
Name string
|
|
||||||
Value level.PageType
|
|
||||||
}
|
|
||||||
var types = []typeObj{
|
|
||||||
{"Unbounded", level.Unbounded},
|
|
||||||
{"Bounded", level.Bounded},
|
|
||||||
{"No Negative Space", level.NoNegativeSpace},
|
|
||||||
// {"Bordered (TODO)", level.Bordered},
|
|
||||||
}
|
|
||||||
for _, t := range types {
|
|
||||||
// TODO: Hide some options for the free version of the game.
|
|
||||||
// - At launch only Bounded and Bordered will be available
|
|
||||||
// in the shareware version.
|
|
||||||
// - For now, only hide Bordered as it's not yet implemented.
|
|
||||||
// --------
|
|
||||||
// if balance.FreeVersion {
|
|
||||||
// if t.Value == level.Bordered {
|
|
||||||
// continue
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
func(t typeObj) {
|
|
||||||
radio := ui.NewRadioButton(t.Name,
|
|
||||||
&s.newPageType,
|
|
||||||
t.Value.String(),
|
|
||||||
ui.NewLabel(ui.Label{
|
|
||||||
Text: t.Name,
|
|
||||||
Font: balance.MenuFont,
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
radio.Handle(ui.Click, func(ed ui.EventData) {
|
|
||||||
s.configureCanvas(d.Engine, t.Value, s.newWallpaper)
|
|
||||||
})
|
|
||||||
s.Supervisor.Add(radio)
|
|
||||||
typeFrame.Pack(radio, ui.Pack{
|
|
||||||
Side: ui.W,
|
|
||||||
PadX: 4,
|
|
||||||
})
|
|
||||||
}(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
/******************
|
|
||||||
* Frame for selecting Level Wallpaper
|
|
||||||
******************/
|
|
||||||
|
|
||||||
label2 := ui.NewLabel(ui.Label{
|
|
||||||
Text: "Wallpaper",
|
|
||||||
Font: balance.LabelFont,
|
|
||||||
})
|
|
||||||
frame.Pack(label2, ui.Pack{
|
|
||||||
Side: ui.N,
|
|
||||||
FillX: true,
|
|
||||||
})
|
|
||||||
|
|
||||||
wpFrame := ui.NewFrame("Wallpaper Frame")
|
|
||||||
frame.Pack(wpFrame, ui.Pack{
|
|
||||||
Side: ui.N,
|
|
||||||
FillX: true,
|
|
||||||
})
|
|
||||||
|
|
||||||
type wallpaperObj struct {
|
|
||||||
Name string
|
|
||||||
Value string
|
|
||||||
}
|
|
||||||
var wallpapers = []wallpaperObj{
|
|
||||||
{"Notebook", "notebook.png"},
|
|
||||||
{"Blueprint", "blueprint.png"},
|
|
||||||
{"Legal Pad", "legal.png"},
|
|
||||||
{"Pure White", "white.png"},
|
|
||||||
// {"Placemat", "placemat.png"},
|
|
||||||
}
|
|
||||||
for _, t := range wallpapers {
|
|
||||||
func(t wallpaperObj) {
|
|
||||||
radio := ui.NewRadioButton(t.Name, &s.newWallpaper, t.Value, ui.NewLabel(ui.Label{
|
|
||||||
Text: t.Name,
|
|
||||||
Font: balance.MenuFont,
|
|
||||||
}))
|
|
||||||
radio.Handle(ui.Click, func(ed ui.EventData) {
|
|
||||||
log.Info("Set wallpaper to %s", t.Value)
|
|
||||||
if pageType, ok := level.PageTypeFromString(s.newPageType); ok {
|
|
||||||
s.configureCanvas(d.Engine, pageType, t.Value)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
s.Supervisor.Add(radio)
|
|
||||||
wpFrame.Pack(radio, ui.Pack{
|
|
||||||
Side: ui.W,
|
|
||||||
PadX: 4,
|
|
||||||
})
|
|
||||||
}(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
/******************
|
|
||||||
* Confirm/cancel buttons.
|
|
||||||
******************/
|
|
||||||
|
|
||||||
bottomFrame := ui.NewFrame("Button Frame")
|
|
||||||
// bottomFrame.Configure(ui.Config{
|
|
||||||
// BorderSize: 1,
|
|
||||||
// BorderStyle: ui.BorderSunken,
|
|
||||||
// BorderColor: render.Black,
|
|
||||||
// })
|
|
||||||
// bottomFrame.SetBackground(render.Grey)
|
|
||||||
frame.Pack(bottomFrame, ui.Pack{
|
|
||||||
Side: ui.N,
|
|
||||||
FillX: true,
|
|
||||||
PadY: 8,
|
|
||||||
})
|
|
||||||
|
|
||||||
var buttons = []struct {
|
|
||||||
Label string
|
|
||||||
F func(ui.EventData)
|
|
||||||
}{
|
|
||||||
{"Continue", func(ed ui.EventData) {
|
|
||||||
d.Flash("Create new map with %s page type and %s wallpaper", s.newPageType, s.newWallpaper)
|
|
||||||
pageType, ok := level.PageTypeFromString(s.newPageType)
|
|
||||||
if !ok {
|
|
||||||
d.Flash("Invalid Page Type '%s'", s.newPageType)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
lvl := level.New()
|
|
||||||
lvl.Palette = level.DefaultPalette()
|
|
||||||
lvl.Wallpaper = s.newWallpaper
|
|
||||||
lvl.PageType = pageType
|
|
||||||
|
|
||||||
// Blueprint theme palette for the dark wallpaper color.
|
|
||||||
if lvl.Wallpaper == "blueprint.png" {
|
|
||||||
lvl.Palette = level.NewBlueprintPalette()
|
|
||||||
}
|
|
||||||
|
|
||||||
d.Goto(&EditorScene{
|
|
||||||
DrawingType: enum.LevelDrawing,
|
|
||||||
Level: lvl,
|
|
||||||
})
|
|
||||||
}},
|
|
||||||
|
|
||||||
{"Cancel", func(ed ui.EventData) {
|
|
||||||
d.Goto(&MainScene{})
|
|
||||||
}},
|
|
||||||
}
|
|
||||||
for _, t := range buttons {
|
|
||||||
btn := ui.NewButton(t.Label, ui.NewLabel(ui.Label{
|
|
||||||
Text: t.Label,
|
|
||||||
Font: balance.MenuFont,
|
|
||||||
}))
|
|
||||||
btn.Handle(ui.Click, t.F)
|
|
||||||
s.Supervisor.Add(btn)
|
|
||||||
bottomFrame.Pack(btn, ui.Pack{
|
|
||||||
Side: ui.W,
|
|
||||||
PadX: 4,
|
|
||||||
PadY: 8,
|
|
||||||
})
|
})
|
||||||
}
|
},
|
||||||
}
|
OnCancel: func() {
|
||||||
|
d.Goto(&MainScene{})
|
||||||
|
},
|
||||||
|
})
|
||||||
s.window = window
|
s.window = window
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// setupLoadWindow sets up the UI for the "New" window.
|
// setupLoadWindow sets up the UI for the "New" window.
|
||||||
func (s *MenuScene) setupLoadWindow(d *Doodle) error {
|
func (s *MenuScene) setupLoadWindow(d *Doodle) error {
|
||||||
window := ui.NewWindow("Open Drawing")
|
window := windows.NewOpenLevelEditor(windows.OpenLevelEditor{
|
||||||
window.Configure(ui.Config{
|
Supervisor: s.Supervisor,
|
||||||
Width: int(float64(d.width) * 0.75),
|
Engine: d.Engine,
|
||||||
Height: int(float64(d.height) * 0.75),
|
LoadForPlay: s.loadForPlay,
|
||||||
Background: render.Grey,
|
OnPlayLevel: func(filename string) {
|
||||||
|
d.PlayLevel(filename)
|
||||||
|
},
|
||||||
|
OnEditLevel: func(filename string) {
|
||||||
|
d.EditFile(filename)
|
||||||
|
},
|
||||||
|
OnCancel: func() {
|
||||||
|
d.Goto(&MainScene{})
|
||||||
|
},
|
||||||
})
|
})
|
||||||
window.Compute(d.Engine)
|
|
||||||
|
|
||||||
{
|
|
||||||
frame := ui.NewFrame("Open Drawing Frame")
|
|
||||||
window.Pack(frame, ui.Pack{
|
|
||||||
Side: ui.N,
|
|
||||||
Fill: true,
|
|
||||||
Expand: true,
|
|
||||||
})
|
|
||||||
|
|
||||||
/******************
|
|
||||||
* Frame for selecting User Levels
|
|
||||||
******************/
|
|
||||||
|
|
||||||
label1 := ui.NewLabel(ui.Label{
|
|
||||||
Text: "Levels",
|
|
||||||
Font: balance.LabelFont,
|
|
||||||
})
|
|
||||||
frame.Pack(label1, ui.Pack{
|
|
||||||
Side: ui.N,
|
|
||||||
FillX: true,
|
|
||||||
})
|
|
||||||
|
|
||||||
// Get the user's levels.
|
|
||||||
levels, _ := userdir.ListLevels()
|
|
||||||
|
|
||||||
// Embedded levels, TODO
|
|
||||||
sysLevels, _ := level.ListSystemLevels()
|
|
||||||
levels = append(levels, sysLevels...)
|
|
||||||
|
|
||||||
lvlRow := ui.NewFrame("Level Row 0")
|
|
||||||
frame.Pack(lvlRow, ui.Pack{
|
|
||||||
Side: ui.N,
|
|
||||||
FillX: true,
|
|
||||||
PadY: 1,
|
|
||||||
})
|
|
||||||
for i, lvl := range levels {
|
|
||||||
func(i int, lvl string) {
|
|
||||||
log.Info("Add file %s to row %s", lvl, lvlRow.Name)
|
|
||||||
btn := ui.NewButton("Level Btn", ui.NewLabel(ui.Label{
|
|
||||||
Text: lvl,
|
|
||||||
Font: balance.MenuFont,
|
|
||||||
}))
|
|
||||||
btn.Handle(ui.Click, func(ed ui.EventData) {
|
|
||||||
if s.loadForPlay {
|
|
||||||
d.PlayLevel(lvl)
|
|
||||||
} else {
|
|
||||||
d.EditFile(lvl)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
s.Supervisor.Add(btn)
|
|
||||||
lvlRow.Pack(btn, ui.Pack{
|
|
||||||
Side: ui.W,
|
|
||||||
Expand: true,
|
|
||||||
Fill: true,
|
|
||||||
})
|
|
||||||
|
|
||||||
if i > 0 && (i+1)%4 == 0 {
|
|
||||||
log.Warn("i=%d wrapped at mod 4", i)
|
|
||||||
lvlRow = ui.NewFrame(fmt.Sprintf("Level Row %d", i))
|
|
||||||
frame.Pack(lvlRow, ui.Pack{
|
|
||||||
Side: ui.N,
|
|
||||||
FillX: true,
|
|
||||||
PadY: 1,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}(i, lvl)
|
|
||||||
}
|
|
||||||
|
|
||||||
/******************
|
|
||||||
* Frame for selecting User Doodads
|
|
||||||
******************/
|
|
||||||
|
|
||||||
// Doodads not shown if we're loading a map to play, nor are they
|
|
||||||
// available to the free version.
|
|
||||||
if !s.loadForPlay && !balance.FreeVersion {
|
|
||||||
label2 := ui.NewLabel(ui.Label{
|
|
||||||
Text: "Doodads",
|
|
||||||
Font: balance.LabelFont,
|
|
||||||
})
|
|
||||||
frame.Pack(label2, ui.Pack{
|
|
||||||
Side: ui.N,
|
|
||||||
FillX: true,
|
|
||||||
})
|
|
||||||
|
|
||||||
files, _ := userdir.ListDoodads()
|
|
||||||
ddRow := ui.NewFrame("Doodad Row 0")
|
|
||||||
frame.Pack(ddRow, ui.Pack{
|
|
||||||
Side: ui.N,
|
|
||||||
FillX: true,
|
|
||||||
PadY: 1,
|
|
||||||
})
|
|
||||||
for i, dd := range files {
|
|
||||||
func(i int, dd string) {
|
|
||||||
btn := ui.NewButton("Doodad Btn", ui.NewLabel(ui.Label{
|
|
||||||
Text: dd,
|
|
||||||
Font: balance.MenuFont,
|
|
||||||
}))
|
|
||||||
btn.Handle(ui.Click, func(ed ui.EventData) {
|
|
||||||
d.EditFile(dd)
|
|
||||||
})
|
|
||||||
s.Supervisor.Add(btn)
|
|
||||||
ddRow.Pack(btn, ui.Pack{
|
|
||||||
Side: ui.W,
|
|
||||||
Expand: true,
|
|
||||||
Fill: true,
|
|
||||||
})
|
|
||||||
|
|
||||||
if i > 0 && (i+1)%4 == 0 {
|
|
||||||
ddRow = ui.NewFrame(fmt.Sprintf("Doodad Row %d", i))
|
|
||||||
frame.Pack(ddRow, ui.Pack{
|
|
||||||
Side: ui.N,
|
|
||||||
FillX: true,
|
|
||||||
PadY: 1,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}(i, dd)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/******************
|
|
||||||
* Confirm/cancel buttons.
|
|
||||||
******************/
|
|
||||||
|
|
||||||
bottomFrame := ui.NewFrame("Button Frame")
|
|
||||||
// bottomFrame.Configure(ui.Config{
|
|
||||||
// BorderSize: 1,
|
|
||||||
// BorderStyle: ui.BorderSunken,
|
|
||||||
// BorderColor: render.Black,
|
|
||||||
// })
|
|
||||||
// bottomFrame.SetBackground(render.Grey)
|
|
||||||
frame.Pack(bottomFrame, ui.Pack{
|
|
||||||
Side: ui.N,
|
|
||||||
FillX: true,
|
|
||||||
PadY: 8,
|
|
||||||
})
|
|
||||||
|
|
||||||
var buttons = []struct {
|
|
||||||
Label string
|
|
||||||
F func(ui.EventData)
|
|
||||||
}{
|
|
||||||
{"Cancel", func(ed ui.EventData) {
|
|
||||||
d.Goto(&MainScene{})
|
|
||||||
}},
|
|
||||||
}
|
|
||||||
for _, t := range buttons {
|
|
||||||
btn := ui.NewButton(t.Label, ui.NewLabel(ui.Label{
|
|
||||||
Text: t.Label,
|
|
||||||
Font: balance.MenuFont,
|
|
||||||
}))
|
|
||||||
btn.Handle(ui.Click, t.F)
|
|
||||||
s.Supervisor.Add(btn)
|
|
||||||
bottomFrame.Pack(btn, ui.Pack{
|
|
||||||
Side: ui.W,
|
|
||||||
PadX: 4,
|
|
||||||
PadY: 8,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
s.window = window
|
s.window = window
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -518,12 +195,12 @@ func (s *MenuScene) Draw(d *Doodle) error {
|
||||||
// Draw the background canvas.
|
// Draw the background canvas.
|
||||||
s.canvas.Present(d.Engine, render.Origin)
|
s.canvas.Present(d.Engine, render.Origin)
|
||||||
|
|
||||||
|
// TODO: if I don't call Compute here, buttons in the Edit Window get all
|
||||||
|
// bunched up. Investigate why later.
|
||||||
s.window.Compute(d.Engine)
|
s.window.Compute(d.Engine)
|
||||||
s.window.MoveTo(render.Point{
|
|
||||||
X: (d.width / 2) - (s.window.Size().W / 2),
|
// Draw the window managed by Supervisor.
|
||||||
Y: 60,
|
s.Supervisor.Present(d.Engine)
|
||||||
})
|
|
||||||
s.window.Present(d.Engine, s.window.Point())
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -119,8 +119,9 @@ func (s *PlayScene) Setup(d *Doodle) error {
|
||||||
Text: "Edit (E)",
|
Text: "Edit (E)",
|
||||||
Font: balance.PlayButtonFont,
|
Font: balance.PlayButtonFont,
|
||||||
}))
|
}))
|
||||||
s.editButton.Handle(ui.Click, func(ed ui.EventData) {
|
s.editButton.Handle(ui.Click, func(ed ui.EventData) error {
|
||||||
s.EditLevel()
|
s.EditLevel()
|
||||||
|
return nil
|
||||||
})
|
})
|
||||||
s.supervisor.Add(s.editButton)
|
s.supervisor.Add(s.editButton)
|
||||||
|
|
||||||
|
@ -300,8 +301,9 @@ func (s *PlayScene) SetupAlertbox() {
|
||||||
Font: balance.LabelFont,
|
Font: balance.LabelFont,
|
||||||
Text: text,
|
Text: text,
|
||||||
}))
|
}))
|
||||||
btn.Handle(ui.Click, func(ed ui.EventData) {
|
btn.Handle(ui.Click, func(ed ui.EventData) error {
|
||||||
handler()
|
handler()
|
||||||
|
return nil
|
||||||
})
|
})
|
||||||
bottomFrame.Pack(btn, ui.Pack{
|
bottomFrame.Pack(btn, ui.Pack{
|
||||||
Side: ui.W,
|
Side: ui.W,
|
||||||
|
|
|
@ -198,6 +198,13 @@ func (a *Actor) RemoveItem(itemName string, quantity int) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ClearInventory removes all items from the actor's inventory.
|
||||||
|
func (a *Actor) ClearInventory() {
|
||||||
|
a.muInventory.Lock()
|
||||||
|
a.inventory = map[string]int{}
|
||||||
|
a.muInventory.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
// HasItem checks the actor's inventory for the item and returns the quantity.
|
// HasItem checks the actor's inventory for the item and returns the quantity.
|
||||||
//
|
//
|
||||||
// A return value of -1 means the item was not found.
|
// A return value of -1 means the item was not found.
|
||||||
|
|
242
pkg/windows/add_edit_level.go
Normal file
242
pkg/windows/add_edit_level.go
Normal file
|
@ -0,0 +1,242 @@
|
||||||
|
package windows
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.kirsle.net/apps/doodle/pkg/balance"
|
||||||
|
"git.kirsle.net/apps/doodle/pkg/level"
|
||||||
|
"git.kirsle.net/apps/doodle/pkg/shmem"
|
||||||
|
"git.kirsle.net/go/render"
|
||||||
|
"git.kirsle.net/go/ui"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AddEditLevel is the "Create New Level & Edit Level Properties" window
|
||||||
|
type AddEditLevel struct {
|
||||||
|
Supervisor *ui.Supervisor
|
||||||
|
Engine render.Engine
|
||||||
|
|
||||||
|
// Editing settings for an existing level?
|
||||||
|
EditLevel *level.Level
|
||||||
|
|
||||||
|
// Callback functions.
|
||||||
|
OnChangePageTypeAndWallpaper func(pageType level.PageType, wallpaper string)
|
||||||
|
OnCreateNewLevel func(*level.Level)
|
||||||
|
OnCancel func()
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewAddEditLevel initializes the window.
|
||||||
|
func NewAddEditLevel(config AddEditLevel) *ui.Window {
|
||||||
|
// Default options.
|
||||||
|
var (
|
||||||
|
newPageType = level.Bounded.String()
|
||||||
|
newWallpaper = "notebook.png"
|
||||||
|
isNewLevel = config.EditLevel == nil
|
||||||
|
)
|
||||||
|
|
||||||
|
// Given a level to edit?
|
||||||
|
if config.EditLevel != nil {
|
||||||
|
newPageType = config.EditLevel.PageType.String()
|
||||||
|
newWallpaper = config.EditLevel.Wallpaper
|
||||||
|
}
|
||||||
|
|
||||||
|
window := ui.NewWindow("New Drawing")
|
||||||
|
window.Configure(ui.Config{
|
||||||
|
Width: 540,
|
||||||
|
Height: 350,
|
||||||
|
Background: render.Grey,
|
||||||
|
})
|
||||||
|
|
||||||
|
{
|
||||||
|
frame := ui.NewFrame("New Level Frame")
|
||||||
|
window.Pack(frame, ui.Pack{
|
||||||
|
Side: ui.N,
|
||||||
|
Fill: true,
|
||||||
|
Expand: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
/******************
|
||||||
|
* Frame for selecting Page Type
|
||||||
|
******************/
|
||||||
|
|
||||||
|
label1 := ui.NewLabel(ui.Label{
|
||||||
|
Text: "Page Type",
|
||||||
|
Font: balance.LabelFont,
|
||||||
|
})
|
||||||
|
frame.Pack(label1, ui.Pack{
|
||||||
|
Side: ui.N,
|
||||||
|
FillX: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
typeFrame := ui.NewFrame("Page Type Options Frame")
|
||||||
|
frame.Pack(typeFrame, ui.Pack{
|
||||||
|
Side: ui.N,
|
||||||
|
FillX: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
type typeObj struct {
|
||||||
|
Name string
|
||||||
|
Value level.PageType
|
||||||
|
}
|
||||||
|
var types = []typeObj{
|
||||||
|
{"Unbounded", level.Unbounded},
|
||||||
|
{"Bounded", level.Bounded},
|
||||||
|
{"No Negative Space", level.NoNegativeSpace},
|
||||||
|
// {"Bordered (TODO)", level.Bordered},
|
||||||
|
}
|
||||||
|
for _, t := range types {
|
||||||
|
// TODO: Hide some options for the free version of the game.
|
||||||
|
// - At launch only Bounded and Bordered will be available
|
||||||
|
// in the shareware version.
|
||||||
|
// - For now, only hide Bordered as it's not yet implemented.
|
||||||
|
// --------
|
||||||
|
// if balance.FreeVersion {
|
||||||
|
// if t.Value == level.Bordered {
|
||||||
|
// continue
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
func(t typeObj) {
|
||||||
|
radio := ui.NewRadioButton(t.Name,
|
||||||
|
&newPageType,
|
||||||
|
t.Value.String(),
|
||||||
|
ui.NewLabel(ui.Label{
|
||||||
|
Text: t.Name,
|
||||||
|
Font: balance.MenuFont,
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
radio.Handle(ui.Click, func(ed ui.EventData) error {
|
||||||
|
config.OnChangePageTypeAndWallpaper(t.Value, newWallpaper)
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
config.Supervisor.Add(radio)
|
||||||
|
typeFrame.Pack(radio, ui.Pack{
|
||||||
|
Side: ui.W,
|
||||||
|
PadX: 4,
|
||||||
|
})
|
||||||
|
}(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************
|
||||||
|
* Frame for selecting Level Wallpaper
|
||||||
|
******************/
|
||||||
|
|
||||||
|
label2 := ui.NewLabel(ui.Label{
|
||||||
|
// Text: "Wallpaper",
|
||||||
|
TextVariable: &newWallpaper,
|
||||||
|
Font: balance.LabelFont,
|
||||||
|
})
|
||||||
|
frame.Pack(label2, ui.Pack{
|
||||||
|
Side: ui.N,
|
||||||
|
FillX: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
wpFrame := ui.NewFrame("Wallpaper Frame")
|
||||||
|
frame.Pack(wpFrame, ui.Pack{
|
||||||
|
Side: ui.N,
|
||||||
|
FillX: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
type wallpaperObj struct {
|
||||||
|
Name string
|
||||||
|
Value string
|
||||||
|
}
|
||||||
|
var wallpapers = []wallpaperObj{
|
||||||
|
{"Notebook", "notebook.png"},
|
||||||
|
{"Blueprint", "blueprint.png"},
|
||||||
|
{"Legal Pad", "legal.png"},
|
||||||
|
{"Pure White", "white.png"},
|
||||||
|
// {"Placemat", "placemat.png"},
|
||||||
|
}
|
||||||
|
for _, t := range wallpapers {
|
||||||
|
func(t wallpaperObj) {
|
||||||
|
radio := ui.NewRadioButton(t.Name, &newWallpaper, t.Value, ui.NewLabel(ui.Label{
|
||||||
|
Text: t.Name,
|
||||||
|
Font: balance.MenuFont,
|
||||||
|
}))
|
||||||
|
radio.Handle(ui.Click, func(ed ui.EventData) error {
|
||||||
|
if pageType, ok := level.PageTypeFromString(newPageType); ok {
|
||||||
|
config.OnChangePageTypeAndWallpaper(pageType, t.Value)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
config.Supervisor.Add(radio)
|
||||||
|
wpFrame.Pack(radio, ui.Pack{
|
||||||
|
Side: ui.W,
|
||||||
|
PadX: 4,
|
||||||
|
})
|
||||||
|
}(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************
|
||||||
|
* Confirm/cancel buttons.
|
||||||
|
******************/
|
||||||
|
|
||||||
|
bottomFrame := ui.NewFrame("Button Frame")
|
||||||
|
// bottomFrame.Configure(ui.Config{
|
||||||
|
// BorderSize: 1,
|
||||||
|
// BorderStyle: ui.BorderSunken,
|
||||||
|
// BorderColor: render.Black,
|
||||||
|
// })
|
||||||
|
// bottomFrame.SetBackground(render.Grey)
|
||||||
|
frame.Pack(bottomFrame, ui.Pack{
|
||||||
|
Side: ui.N,
|
||||||
|
FillX: true,
|
||||||
|
PadY: 8,
|
||||||
|
})
|
||||||
|
|
||||||
|
var buttons = []struct {
|
||||||
|
Label string
|
||||||
|
F func(ui.EventData) error
|
||||||
|
}{
|
||||||
|
{"Continue", func(ed ui.EventData) error {
|
||||||
|
shmem.Flash("Create new map with %s page type and %s wallpaper", newPageType, newWallpaper)
|
||||||
|
pageType, ok := level.PageTypeFromString(newPageType)
|
||||||
|
if !ok {
|
||||||
|
shmem.Flash("Invalid Page Type '%s'", newPageType)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
lvl := level.New()
|
||||||
|
lvl.Palette = level.DefaultPalette()
|
||||||
|
lvl.Wallpaper = newWallpaper
|
||||||
|
lvl.PageType = pageType
|
||||||
|
|
||||||
|
// Blueprint theme palette for the dark wallpaper color.
|
||||||
|
if lvl.Wallpaper == "blueprint.png" {
|
||||||
|
lvl.Palette = level.NewBlueprintPalette()
|
||||||
|
}
|
||||||
|
|
||||||
|
config.OnCreateNewLevel(lvl)
|
||||||
|
return nil
|
||||||
|
}},
|
||||||
|
|
||||||
|
{"Cancel", func(ed ui.EventData) error {
|
||||||
|
config.OnCancel()
|
||||||
|
return nil
|
||||||
|
}},
|
||||||
|
|
||||||
|
// OK button is for editing an existing level.
|
||||||
|
{"OK", func(ed ui.EventData) error {
|
||||||
|
config.OnCancel()
|
||||||
|
return nil
|
||||||
|
}},
|
||||||
|
}
|
||||||
|
for _, t := range buttons {
|
||||||
|
// If we're editing settings on an existing level, skip the Continue.
|
||||||
|
if isNewLevel && t.Label == "OK" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
btn := ui.NewButton(t.Label, ui.NewLabel(ui.Label{
|
||||||
|
Text: t.Label,
|
||||||
|
Font: balance.MenuFont,
|
||||||
|
}))
|
||||||
|
btn.Handle(ui.Click, t.F)
|
||||||
|
config.Supervisor.Add(btn)
|
||||||
|
bottomFrame.Pack(btn, ui.Pack{
|
||||||
|
Side: ui.W,
|
||||||
|
PadX: 4,
|
||||||
|
PadY: 8,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return window
|
||||||
|
}
|
203
pkg/windows/open_level_editor.go
Normal file
203
pkg/windows/open_level_editor.go
Normal file
|
@ -0,0 +1,203 @@
|
||||||
|
package windows
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"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/userdir"
|
||||||
|
"git.kirsle.net/go/render"
|
||||||
|
"git.kirsle.net/go/ui"
|
||||||
|
)
|
||||||
|
|
||||||
|
// OpenLevelEditor is the "Open a Level to Edit It" window
|
||||||
|
type OpenLevelEditor struct {
|
||||||
|
Supervisor *ui.Supervisor
|
||||||
|
Engine render.Engine
|
||||||
|
|
||||||
|
// Load it for playing instead of editing?
|
||||||
|
LoadForPlay bool
|
||||||
|
|
||||||
|
// Callback functions.
|
||||||
|
OnPlayLevel func(filename string)
|
||||||
|
OnEditLevel func(filename string)
|
||||||
|
OnCancel func()
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewOpenLevelEditor initializes the window.
|
||||||
|
func NewOpenLevelEditor(config OpenLevelEditor) *ui.Window {
|
||||||
|
var (
|
||||||
|
width, height = config.Engine.WindowSize()
|
||||||
|
)
|
||||||
|
|
||||||
|
window := ui.NewWindow("Open Drawing")
|
||||||
|
window.Configure(ui.Config{
|
||||||
|
Width: int(float64(width) * 0.75),
|
||||||
|
Height: int(float64(height) * 0.75),
|
||||||
|
Background: render.Grey,
|
||||||
|
})
|
||||||
|
|
||||||
|
{
|
||||||
|
frame := ui.NewFrame("Open Drawing Frame")
|
||||||
|
window.Pack(frame, ui.Pack{
|
||||||
|
Side: ui.N,
|
||||||
|
Fill: true,
|
||||||
|
Expand: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
/******************
|
||||||
|
* Frame for selecting User Levels
|
||||||
|
******************/
|
||||||
|
|
||||||
|
label1 := ui.NewLabel(ui.Label{
|
||||||
|
Text: "Levels",
|
||||||
|
Font: balance.LabelFont,
|
||||||
|
})
|
||||||
|
frame.Pack(label1, ui.Pack{
|
||||||
|
Side: ui.N,
|
||||||
|
FillX: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
// Get the user's levels.
|
||||||
|
levels, _ := userdir.ListLevels()
|
||||||
|
|
||||||
|
// Embedded levels, TODO
|
||||||
|
sysLevels, _ := level.ListSystemLevels()
|
||||||
|
levels = append(levels, sysLevels...)
|
||||||
|
|
||||||
|
lvlRow := ui.NewFrame("Level Row 0")
|
||||||
|
frame.Pack(lvlRow, ui.Pack{
|
||||||
|
Side: ui.N,
|
||||||
|
FillX: true,
|
||||||
|
PadY: 1,
|
||||||
|
})
|
||||||
|
for i, lvl := range levels {
|
||||||
|
func(i int, lvl string) {
|
||||||
|
log.Info("Add file %s to row %s", lvl, lvlRow.Name)
|
||||||
|
btn := ui.NewButton("Level Btn", ui.NewLabel(ui.Label{
|
||||||
|
Text: lvl,
|
||||||
|
Font: balance.MenuFont,
|
||||||
|
}))
|
||||||
|
btn.Handle(ui.Click, func(ed ui.EventData) error {
|
||||||
|
if config.LoadForPlay {
|
||||||
|
config.OnPlayLevel(lvl)
|
||||||
|
} else {
|
||||||
|
config.OnEditLevel(lvl)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
config.Supervisor.Add(btn)
|
||||||
|
lvlRow.Pack(btn, ui.Pack{
|
||||||
|
Side: ui.W,
|
||||||
|
Expand: true,
|
||||||
|
Fill: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
if i > 0 && (i+1)%4 == 0 {
|
||||||
|
log.Warn("i=%d wrapped at mod 4", i)
|
||||||
|
lvlRow = ui.NewFrame(fmt.Sprintf("Level Row %d", i))
|
||||||
|
frame.Pack(lvlRow, ui.Pack{
|
||||||
|
Side: ui.N,
|
||||||
|
FillX: true,
|
||||||
|
PadY: 1,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}(i, lvl)
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************
|
||||||
|
* Frame for selecting User Doodads
|
||||||
|
******************/
|
||||||
|
|
||||||
|
// Doodads not shown if we're loading a map to play, nor are they
|
||||||
|
// available to the free version.
|
||||||
|
if !config.LoadForPlay && !balance.FreeVersion {
|
||||||
|
label2 := ui.NewLabel(ui.Label{
|
||||||
|
Text: "Doodads",
|
||||||
|
Font: balance.LabelFont,
|
||||||
|
})
|
||||||
|
frame.Pack(label2, ui.Pack{
|
||||||
|
Side: ui.N,
|
||||||
|
FillX: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
files, _ := userdir.ListDoodads()
|
||||||
|
ddRow := ui.NewFrame("Doodad Row 0")
|
||||||
|
frame.Pack(ddRow, ui.Pack{
|
||||||
|
Side: ui.N,
|
||||||
|
FillX: true,
|
||||||
|
PadY: 1,
|
||||||
|
})
|
||||||
|
for i, dd := range files {
|
||||||
|
func(i int, dd string) {
|
||||||
|
btn := ui.NewButton("Doodad Btn", ui.NewLabel(ui.Label{
|
||||||
|
Text: dd,
|
||||||
|
Font: balance.MenuFont,
|
||||||
|
}))
|
||||||
|
btn.Handle(ui.Click, func(ed ui.EventData) error {
|
||||||
|
config.OnEditLevel(dd)
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
config.Supervisor.Add(btn)
|
||||||
|
ddRow.Pack(btn, ui.Pack{
|
||||||
|
Side: ui.W,
|
||||||
|
Expand: true,
|
||||||
|
Fill: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
if i > 0 && (i+1)%4 == 0 {
|
||||||
|
ddRow = ui.NewFrame(fmt.Sprintf("Doodad Row %d", i))
|
||||||
|
frame.Pack(ddRow, ui.Pack{
|
||||||
|
Side: ui.N,
|
||||||
|
FillX: true,
|
||||||
|
PadY: 1,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}(i, dd)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************
|
||||||
|
* Confirm/cancel buttons.
|
||||||
|
******************/
|
||||||
|
|
||||||
|
bottomFrame := ui.NewFrame("Button Frame")
|
||||||
|
// bottomFrame.Configure(ui.Config{
|
||||||
|
// BorderSize: 1,
|
||||||
|
// BorderStyle: ui.BorderSunken,
|
||||||
|
// BorderColor: render.Black,
|
||||||
|
// })
|
||||||
|
// bottomFrame.SetBackground(render.Grey)
|
||||||
|
frame.Pack(bottomFrame, ui.Pack{
|
||||||
|
Side: ui.N,
|
||||||
|
FillX: true,
|
||||||
|
PadY: 8,
|
||||||
|
})
|
||||||
|
|
||||||
|
var buttons = []struct {
|
||||||
|
Label string
|
||||||
|
F func(ui.EventData) error
|
||||||
|
}{
|
||||||
|
{"Cancel", func(ed ui.EventData) error {
|
||||||
|
config.OnCancel()
|
||||||
|
return nil
|
||||||
|
}},
|
||||||
|
}
|
||||||
|
for _, t := range buttons {
|
||||||
|
btn := ui.NewButton(t.Label, ui.NewLabel(ui.Label{
|
||||||
|
Text: t.Label,
|
||||||
|
Font: balance.MenuFont,
|
||||||
|
}))
|
||||||
|
btn.Handle(ui.Click, t.F)
|
||||||
|
config.Supervisor.Add(btn)
|
||||||
|
bottomFrame.Pack(btn, ui.Pack{
|
||||||
|
Side: ui.W,
|
||||||
|
PadX: 4,
|
||||||
|
PadY: 8,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return window
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user