Noah Petherbridge
fb5a8a1ae8
* The "Giant Screenshot" feature takes a very long time, so it is made asynchronous. If you try and run a second one while the first is busy, you get an error flash. You can continue editing the level, even playtest it, or load a different level, and it will continue crunching on the Giant Screenshot and flash when it's finished. * Updated the player physics to use proper Velocity to jump off the ground rather than the hacky timer-based fixed speed approach. * FlashError() function to flash "error level" messages to the screen. They appear in orange text instead of the usual blue, and most error messages in the game use this now. The dev console "error <msg>" command can simulate an error message. * Flashed message fonts are updated. The blue font now uses softer stroke and shadow colors and the same algorithm applies to the orange error flashes. Some other changes to player physics: * Max velocity, acceleration speed, and gravity have been tweaked. * Fast turn-around if you are moving right and then need to go left. Your velocity resets to zero at the transition so you quickly get going the way you want to go. Some levels that need a bit of love for the new platforming physics: * Tutorial 3.level
373 lines
9.2 KiB
Go
373 lines
9.2 KiB
Go
package doodle
|
|
|
|
// Menu Bar features for Edit Mode.
|
|
// In here is the SetupMenuBar() and menu item functions.
|
|
// The rest of it is controlled in editor_ui.go
|
|
|
|
import (
|
|
"git.kirsle.net/apps/doodle/pkg/balance"
|
|
"git.kirsle.net/apps/doodle/pkg/branding"
|
|
"git.kirsle.net/apps/doodle/pkg/drawtool"
|
|
"git.kirsle.net/apps/doodle/pkg/enum"
|
|
"git.kirsle.net/apps/doodle/pkg/level/giant_screenshot"
|
|
"git.kirsle.net/apps/doodle/pkg/log"
|
|
"git.kirsle.net/apps/doodle/pkg/native"
|
|
"git.kirsle.net/apps/doodle/pkg/userdir"
|
|
"git.kirsle.net/apps/doodle/pkg/windows"
|
|
"git.kirsle.net/go/render"
|
|
"git.kirsle.net/go/ui"
|
|
)
|
|
|
|
// SetupMenuBar sets up the menu bar.
|
|
func (u *EditorUI) SetupMenuBar(d *Doodle) *ui.MenuBar {
|
|
menu := ui.NewMenuBar("Main Menu")
|
|
|
|
// Save and Save As common menu handler
|
|
var (
|
|
drawingType string
|
|
saveFunc func(filename string)
|
|
)
|
|
|
|
switch u.Scene.DrawingType {
|
|
case enum.LevelDrawing:
|
|
drawingType = "level"
|
|
saveFunc = func(filename string) {
|
|
if err := u.Scene.SaveLevel(filename); err != nil {
|
|
d.FlashError("Error: %s", err)
|
|
} else {
|
|
d.Flash("Saved level: %s", filename)
|
|
}
|
|
}
|
|
case enum.DoodadDrawing:
|
|
drawingType = "doodad"
|
|
saveFunc = func(filename string) {
|
|
if err := u.Scene.SaveDoodad(filename); err != nil {
|
|
d.FlashError("Error: %s", err)
|
|
} else {
|
|
d.Flash("Saved doodad: %s", filename)
|
|
}
|
|
}
|
|
default:
|
|
d.FlashError("Error: Scene.DrawingType is not a valid type")
|
|
}
|
|
|
|
////////
|
|
// File menu
|
|
fileMenu := menu.AddMenu("File")
|
|
fileMenu.AddItemAccel("New level", "Ctrl-N", u.Scene.MenuNewLevel)
|
|
fileMenu.AddItem("New doodad", func() {
|
|
u.Scene.ConfirmUnload(func() {
|
|
// New doodad size with prompt.
|
|
d.NewDoodad(0)
|
|
})
|
|
})
|
|
fileMenu.AddItemAccel("Save", "Ctrl-S", u.Scene.MenuSave(false))
|
|
fileMenu.AddItemAccel("Save as...", "Shift-Ctrl-S", func() {
|
|
d.Prompt("Save as filename>", func(answer string) {
|
|
if answer != "" {
|
|
saveFunc(answer)
|
|
}
|
|
})
|
|
})
|
|
|
|
if balance.Feature.EmbeddableDoodads && drawingType == "level" {
|
|
fileMenu.AddItem("Publish level", func() {
|
|
u.OpenPublishWindow()
|
|
})
|
|
}
|
|
|
|
fileMenu.AddItemAccel("Open...", "Ctrl-O", u.Scene.MenuOpen)
|
|
fileMenu.AddSeparator()
|
|
fileMenu.AddItem("Close "+drawingType, func() {
|
|
u.Scene.ConfirmUnload(func() {
|
|
d.Goto(&MainScene{})
|
|
})
|
|
})
|
|
fileMenu.AddItemAccel("Quit", "Escape", func() {
|
|
d.ConfirmExit()
|
|
})
|
|
|
|
////////
|
|
// Edit menu
|
|
editMenu := menu.AddMenu("Edit")
|
|
editMenu.AddItemAccel("Undo", "Ctrl-Z", func() {
|
|
u.Canvas.UndoStroke()
|
|
})
|
|
editMenu.AddItemAccel("Redo", "Ctrl-Y", func() {
|
|
u.Canvas.RedoStroke()
|
|
})
|
|
editMenu.AddSeparator()
|
|
editMenu.AddItem("Settings", func() {
|
|
if u.settingsWindow == nil {
|
|
u.settingsWindow = d.MakeSettingsWindow(u.Supervisor)
|
|
}
|
|
u.settingsWindow.Show()
|
|
})
|
|
|
|
////////
|
|
// Level menu
|
|
if u.Scene.DrawingType == enum.LevelDrawing {
|
|
levelMenu := menu.AddMenu("Level")
|
|
levelMenu.AddItem("Level Properties", func() {
|
|
log.Info("Opening the window")
|
|
|
|
// Open the New Level window in edit-settings mode.
|
|
u.levelSettingsWindow.Hide()
|
|
u.levelSettingsWindow = nil
|
|
u.SetupPopups(u.d)
|
|
u.levelSettingsWindow.Show()
|
|
})
|
|
levelMenu.AddItem("Attached files", func() {
|
|
log.Info("Opening the FileSystem window")
|
|
u.OpenFileSystemWindow()
|
|
})
|
|
levelMenu.AddItemAccel("Playtest", "P", func() {
|
|
u.Scene.Playtest()
|
|
})
|
|
|
|
levelMenu.AddSeparator()
|
|
levelMenu.AddItem("Giant Screenshot", func() {
|
|
// It takes a LONG TIME to render for medium+ maps.
|
|
// Do so on a background thread.
|
|
go func() {
|
|
filename, err := giant_screenshot.SaveGiantScreenshot(u.Scene.Level)
|
|
if err != nil {
|
|
d.FlashError("Error: %s", err.Error())
|
|
return
|
|
}
|
|
|
|
d.FlashError("Giant screenshot saved as: %s", filename)
|
|
}()
|
|
})
|
|
levelMenu.AddItem("Open screenshot folder", func() {
|
|
native.OpenLocalURL(userdir.ScreenshotDirectory)
|
|
})
|
|
|
|
levelMenu.AddSeparator()
|
|
levelMenu.AddItemAccel("New viewport", "v", func() {
|
|
pip := windows.MakePiPWindow(d.width, d.height, windows.PiP{
|
|
Supervisor: u.Supervisor,
|
|
Engine: u.d.Engine,
|
|
Level: u.Scene.Level,
|
|
Event: u.d.event,
|
|
|
|
Tool: &u.Scene.UI.Canvas.Tool,
|
|
BrushSize: &u.Scene.UI.Canvas.BrushSize,
|
|
})
|
|
|
|
pip.Show()
|
|
})
|
|
}
|
|
|
|
////////
|
|
// Doodad Menu
|
|
if u.Scene.DrawingType == enum.DoodadDrawing {
|
|
levelMenu := menu.AddMenu("Doodad")
|
|
levelMenu.AddItem("Doodad Properties", func() {
|
|
log.Info("Opening the window")
|
|
|
|
// Open the New Level window in edit-settings mode.
|
|
u.doodadPropertiesWindow.Hide()
|
|
u.doodadPropertiesWindow = nil
|
|
u.SetupPopups(u.d)
|
|
u.doodadPropertiesWindow.Show()
|
|
})
|
|
|
|
levelMenu.AddItem("Layers", func() {
|
|
u.OpenLayersWindow()
|
|
})
|
|
}
|
|
|
|
////////
|
|
// View menu
|
|
viewMenu := menu.AddMenu("View")
|
|
viewMenu.AddItemAccel("Zoom in", "+", func() {
|
|
u.Canvas.Zoom++
|
|
})
|
|
viewMenu.AddItemAccel("Zoom out", "-", func() {
|
|
u.Canvas.Zoom--
|
|
})
|
|
viewMenu.AddItemAccel("Reset zoom", "1", func() {
|
|
u.Canvas.Zoom = 0
|
|
})
|
|
viewMenu.AddItemAccel("Scroll drawing to origin", "0", func() {
|
|
u.Canvas.ScrollTo(render.Origin)
|
|
})
|
|
|
|
viewMenu.AddSeparator()
|
|
|
|
viewMenu.AddItemAccel("Close window", "←", func() {
|
|
u.Supervisor.CloseActiveWindow()
|
|
})
|
|
viewMenu.AddItemAccel("Close all windows", "Shift-←", func() {
|
|
u.Supervisor.CloseAllWindows()
|
|
})
|
|
|
|
////////
|
|
// Tools menu
|
|
toolMenu := menu.AddMenu("Tools")
|
|
toolMenu.AddItemAccel("Debug overlay", "F3", func() {
|
|
DebugOverlay = !DebugOverlay
|
|
if DebugOverlay {
|
|
d.Flash("Debug overlay enabled. Press F3 to turn it off.")
|
|
}
|
|
})
|
|
toolMenu.AddItemAccel("Command shell", "`", func() {
|
|
d.shell.Open = true
|
|
})
|
|
toolMenu.AddSeparator()
|
|
toolMenu.AddItem("Edit Palette", func() {
|
|
u.OpenPaletteWindow()
|
|
})
|
|
|
|
// Draw Tools
|
|
toolMenu.AddItemAccel("Pencil Tool", "F", func() {
|
|
u.Canvas.Tool = drawtool.PencilTool
|
|
u.activeTool = u.Canvas.Tool.String()
|
|
d.Flash("Pencil Tool selected.")
|
|
})
|
|
toolMenu.AddItemAccel("Line Tool", "L", func() {
|
|
u.Canvas.Tool = drawtool.LineTool
|
|
u.activeTool = u.Canvas.Tool.String()
|
|
d.Flash("Line Tool selected.")
|
|
})
|
|
toolMenu.AddItemAccel("Rectangle Tool", "R", func() {
|
|
u.Canvas.Tool = drawtool.RectTool
|
|
u.activeTool = u.Canvas.Tool.String()
|
|
d.Flash("Rectangle Tool selected.")
|
|
})
|
|
toolMenu.AddItemAccel("Ellipse Tool", "C", func() {
|
|
u.Canvas.Tool = drawtool.EllipseTool
|
|
u.activeTool = u.Canvas.Tool.String()
|
|
d.Flash("Ellipse Tool selected.")
|
|
})
|
|
toolMenu.AddItemAccel("Eraser Tool", "x", func() {
|
|
u.Canvas.Tool = drawtool.EraserTool
|
|
u.activeTool = u.Canvas.Tool.String()
|
|
d.Flash("Eraser Tool selected.")
|
|
})
|
|
|
|
if u.Scene.DrawingType == enum.LevelDrawing {
|
|
toolMenu.AddItemAccel("Doodads", "q", func() {
|
|
log.Info("Open the DoodadDropper")
|
|
u.doodadWindow.Show()
|
|
})
|
|
toolMenu.AddItem("Link Tool", func() {
|
|
u.Canvas.Tool = drawtool.LinkTool
|
|
u.activeTool = u.Canvas.Tool.String()
|
|
d.Flash("Link Tool selected. Click a doodad in your level to link it to another.")
|
|
})
|
|
}
|
|
|
|
////////
|
|
// Help menu
|
|
helpMenu := menu.AddMenu("Help")
|
|
helpMenu.AddItemAccel("User Manual", "F1", func() {
|
|
native.OpenLocalURL(balance.GuidebookPath)
|
|
})
|
|
helpMenu.AddItem("Register", func() {
|
|
u.licenseWindow.Show()
|
|
})
|
|
helpMenu.AddItem("About", func() {
|
|
if u.aboutWindow == nil {
|
|
u.aboutWindow = windows.NewAboutWindow(windows.About{
|
|
Supervisor: u.Supervisor,
|
|
Engine: d.Engine,
|
|
})
|
|
u.aboutWindow.Compute(d.Engine)
|
|
u.aboutWindow.Supervise(u.Supervisor)
|
|
|
|
// Center the window.
|
|
u.aboutWindow.MoveTo(render.Point{
|
|
X: (d.width / 2) - (u.aboutWindow.Size().W / 2),
|
|
Y: 60,
|
|
})
|
|
}
|
|
u.aboutWindow.Show()
|
|
})
|
|
helpMenu.AddSeparator()
|
|
helpMenu.AddItem("Go to Website", func() {
|
|
native.OpenURL(branding.Website)
|
|
})
|
|
helpMenu.AddItem("Guidebook Online", func() {
|
|
native.OpenURL(branding.GuidebookURL)
|
|
})
|
|
|
|
menu.Supervise(u.Supervisor)
|
|
menu.Compute(d.Engine)
|
|
|
|
return menu
|
|
}
|
|
|
|
// Menu functions that have keybind callbacks below.
|
|
|
|
// File->New level, or Ctrl-N
|
|
func (s *EditorScene) MenuNewLevel() {
|
|
s.ConfirmUnload(func() {
|
|
s.d.GotoNewMenu()
|
|
})
|
|
}
|
|
|
|
// File->Open, or Ctrl-O
|
|
func (s *EditorScene) MenuOpen() {
|
|
s.ConfirmUnload(func() {
|
|
s.d.GotoLoadMenu()
|
|
})
|
|
}
|
|
|
|
// File->Save, or Ctrl-S
|
|
// File->Save As, or Shift-Ctrl-S
|
|
// NOTICE: this one returns a func() so you need to call that one!
|
|
func (s *EditorScene) MenuSave(as bool) func() {
|
|
return func() {
|
|
var (
|
|
// drawingType string
|
|
saveFunc func(filename string)
|
|
)
|
|
|
|
switch s.DrawingType {
|
|
case enum.LevelDrawing:
|
|
// drawingType = "level"
|
|
saveFunc = func(filename string) {
|
|
if err := s.SaveLevel(filename); err != nil {
|
|
s.d.FlashError("Error: %s", err)
|
|
} else {
|
|
s.d.Flash("Saved level: %s", filename)
|
|
}
|
|
}
|
|
case enum.DoodadDrawing:
|
|
// drawingType = "doodad"
|
|
saveFunc = func(filename string) {
|
|
if err := s.SaveDoodad(filename); err != nil {
|
|
s.d.FlashError("Error: %s", err)
|
|
} else {
|
|
s.d.Flash("Saved doodad: %s", filename)
|
|
}
|
|
}
|
|
default:
|
|
s.d.FlashError("Error: Scene.DrawingType is not a valid type")
|
|
}
|
|
|
|
// "Save As"?
|
|
if as {
|
|
s.d.Prompt("Save as filename>", func(answer string) {
|
|
if answer != "" {
|
|
saveFunc(answer)
|
|
}
|
|
})
|
|
return
|
|
}
|
|
|
|
// "Save", write to existing filename or prompt for it.
|
|
if s.filename != "" {
|
|
saveFunc(s.filename)
|
|
} else {
|
|
s.d.Prompt("Save filename>", func(answer string) {
|
|
if answer != "" {
|
|
saveFunc(answer)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
}
|