Noah Petherbridge
af6b8625d6
New features: * Flood Tool for the editor. It replaces pixels of one color with another, contiguously. Has limits on how far from the original pixel it will color, to avoid infinite loops in case the user clicked on wide open void. The limit when clicking an existing color is 1200px or only a 600px limit if clicking into the void. * Cheat code: 'master key' to play locked Story Mode levels. Level GameRules feature added: * A new tab in the Level Properties dialog * Difficulty has been moved to this tab * Survival Mode: for silver high score, longest time alive is better than fastest time, for Azulian Tag maps. Gold high score is still based on fastest time - find the hidden level exit without dying! Tweaks to the Azulians' jump heights: * Blue Azulian: 12 -> 14 * Red Azulian: 14 -> 18 * White Azulian: 16 -> 20 Bugs fixed: * When editing your Palette to rename a color or add a new color, it wasn't possible to draw with that color until the editor was completely unloaded and reloaded; this is now fixed. * Minor bugfix in Difficulty.String() for Peaceful (-1) difficulty to avoid a negative array index. * Try and prevent user giving the same name to multiple swatches on their palette. Replacing the whole palette can let duplication through still.
350 lines
8.6 KiB
Go
350 lines
8.6 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/drawtool"
|
|
"git.kirsle.net/apps/doodle/pkg/enum"
|
|
"git.kirsle.net/apps/doodle/pkg/level/giant_screenshot"
|
|
"git.kirsle.net/apps/doodle/pkg/license"
|
|
"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 (
|
|
saveFunc func(filename string)
|
|
)
|
|
|
|
switch u.Scene.DrawingType {
|
|
case enum.LevelDrawing:
|
|
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:
|
|
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)
|
|
}
|
|
})
|
|
})
|
|
|
|
fileMenu.AddItemAccel("Open...", "Ctrl-O", u.Scene.MenuOpen)
|
|
fileMenu.AddSeparator()
|
|
fileMenu.AddItem("Exit to menu", 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.AddItem("Publish", func() {
|
|
u.OpenPublishWindow()
|
|
})
|
|
|
|
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)
|
|
})
|
|
|
|
if balance.Feature.ViewportWindow {
|
|
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.OpenDoodadDropper()
|
|
})
|
|
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
|
|
var (
|
|
helpMenu = u.d.MakeHelpMenu(menu, u.Supervisor)
|
|
registerText = "Register"
|
|
)
|
|
helpMenu.AddSeparator()
|
|
if license.IsRegistered() {
|
|
registerText = "Registration"
|
|
}
|
|
helpMenu.AddItem(registerText, func() {
|
|
u.licenseWindow.Show()
|
|
u.Supervisor.FocusWindow(u.licenseWindow)
|
|
})
|
|
|
|
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)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
}
|