Blueprint Theme Palette

* Fix the EditorUI not showing the correct palette baked into the level
  and only showing the default. This was tricky because the palette UI
  can only be configured at setup time but not updated later.
* Add a new default palette for the Blueprint theme. Blueprint has a
  dark background, so the palette colors should be bright. This palette
  is chosen when you start a map with the blueprint wallpaper.
* Add a background Canvas to the MenuScene. In the "New Level" screen,
  the background canvas will update to show the wallpaper settings
  you've chosen as a preview of the level theme you're about to create.
This commit is contained in:
Noah 2019-06-25 17:43:23 -07:00
parent 7281fcbf91
commit 3d3561b8e6
6 changed files with 206 additions and 113 deletions

View File

@ -32,7 +32,7 @@ var (
DebugCanvasLabel = false // Tag the canvas with a label. DebugCanvasLabel = false // Tag the canvas with a label.
// Pretty-print JSON files when writing. // Pretty-print JSON files when writing.
JSONIndent = false JSONIndent = true
) )
func init() { func init() {

View File

@ -117,6 +117,9 @@ func (s *EditorScene) Setup(d *Doodle) error {
s.UI.Workspace.Compute(d.Engine) s.UI.Workspace.Compute(d.Engine)
} }
// Recompute the UI Palette window for the level's palette.
s.UI.FinishSetup(d)
d.Flash("Editor Mode. Press 'P' to play this map.") d.Flash("Editor Mode. Press 'P' to play this map.")
return nil return nil

View File

@ -76,11 +76,8 @@ func NewEditorUI(d *Doodle, s *EditorScene) *EditorUI {
u.Canvas = u.SetupCanvas(d) u.Canvas = u.SetupCanvas(d)
u.MenuBar = u.SetupMenuBar(d) u.MenuBar = u.SetupMenuBar(d)
u.StatusBar = u.SetupStatusBar(d) u.StatusBar = u.SetupStatusBar(d)
u.Palette = u.SetupPalette(d)
u.Workspace = u.SetupWorkspace(d) // important that this is last! u.Workspace = u.SetupWorkspace(d) // important that this is last!
u.Resized(d)
// Position the Canvas inside the frame. // Position the Canvas inside the frame.
u.Workspace.Pack(u.Canvas, ui.Pack{ u.Workspace.Pack(u.Canvas, ui.Pack{
Anchor: ui.N, Anchor: ui.N,
@ -95,6 +92,14 @@ func NewEditorUI(d *Doodle, s *EditorScene) *EditorUI {
return u return u
} }
// FinishSetup runs the Setup tasks that must be postponed til the end, such
// as rendering the Palette window so that it can accurately show the palette
// loaded from a level.
func (u *EditorUI) FinishSetup(d *Doodle) {
u.Palette = u.SetupPalette(d)
u.Resized(d)
}
// 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. // Menu Bar frame.
@ -442,84 +447,6 @@ func (u *EditorUI) SetupMenuBar(d *Doodle) *ui.Frame {
return frame return frame
} }
// SetupPalette sets up the palette panel.
func (u *EditorUI) SetupPalette(d *Doodle) *ui.Window {
window := ui.NewWindow("Palette")
window.ConfigureTitle(balance.TitleConfig)
window.TitleBar().Font = balance.TitleFont
window.Configure(ui.Config{
Background: balance.WindowBackground,
BorderColor: balance.WindowBorder,
})
// Frame that holds the tab buttons in Level Edit mode.
tabFrame := ui.NewFrame("Palette Tabs")
for _, name := range []string{"Palette", "Doodads"} {
if u.paletteTab == "" {
u.paletteTab = name
}
tab := ui.NewRadioButton("Palette Tab", &u.paletteTab, name, ui.NewLabel(ui.Label{
Text: name,
}))
tab.Handle(ui.Click, func(p render.Point) {
if u.paletteTab == "Palette" {
u.Canvas.Tool = uix.PencilTool
u.PaletteTab.Show()
u.DoodadTab.Hide()
} else {
u.Canvas.Tool = uix.ActorTool
u.PaletteTab.Hide()
u.DoodadTab.Show()
}
window.Compute(d.Engine)
})
u.Supervisor.Add(tab)
tabFrame.Pack(tab, ui.Pack{
Anchor: ui.W,
Fill: true,
Expand: true,
})
}
window.Pack(tabFrame, ui.Pack{
Anchor: ui.N,
Fill: true,
PadY: 4,
})
// Only show the tab frame in Level drawing mode!
if u.Scene.DrawingType != enum.LevelDrawing {
tabFrame.Hide()
}
// Doodad frame.
{
frame, err := u.setupDoodadFrame(d.Engine, window)
if err != nil {
d.Flash(err.Error())
}
// Even if there was an error (userdir.ListDoodads couldn't read the
// config folder on disk or whatever) the Frame is still valid but
// empty, which is still the intended behavior.
u.DoodadTab = frame
u.DoodadTab.Hide()
window.Pack(u.DoodadTab, ui.Pack{
Anchor: ui.N,
Fill: true,
})
}
// Color Palette Frame.
u.PaletteTab = u.setupPaletteFrame(window)
window.Pack(u.PaletteTab, ui.Pack{
Anchor: ui.N,
Fill: true,
})
return window
}
// 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.
func (u *EditorUI) SetupStatusBar(d *Doodle) *ui.Frame { func (u *EditorUI) SetupStatusBar(d *Doodle) *ui.Frame {
frame := ui.NewFrame("Status Bar") frame := ui.NewFrame("Status Bar")

View File

@ -4,9 +4,89 @@ import (
"git.kirsle.net/apps/doodle/lib/render" "git.kirsle.net/apps/doodle/lib/render"
"git.kirsle.net/apps/doodle/lib/ui" "git.kirsle.net/apps/doodle/lib/ui"
"git.kirsle.net/apps/doodle/pkg/balance" "git.kirsle.net/apps/doodle/pkg/balance"
"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/uix"
) )
// SetupPalette sets up the palette panel.
func (u *EditorUI) SetupPalette(d *Doodle) *ui.Window {
window := ui.NewWindow("Palette")
window.ConfigureTitle(balance.TitleConfig)
window.TitleBar().Font = balance.TitleFont
window.Configure(ui.Config{
Background: balance.WindowBackground,
BorderColor: balance.WindowBorder,
})
// Frame that holds the tab buttons in Level Edit mode.
tabFrame := ui.NewFrame("Palette Tabs")
for _, name := range []string{"Palette", "Doodads"} {
if u.paletteTab == "" {
u.paletteTab = name
}
tab := ui.NewRadioButton("Palette Tab", &u.paletteTab, name, ui.NewLabel(ui.Label{
Text: name,
}))
tab.Handle(ui.Click, func(p render.Point) {
if u.paletteTab == "Palette" {
u.Canvas.Tool = uix.PencilTool
u.PaletteTab.Show()
u.DoodadTab.Hide()
} else {
u.Canvas.Tool = uix.ActorTool
u.PaletteTab.Hide()
u.DoodadTab.Show()
}
window.Compute(d.Engine)
})
u.Supervisor.Add(tab)
tabFrame.Pack(tab, ui.Pack{
Anchor: ui.W,
Fill: true,
Expand: true,
})
}
window.Pack(tabFrame, ui.Pack{
Anchor: ui.N,
Fill: true,
PadY: 4,
})
// Only show the tab frame in Level drawing mode!
if u.Scene.DrawingType != enum.LevelDrawing {
tabFrame.Hide()
}
// Doodad frame.
{
frame, err := u.setupDoodadFrame(d.Engine, window)
if err != nil {
d.Flash(err.Error())
}
// Even if there was an error (userdir.ListDoodads couldn't read the
// config folder on disk or whatever) the Frame is still valid but
// empty, which is still the intended behavior.
u.DoodadTab = frame
u.DoodadTab.Hide()
window.Pack(u.DoodadTab, ui.Pack{
Anchor: ui.N,
Fill: true,
})
}
// Color Palette Frame.
u.PaletteTab = u.setupPaletteFrame(window)
window.Pack(u.PaletteTab, ui.Pack{
Anchor: ui.N,
Fill: true,
})
return window
}
// setupPaletteFrame configures the Color Palette tab for Edit Mode. // setupPaletteFrame configures the Color Palette tab for Edit Mode.
// This is a subroutine of editor_ui.go#SetupPalette() // This is a subroutine of editor_ui.go#SetupPalette()
func (u *EditorUI) setupPaletteFrame(window *ui.Window) *ui.Frame { func (u *EditorUI) setupPaletteFrame(window *ui.Window) *ui.Frame {
@ -32,7 +112,7 @@ func (u *EditorUI) setupPaletteFrame(window *ui.Window) *ui.Frame {
Text: swatch.Name, Text: swatch.Name,
Font: balance.StatusFont, Font: balance.StatusFont,
}) })
label.Font.Color = swatch.Color.Darken(40) label.Font.Color = swatch.Color.Darken(128)
btn := ui.NewRadioButton("palette", &u.selectedSwatch, swatch.Name, label) btn := ui.NewRadioButton("palette", &u.selectedSwatch, swatch.Name, label)
btn.Handle(ui.Click, onClick) btn.Handle(ui.Click, onClick)

View File

@ -29,6 +29,38 @@ func DefaultPalette() *Palette {
} }
} }
// NewBlueprintPalette returns the blueprint theme's color palette.
func NewBlueprintPalette() *Palette {
return &Palette{
Swatches: []*Swatch{
&Swatch{
Name: "solid",
Color: render.RGBA(254, 254, 254, 255),
Solid: true,
},
&Swatch{
Name: "decoration",
Color: render.Grey,
},
&Swatch{
Name: "fire",
Color: render.RGBA(255, 80, 0, 255),
Fire: true,
},
&Swatch{
Name: "water",
Color: render.RGBA(0, 153, 255, 255),
Water: true,
},
&Swatch{
Name: "electric",
Color: render.RGBA(255, 255, 0, 255),
Solid: true,
},
},
}
}
// NewPalette initializes a blank palette. // NewPalette initializes a blank palette.
func NewPalette() *Palette { func NewPalette() *Palette {
return &Palette{ return &Palette{

View File

@ -10,6 +10,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/uix"
"git.kirsle.net/apps/doodle/pkg/userdir" "git.kirsle.net/apps/doodle/pkg/userdir"
) )
@ -29,6 +30,9 @@ type MenuScene struct {
// Private widgets. // Private widgets.
window *ui.Window window *ui.Window
// Background wallpaper canvas.
canvas *uix.Canvas
// Values for the New menu // Values for the New menu
newPageType string newPageType string
newWallpaper string newWallpaper string
@ -61,6 +65,19 @@ func (d *Doodle) GotoLoadMenu() {
func (s *MenuScene) Setup(d *Doodle) error { func (s *MenuScene) Setup(d *Doodle) error {
s.Supervisor = ui.NewSupervisor() s.Supervisor = ui.NewSupervisor()
// Set up the background wallpaper canvas.
s.canvas = uix.NewCanvas(100, false)
s.canvas.Resize(render.Rect{
W: int32(d.width),
H: int32(d.height),
})
s.canvas.LoadLevel(d.Engine, &level.Level{
Chunker: level.NewChunker(100),
Palette: level.NewPalette(),
PageType: level.Bounded,
Wallpaper: "notebook.png",
})
switch s.StartupMenu { switch s.StartupMenu {
case "new": case "new":
if err := s.setupNewWindow(d); err != nil { if err := s.setupNewWindow(d); err != nil {
@ -77,6 +94,17 @@ func (s *MenuScene) Setup(d *Doodle) error {
return nil return nil
} }
// configureCanvas updates the settings of the background canvas, so a live
// preview of the wallpaper and wrapping type can be shown.
func (s *MenuScene) configureCanvas(e render.Engine, pageType level.PageType, wallpaper string) {
s.canvas.LoadLevel(e, &level.Level{
Chunker: level.NewChunker(100),
Palette: level.NewPalette(),
PageType: pageType,
Wallpaper: wallpaper,
})
}
// 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. // Default scene options.
@ -85,8 +113,8 @@ func (s *MenuScene) setupNewWindow(d *Doodle) error {
window := ui.NewWindow("New Drawing") window := ui.NewWindow("New Drawing")
window.Configure(ui.Config{ window.Configure(ui.Config{
Width: int32(float64(d.width) * 0.8), Width: int32(float64(d.width) * 0.75),
Height: int32(float64(d.height) * 0.8), Height: int32(float64(d.height) * 0.75),
Background: render.Grey, Background: render.Grey,
}) })
window.Compute(d.Engine) window.Compute(d.Engine)
@ -118,10 +146,11 @@ func (s *MenuScene) setupNewWindow(d *Doodle) error {
FillX: true, FillX: true,
}) })
var types = []struct { type typeObj struct {
Name string Name string
Value level.PageType Value level.PageType
}{ }
var types = []typeObj{
{"Unbounded", level.Unbounded}, {"Unbounded", level.Unbounded},
{"Bounded", level.Bounded}, {"Bounded", level.Bounded},
{"No Negative Space", level.NoNegativeSpace}, {"No Negative Space", level.NoNegativeSpace},
@ -135,19 +164,24 @@ func (s *MenuScene) setupNewWindow(d *Doodle) error {
} }
} }
radio := ui.NewRadioButton(t.Name, func(t typeObj) {
&s.newPageType, radio := ui.NewRadioButton(t.Name,
t.Value.String(), &s.newPageType,
ui.NewLabel(ui.Label{ t.Value.String(),
Text: t.Name, ui.NewLabel(ui.Label{
Font: balance.MenuFont, Text: t.Name,
}), Font: balance.MenuFont,
) }),
s.Supervisor.Add(radio) )
typeFrame.Pack(radio, ui.Pack{ radio.Handle(ui.Click, func(p render.Point) {
Anchor: ui.W, s.configureCanvas(d.Engine, t.Value, s.newWallpaper)
PadX: 4, })
}) s.Supervisor.Add(radio)
typeFrame.Pack(radio, ui.Pack{
Anchor: ui.W,
PadX: 4,
})
}(t)
} }
/****************** /******************
@ -169,25 +203,34 @@ func (s *MenuScene) setupNewWindow(d *Doodle) error {
FillX: true, FillX: true,
}) })
var wallpapers = []struct { type wallpaperObj struct {
Name string Name string
Value string Value string
}{ }
var wallpapers = []wallpaperObj{
{"Notebook", "notebook.png"}, {"Notebook", "notebook.png"},
{"Blueprint", "blueprint.png"}, {"Blueprint", "blueprint.png"},
{"Legal Pad", "legal.png"}, {"Legal Pad", "legal.png"},
{"Placemat", "placemat.png"}, {"Placemat", "placemat.png"},
} }
for _, t := range wallpapers { for _, t := range wallpapers {
radio := ui.NewRadioButton(t.Name, &s.newWallpaper, t.Value, ui.NewLabel(ui.Label{ func(t wallpaperObj) {
Text: t.Name, radio := ui.NewRadioButton(t.Name, &s.newWallpaper, t.Value, ui.NewLabel(ui.Label{
Font: balance.MenuFont, Text: t.Name,
})) Font: balance.MenuFont,
s.Supervisor.Add(radio) }))
wpFrame.Pack(radio, ui.Pack{ radio.Handle(ui.Click, func(p render.Point) {
Anchor: ui.W, log.Info("Set wallpaper to %s", t.Value)
PadX: 4, if pageType, ok := level.PageTypeFromString(s.newPageType); ok {
}) s.configureCanvas(d.Engine, pageType, t.Value)
}
})
s.Supervisor.Add(radio)
wpFrame.Pack(radio, ui.Pack{
Anchor: ui.W,
PadX: 4,
})
}(t)
} }
/****************** /******************
@ -224,6 +267,11 @@ func (s *MenuScene) setupNewWindow(d *Doodle) error {
lvl.Wallpaper = s.newWallpaper lvl.Wallpaper = s.newWallpaper
lvl.PageType = pageType lvl.PageType = pageType
// Blueprint theme palette for the dark wallpaper color.
if lvl.Wallpaper == "blueprint.png" {
lvl.Palette = level.NewBlueprintPalette()
}
d.Goto(&EditorScene{ d.Goto(&EditorScene{
DrawingType: enum.LevelDrawing, DrawingType: enum.LevelDrawing,
Level: lvl, Level: lvl,
@ -257,8 +305,8 @@ func (s *MenuScene) setupNewWindow(d *Doodle) error {
func (s *MenuScene) setupLoadWindow(d *Doodle) error { func (s *MenuScene) setupLoadWindow(d *Doodle) error {
window := ui.NewWindow("Open Drawing") window := ui.NewWindow("Open Drawing")
window.Configure(ui.Config{ window.Configure(ui.Config{
Width: int32(float64(d.width) * 0.8), Width: int32(float64(d.width) * 0.75),
Height: int32(float64(d.height) * 0.8), Height: int32(float64(d.height) * 0.75),
Background: render.Grey, Background: render.Grey,
}) })
window.Compute(d.Engine) window.Compute(d.Engine)
@ -424,6 +472,9 @@ func (s *MenuScene) Draw(d *Doodle) error {
// Clear the canvas and fill it with white. // Clear the canvas and fill it with white.
d.Engine.Clear(render.White) d.Engine.Clear(render.White)
// Draw the background canvas.
s.canvas.Present(d.Engine, render.Origin)
s.window.Compute(d.Engine) s.window.Compute(d.Engine)
s.window.MoveTo(render.Point{ s.window.MoveTo(render.Point{
X: (int32(d.width) / 2) - (s.window.Size().W / 2), X: (int32(d.width) / 2) - (s.window.Size().W / 2),