Noah Petherbridge
da83231559
Adds some support for "less giant" level screenshots. * In the Editor, the Level->Take Screenshot menu will render a cropped screen shot of just the level viewport on screen. Note: it is not an SDL2 screen copy but generated from scratch from the level data. * In levels themselves, screenshots can be stored inside the level data in three different sizes: large (1280x720), medium and small (each a halved size of the previous). * The first screenshot is created when the level is saved, starting from wherever the scroll position in the editor is at, and recording the 720p view of the level from there. * The level screenshot can be previewed and updated in the Level Properties window of the editor: so you can scroll the editor to just the right position and take a good screenshot to represent your level. * In the future: these embedded level screenshots will be displayed on the Story Mode and other screens to see a preview of each level. Other tweaks: * When taking a Giant Screenshot: a confirm modal will warn the player that it may take a while. And during the screenshot, show the new Wait Modal to block player interaction until the screenshot has finished.
375 lines
9.5 KiB
Go
375 lines
9.5 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/SketchyMaze/doodle/pkg/balance"
|
|
"git.kirsle.net/SketchyMaze/doodle/pkg/drawtool"
|
|
"git.kirsle.net/SketchyMaze/doodle/pkg/enum"
|
|
"git.kirsle.net/SketchyMaze/doodle/pkg/level/giant_screenshot"
|
|
"git.kirsle.net/SketchyMaze/doodle/pkg/license"
|
|
"git.kirsle.net/SketchyMaze/doodle/pkg/log"
|
|
"git.kirsle.net/SketchyMaze/doodle/pkg/modal"
|
|
"git.kirsle.net/SketchyMaze/doodle/pkg/native"
|
|
"git.kirsle.net/SketchyMaze/doodle/pkg/userdir"
|
|
"git.kirsle.net/SketchyMaze/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", u.Scene.MenuNewDoodad)
|
|
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("Screenshot", func() {
|
|
// It takes a LONG TIME to render for medium+ maps.
|
|
// Do so on a background thread.
|
|
go func() {
|
|
filename, err := giant_screenshot.SaveCroppedScreenshot(u.Scene.Level, u.Scene.GetDrawing().Viewport())
|
|
if err != nil {
|
|
d.FlashError("Error: %s", err.Error())
|
|
return
|
|
}
|
|
|
|
d.FlashError("Screenshot saved as: %s", filename)
|
|
}()
|
|
})
|
|
levelMenu.AddItem("Giant Screenshot", func() {
|
|
// It takes a LONG TIME to render for medium+ maps.
|
|
modal.Confirm(
|
|
"Do you want to make a 'Giant Screenshot' of\n" +
|
|
"your WHOLE level? Note: this may take several\n" +
|
|
"seconds for very large maps!",
|
|
).WithTitle("Giant Screenshot").Then(func() {
|
|
// Show the wait modal and generate the screenshot on a background thread.
|
|
m := modal.Wait("Generating a giant screenshot...").WithTitle("Please hold")
|
|
go func() {
|
|
defer m.Dismiss(true)
|
|
|
|
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()
|
|
})
|
|
}
|
|
|
|
func (s *EditorScene) MenuNewDoodad() {
|
|
s.ConfirmUnload(func() {
|
|
// New doodad size with prompt.
|
|
s.d.GotoNewDoodadMenu()
|
|
})
|
|
}
|
|
|
|
// 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)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
}
|