Menu Bar Update
* Integrate the new ui.MenuBar into the Editor Scene. * File: New Level/Doodad, Save [as], Open, Close, Exit * Edit: Undo, Redo, Level options * Level: Playtest * Tools: Debug overlay, Command shell * Help: User Manual, About * Add an About dialog accessible from the Help menu.
This commit is contained in:
parent
82d50f1c91
commit
2c032f1df7
|
@ -3,7 +3,11 @@ package balance
|
||||||
import "runtime"
|
import "runtime"
|
||||||
|
|
||||||
// Runtime environment settings.
|
// Runtime environment settings.
|
||||||
var Runtime rtc
|
var (
|
||||||
|
Runtime rtc
|
||||||
|
|
||||||
|
GuidebookPath = "./guidebook/index.html"
|
||||||
|
)
|
||||||
|
|
||||||
type rtc struct {
|
type rtc struct {
|
||||||
Platform platform
|
Platform platform
|
||||||
|
|
|
@ -2,9 +2,11 @@ package branding
|
||||||
|
|
||||||
// Constants for branding and version information.
|
// Constants for branding and version information.
|
||||||
const (
|
const (
|
||||||
AppName = "Project: Doodle"
|
AppName = "Project: Doodle"
|
||||||
Summary = "A drawing-based maze game"
|
Summary = "A drawing-based maze game"
|
||||||
Version = "0.1.0-alpha"
|
Version = "0.1.0-alpha"
|
||||||
|
Website = "https://www.kirsle.net/tagged/Doodle"
|
||||||
|
Copyright = "2020 Noah Petherbridge"
|
||||||
|
|
||||||
// Update check URL
|
// Update check URL
|
||||||
UpdateCheckJSON = "https://download.sketchymaze.com/version.json"
|
UpdateCheckJSON = "https://download.sketchymaze.com/version.json"
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"git.kirsle.net/apps/doodle/pkg/branding"
|
"git.kirsle.net/apps/doodle/pkg/branding"
|
||||||
"git.kirsle.net/apps/doodle/pkg/enum"
|
"git.kirsle.net/apps/doodle/pkg/enum"
|
||||||
"git.kirsle.net/apps/doodle/pkg/log"
|
"git.kirsle.net/apps/doodle/pkg/log"
|
||||||
|
"git.kirsle.net/apps/doodle/pkg/native"
|
||||||
"git.kirsle.net/apps/doodle/pkg/shmem"
|
"git.kirsle.net/apps/doodle/pkg/shmem"
|
||||||
golog "git.kirsle.net/go/log"
|
golog "git.kirsle.net/go/log"
|
||||||
"git.kirsle.net/go/render"
|
"git.kirsle.net/go/render"
|
||||||
|
@ -134,7 +135,11 @@ func (d *Doodle) Run() error {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
if ev.KeyDown("F3") {
|
if ev.KeyDown("F1") {
|
||||||
|
// TODO: launch the guidebook.
|
||||||
|
native.OpenURL(balance.GuidebookPath)
|
||||||
|
ev.SetKeyDown("F1", false)
|
||||||
|
} else if ev.KeyDown("F3") {
|
||||||
DebugOverlay = !DebugOverlay
|
DebugOverlay = !DebugOverlay
|
||||||
ev.SetKeyDown("F3", false)
|
ev.SetKeyDown("F3", false)
|
||||||
} else if ev.KeyDown("F4") {
|
} else if ev.KeyDown("F4") {
|
||||||
|
|
318
pkg/editor_ui.go
318
pkg/editor_ui.go
|
@ -2,6 +2,7 @@ package doodle
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
|
@ -11,6 +12,7 @@ import (
|
||||||
"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/native"
|
||||||
"git.kirsle.net/apps/doodle/pkg/uix"
|
"git.kirsle.net/apps/doodle/pkg/uix"
|
||||||
"git.kirsle.net/apps/doodle/pkg/windows"
|
"git.kirsle.net/apps/doodle/pkg/windows"
|
||||||
"git.kirsle.net/go/render"
|
"git.kirsle.net/go/render"
|
||||||
|
@ -36,16 +38,18 @@ type EditorUI struct {
|
||||||
cursor render.Point // remember the cursor position in Loop
|
cursor render.Point // remember the cursor position in Loop
|
||||||
|
|
||||||
// Widgets
|
// Widgets
|
||||||
|
screen *ui.Frame // full-window parent frame for layout
|
||||||
Supervisor *ui.Supervisor
|
Supervisor *ui.Supervisor
|
||||||
Canvas *uix.Canvas
|
Canvas *uix.Canvas
|
||||||
Workspace *ui.Frame
|
Workspace *ui.Frame
|
||||||
MenuBar *ui.Frame
|
MenuBar *ui.MenuBar
|
||||||
StatusBar *ui.Frame
|
StatusBar *ui.Frame
|
||||||
ToolBar *ui.Frame
|
ToolBar *ui.Frame
|
||||||
PlayButton *ui.Button
|
PlayButton *ui.Button
|
||||||
|
|
||||||
// Popup windows.
|
// Popup windows.
|
||||||
levelSettingsWindow *ui.Window
|
levelSettingsWindow *ui.Window
|
||||||
|
aboutWindow *ui.Window
|
||||||
|
|
||||||
// Palette window.
|
// Palette window.
|
||||||
Palette *ui.Window
|
Palette *ui.Window
|
||||||
|
@ -81,6 +85,11 @@ func NewEditorUI(d *Doodle, s *EditorScene) *EditorUI {
|
||||||
StatusScrollText: "Hello world",
|
StatusScrollText: "Hello world",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The screen is a full-window-sized frame for laying out the UI.
|
||||||
|
u.screen = ui.NewFrame("screen")
|
||||||
|
u.screen.Resize(render.NewRect(d.width, d.height))
|
||||||
|
u.screen.Compute(d.Engine)
|
||||||
|
|
||||||
// Default tool in the toolbox.
|
// Default tool in the toolbox.
|
||||||
u.activeTool = drawtool.PencilTool.String()
|
u.activeTool = drawtool.PencilTool.String()
|
||||||
|
|
||||||
|
@ -98,6 +107,12 @@ func NewEditorUI(d *Doodle, s *EditorScene) *EditorUI {
|
||||||
u.ToolBar = u.SetupToolbar(d)
|
u.ToolBar = u.SetupToolbar(d)
|
||||||
u.Workspace = u.SetupWorkspace(d) // important that this is last!
|
u.Workspace = u.SetupWorkspace(d) // important that this is last!
|
||||||
|
|
||||||
|
log.Error("menu size: %s", u.MenuBar.Rect())
|
||||||
|
u.screen.Pack(u.MenuBar, ui.Pack{
|
||||||
|
Side: ui.N,
|
||||||
|
FillX: true,
|
||||||
|
})
|
||||||
|
|
||||||
u.PlayButton = ui.NewButton("Play", ui.NewLabel(ui.Label{
|
u.PlayButton = ui.NewButton("Play", ui.NewLabel(ui.Label{
|
||||||
Text: "Play (P)",
|
Text: "Play (P)",
|
||||||
Font: balance.PlayButtonFont,
|
Font: balance.PlayButtonFont,
|
||||||
|
@ -132,14 +147,10 @@ func (u *EditorUI) FinishSetup(d *Doodle) {
|
||||||
|
|
||||||
// Resized handles the window being resized so we can recompute the widgets.
|
// Resized handles the window being resized so we can recompute the widgets.
|
||||||
func (u *EditorUI) Resized(d *Doodle) {
|
func (u *EditorUI) Resized(d *Doodle) {
|
||||||
// Menu Bar frame.
|
// Resize the screen frame to fill the window.
|
||||||
{
|
u.screen.Resize(render.NewRect(d.width, d.height))
|
||||||
u.MenuBar.Configure(ui.Config{
|
u.screen.Compute(d.Engine)
|
||||||
Width: d.width,
|
menuHeight := 20 // TODO: ideally the MenuBar should know its own height and we can ask
|
||||||
Background: render.Black,
|
|
||||||
})
|
|
||||||
u.MenuBar.Compute(d.Engine)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Status Bar.
|
// Status Bar.
|
||||||
{
|
{
|
||||||
|
@ -161,14 +172,14 @@ func (u *EditorUI) Resized(d *Doodle) {
|
||||||
})
|
})
|
||||||
u.Palette.MoveTo(render.NewPoint(
|
u.Palette.MoveTo(render.NewPoint(
|
||||||
u.d.width-u.Palette.BoxSize().W,
|
u.d.width-u.Palette.BoxSize().W,
|
||||||
u.MenuBar.BoxSize().H,
|
menuHeight,
|
||||||
))
|
))
|
||||||
u.Palette.Compute(d.Engine)
|
u.Palette.Compute(d.Engine)
|
||||||
|
|
||||||
u.scrollDoodadFrame(0)
|
u.scrollDoodadFrame(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
var innerHeight = u.d.height - u.MenuBar.Size().H - u.StatusBar.Size().H
|
var innerHeight = u.d.height - menuHeight - u.StatusBar.Size().H
|
||||||
|
|
||||||
// Tool Bar.
|
// Tool Bar.
|
||||||
{
|
{
|
||||||
|
@ -178,7 +189,7 @@ func (u *EditorUI) Resized(d *Doodle) {
|
||||||
})
|
})
|
||||||
u.ToolBar.MoveTo(render.NewPoint(
|
u.ToolBar.MoveTo(render.NewPoint(
|
||||||
0,
|
0,
|
||||||
u.MenuBar.BoxSize().H,
|
menuHeight,
|
||||||
))
|
))
|
||||||
u.ToolBar.Compute(d.Engine)
|
u.ToolBar.Compute(d.Engine)
|
||||||
}
|
}
|
||||||
|
@ -189,11 +200,11 @@ func (u *EditorUI) Resized(d *Doodle) {
|
||||||
frame := u.Workspace
|
frame := u.Workspace
|
||||||
frame.MoveTo(render.NewPoint(
|
frame.MoveTo(render.NewPoint(
|
||||||
u.ToolBar.Size().W,
|
u.ToolBar.Size().W,
|
||||||
u.MenuBar.Size().H,
|
menuHeight,
|
||||||
))
|
))
|
||||||
frame.Resize(render.NewRect(
|
frame.Resize(render.NewRect(
|
||||||
d.width-u.Palette.Size().W-u.ToolBar.Size().W,
|
d.width-u.Palette.Size().W-u.ToolBar.Size().W,
|
||||||
d.height-u.MenuBar.Size().H-u.StatusBar.Size().H,
|
d.height-menuHeight-u.StatusBar.Size().H,
|
||||||
))
|
))
|
||||||
frame.Compute(d.Engine)
|
frame.Compute(d.Engine)
|
||||||
|
|
||||||
|
@ -274,7 +285,8 @@ func (u *EditorUI) Loop(ev *event.State) error {
|
||||||
|
|
||||||
// Only forward events to the Canvas if the UI hasn't stopped them.
|
// Only forward events to the Canvas if the UI hasn't stopped them.
|
||||||
// Also ignore events if a managed ui.Window is overlapping the canvas.
|
// Also ignore events if a managed ui.Window is overlapping the canvas.
|
||||||
if !(stopPropagation || u.Supervisor.IsPointInWindow(u.cursor)) {
|
// Also ignore if an active modal (popup menu) is on screen.
|
||||||
|
if !(stopPropagation || u.Supervisor.IsPointInWindow(u.cursor) || u.Supervisor.GetModal() != nil) {
|
||||||
u.Canvas.Loop(ev)
|
u.Canvas.Loop(ev)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
@ -298,6 +310,8 @@ func (u *EditorUI) Present(e render.Engine) {
|
||||||
u.ToolBar.Present(e, u.ToolBar.Point())
|
u.ToolBar.Present(e, u.ToolBar.Point())
|
||||||
u.PlayButton.Present(e, u.PlayButton.Point())
|
u.PlayButton.Present(e, u.PlayButton.Point())
|
||||||
|
|
||||||
|
u.screen.Present(e, render.Origin)
|
||||||
|
|
||||||
// Are we dragging a Doodad canvas?
|
// Are we dragging a Doodad canvas?
|
||||||
if u.Supervisor.IsDragging() {
|
if u.Supervisor.IsDragging() {
|
||||||
if actor := u.DraggableActor; actor != nil {
|
if actor := u.DraggableActor; actor != nil {
|
||||||
|
@ -421,14 +435,18 @@ func (u *EditorUI) ExpandCanvas(e render.Engine) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetupMenuBar sets up the menu bar.
|
// SetupMenuBar sets up the menu bar.
|
||||||
func (u *EditorUI) SetupMenuBar(d *Doodle) *ui.Frame {
|
func (u *EditorUI) SetupMenuBar(d *Doodle) *ui.MenuBar {
|
||||||
frame := ui.NewFrame("MenuBar")
|
menu := ui.NewMenuBar("Main Menu")
|
||||||
|
|
||||||
// Save and Save As common menu handler
|
// Save and Save As common menu handler
|
||||||
var saveFunc func(filename string)
|
var (
|
||||||
|
drawingType string
|
||||||
|
saveFunc func(filename string)
|
||||||
|
)
|
||||||
|
|
||||||
switch u.Scene.DrawingType {
|
switch u.Scene.DrawingType {
|
||||||
case enum.LevelDrawing:
|
case enum.LevelDrawing:
|
||||||
|
drawingType = "level"
|
||||||
saveFunc = func(filename string) {
|
saveFunc = func(filename string) {
|
||||||
if err := u.Scene.SaveLevel(filename); err != nil {
|
if err := u.Scene.SaveLevel(filename); err != nil {
|
||||||
d.Flash("Error: %s", err)
|
d.Flash("Error: %s", err)
|
||||||
|
@ -437,6 +455,7 @@ func (u *EditorUI) SetupMenuBar(d *Doodle) *ui.Frame {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case enum.DoodadDrawing:
|
case enum.DoodadDrawing:
|
||||||
|
drawingType = "doodad"
|
||||||
saveFunc = func(filename string) {
|
saveFunc = func(filename string) {
|
||||||
if err := u.Scene.SaveDoodad(filename); err != nil {
|
if err := u.Scene.SaveDoodad(filename); err != nil {
|
||||||
d.Flash("Error: %s", err)
|
d.Flash("Error: %s", err)
|
||||||
|
@ -448,136 +467,155 @@ func (u *EditorUI) SetupMenuBar(d *Doodle) *ui.Frame {
|
||||||
d.Flash("Error: Scene.DrawingType is not a valid type")
|
d.Flash("Error: Scene.DrawingType is not a valid type")
|
||||||
}
|
}
|
||||||
|
|
||||||
type menuButton struct {
|
////////
|
||||||
Text string
|
// File menu
|
||||||
Click func(ui.EventData) error
|
fileMenu := menu.AddMenu("File")
|
||||||
}
|
fileMenu.AddItemAccel("New level", "Ctrl-N", func() {
|
||||||
buttons := []menuButton{
|
d.GotoNewMenu()
|
||||||
menuButton{
|
})
|
||||||
Text: "New Level",
|
if !balance.FreeVersion {
|
||||||
Click: func(ed ui.EventData) error {
|
fileMenu.AddItem("New doodad", func() {
|
||||||
d.GotoNewMenu()
|
d.Prompt("Doodad size [100]>", func(answer string) {
|
||||||
return nil
|
size := balance.DoodadSize
|
||||||
},
|
if answer != "" {
|
||||||
},
|
i, err := strconv.Atoi(answer)
|
||||||
menuButton{
|
if err != nil {
|
||||||
Text: "New Doodad",
|
d.Flash("Error: Doodad size must be a number.")
|
||||||
Click: func(ed ui.EventData) error {
|
return
|
||||||
d.Prompt("Doodad size [100]>", func(answer string) {
|
|
||||||
size := balance.DoodadSize
|
|
||||||
if answer != "" {
|
|
||||||
i, err := strconv.Atoi(answer)
|
|
||||||
if err != nil {
|
|
||||||
d.Flash("Error: Doodad size must be a number.")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
size = i
|
|
||||||
}
|
}
|
||||||
d.NewDoodad(size)
|
size = i
|
||||||
})
|
|
||||||
|
|
||||||
return nil
|
|
||||||
},
|
|
||||||
},
|
|
||||||
menuButton{
|
|
||||||
Text: "Save",
|
|
||||||
Click: func(ed ui.EventData) error {
|
|
||||||
if u.Scene.filename != "" {
|
|
||||||
saveFunc(u.Scene.filename)
|
|
||||||
} else {
|
|
||||||
d.Prompt("Save filename>", func(answer string) {
|
|
||||||
if answer != "" {
|
|
||||||
saveFunc(answer)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
return nil
|
d.NewDoodad(size)
|
||||||
},
|
})
|
||||||
},
|
})
|
||||||
menuButton{
|
|
||||||
Text: "Save as...",
|
|
||||||
Click: func(ed ui.EventData) error {
|
|
||||||
d.Prompt("Save as filename>", func(answer string) {
|
|
||||||
if answer != "" {
|
|
||||||
saveFunc(answer)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
return nil
|
|
||||||
},
|
|
||||||
},
|
|
||||||
menuButton{
|
|
||||||
Text: "Load",
|
|
||||||
Click: func(ed ui.EventData) error {
|
|
||||||
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
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
fileMenu.AddItemAccel("Save", "Ctrl-S", func() {
|
||||||
for _, btn := range buttons {
|
if u.Scene.filename != "" {
|
||||||
if balance.FreeVersion {
|
saveFunc(u.Scene.filename)
|
||||||
if btn.Text == "New Doodad" {
|
} else {
|
||||||
continue
|
d.Prompt("Save filename>", func(answer string) {
|
||||||
}
|
if answer != "" {
|
||||||
|
saveFunc(answer)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
})
|
||||||
w := ui.NewButton(btn.Text, ui.NewLabel(ui.Label{
|
fileMenu.AddItem("Save as...", func() {
|
||||||
Text: btn.Text,
|
d.Prompt("Save as filename>", func(answer string) {
|
||||||
Font: balance.MenuFont,
|
if answer != "" {
|
||||||
}))
|
saveFunc(answer)
|
||||||
w.Configure(ui.Config{
|
}
|
||||||
BorderSize: 1,
|
|
||||||
OutlineSize: 0,
|
|
||||||
})
|
})
|
||||||
w.Handle(ui.MouseUp, btn.Click)
|
})
|
||||||
u.Supervisor.Add(w)
|
fileMenu.AddItemAccel("Open...", "Ctrl-O", func() {
|
||||||
frame.Pack(w, ui.Pack{
|
d.GotoLoadMenu()
|
||||||
Side: ui.W,
|
})
|
||||||
PadX: 1,
|
fileMenu.AddSeparator()
|
||||||
|
fileMenu.AddItem("Close "+drawingType, func() {
|
||||||
|
d.Goto(&MainScene{})
|
||||||
|
})
|
||||||
|
fileMenu.AddItemAccel("Quit", "Ctrl-Q", func() {
|
||||||
|
// TODO graceful shutdown
|
||||||
|
os.Exit(0)
|
||||||
|
})
|
||||||
|
|
||||||
|
////////
|
||||||
|
// Edit menu
|
||||||
|
editMenu := menu.AddMenu("Edit")
|
||||||
|
editMenu.AddItemAccel("Undo", "Ctrl-Z", func() {
|
||||||
|
u.Canvas.UndoStroke()
|
||||||
|
})
|
||||||
|
editMenu.AddItemAccel("Redo", "Shift-Ctrl-Y", func() {
|
||||||
|
u.Canvas.RedoStroke()
|
||||||
|
})
|
||||||
|
editMenu.AddSeparator()
|
||||||
|
editMenu.AddItem("Level options", func() {
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
////////
|
||||||
|
// Level menu
|
||||||
|
if drawingType == "level" {
|
||||||
|
levelMenu := menu.AddMenu("Level")
|
||||||
|
levelMenu.AddItemAccel("Playtest", "P", func() {
|
||||||
|
u.Scene.Playtest()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
frame.Compute(d.Engine)
|
////////
|
||||||
return frame
|
// 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", "Enter", func() {
|
||||||
|
d.shell.Open = true
|
||||||
|
})
|
||||||
|
|
||||||
|
////////
|
||||||
|
// Help menu
|
||||||
|
helpMenu := menu.AddMenu("Help")
|
||||||
|
helpMenu.AddItemAccel("User Manual", "F1", func() {
|
||||||
|
// TODO: launch the guidebook.
|
||||||
|
native.OpenURL(balance.GuidebookPath)
|
||||||
|
})
|
||||||
|
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()
|
||||||
|
})
|
||||||
|
|
||||||
|
menu.Supervise(u.Supervisor)
|
||||||
|
menu.Compute(d.Engine)
|
||||||
|
log.Error("Setup MenuBar: %s\n", menu.Size())
|
||||||
|
|
||||||
|
return menu
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetupStatusBar sets up the status bar widget along the bottom of the window.
|
// SetupStatusBar sets up the status bar widget along the bottom of the window.
|
||||||
|
|
86
pkg/windows/about.go
Normal file
86
pkg/windows/about.go
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
package windows
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"git.kirsle.net/apps/doodle/pkg/balance"
|
||||||
|
"git.kirsle.net/apps/doodle/pkg/branding"
|
||||||
|
"git.kirsle.net/apps/doodle/pkg/native"
|
||||||
|
"git.kirsle.net/go/render"
|
||||||
|
"git.kirsle.net/go/ui"
|
||||||
|
)
|
||||||
|
|
||||||
|
// About window.
|
||||||
|
type About struct {
|
||||||
|
// Settings passed in by doodle
|
||||||
|
Supervisor *ui.Supervisor
|
||||||
|
Engine render.Engine
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewAboutWindow initializes the window.
|
||||||
|
func NewAboutWindow(cfg About) *ui.Window {
|
||||||
|
window := ui.NewWindow("About " + branding.AppName)
|
||||||
|
window.SetButtons(ui.CloseButton)
|
||||||
|
window.Configure(ui.Config{
|
||||||
|
Width: 400,
|
||||||
|
Height: 170,
|
||||||
|
Background: render.Grey,
|
||||||
|
})
|
||||||
|
|
||||||
|
text := ui.NewLabel(ui.Label{
|
||||||
|
Text: fmt.Sprintf("%s is a drawing-based maze game.\n\n"+
|
||||||
|
"Copyright © %s.\nAll rights reserved.\n\n"+
|
||||||
|
"Version %s",
|
||||||
|
branding.AppName,
|
||||||
|
branding.Copyright,
|
||||||
|
branding.Version,
|
||||||
|
),
|
||||||
|
})
|
||||||
|
window.Pack(text, ui.Pack{
|
||||||
|
Side: ui.N,
|
||||||
|
Padding: 8,
|
||||||
|
})
|
||||||
|
|
||||||
|
frame := ui.NewFrame("Button frame")
|
||||||
|
buttons := []struct {
|
||||||
|
label string
|
||||||
|
f func()
|
||||||
|
}{
|
||||||
|
{"Website", func() {
|
||||||
|
native.OpenURL(branding.Website)
|
||||||
|
}},
|
||||||
|
{"Open Source Licenses", func() {
|
||||||
|
// TODO: open file
|
||||||
|
native.OpenURL("./Open Source Licenses.md")
|
||||||
|
}},
|
||||||
|
}
|
||||||
|
for _, button := range buttons {
|
||||||
|
button := button
|
||||||
|
|
||||||
|
btn := ui.NewButton(button.label, ui.NewLabel(ui.Label{
|
||||||
|
Text: button.label,
|
||||||
|
Font: balance.MenuFont,
|
||||||
|
}))
|
||||||
|
|
||||||
|
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,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
window.Pack(frame, ui.Pack{
|
||||||
|
Side: ui.N,
|
||||||
|
Padding: 8,
|
||||||
|
})
|
||||||
|
|
||||||
|
return window
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user