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.
// Pretty-print JSON files when writing.
JSONIndent = false
JSONIndent = true
)
func init() {

View File

@ -117,6 +117,9 @@ func (s *EditorScene) Setup(d *Doodle) error {
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.")
return nil

View File

@ -76,11 +76,8 @@ func NewEditorUI(d *Doodle, s *EditorScene) *EditorUI {
u.Canvas = u.SetupCanvas(d)
u.MenuBar = u.SetupMenuBar(d)
u.StatusBar = u.SetupStatusBar(d)
u.Palette = u.SetupPalette(d)
u.Workspace = u.SetupWorkspace(d) // important that this is last!
u.Resized(d)
// Position the Canvas inside the frame.
u.Workspace.Pack(u.Canvas, ui.Pack{
Anchor: ui.N,
@ -95,6 +92,14 @@ func NewEditorUI(d *Doodle, s *EditorScene) *EditorUI {
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.
func (u *EditorUI) Resized(d *Doodle) {
// Menu Bar frame.
@ -442,84 +447,6 @@ func (u *EditorUI) SetupMenuBar(d *Doodle) *ui.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.
func (u *EditorUI) SetupStatusBar(d *Doodle) *ui.Frame {
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/ui"
"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/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.
// This is a subroutine of editor_ui.go#SetupPalette()
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,
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.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.
func NewPalette() *Palette {
return &Palette{

View File

@ -10,6 +10,7 @@ import (
"git.kirsle.net/apps/doodle/pkg/enum"
"git.kirsle.net/apps/doodle/pkg/level"
"git.kirsle.net/apps/doodle/pkg/log"
"git.kirsle.net/apps/doodle/pkg/uix"
"git.kirsle.net/apps/doodle/pkg/userdir"
)
@ -29,6 +30,9 @@ type MenuScene struct {
// Private widgets.
window *ui.Window
// Background wallpaper canvas.
canvas *uix.Canvas
// Values for the New menu
newPageType string
newWallpaper string
@ -61,6 +65,19 @@ func (d *Doodle) GotoLoadMenu() {
func (s *MenuScene) Setup(d *Doodle) error {
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 {
case "new":
if err := s.setupNewWindow(d); err != nil {
@ -77,6 +94,17 @@ func (s *MenuScene) Setup(d *Doodle) error {
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.
func (s *MenuScene) setupNewWindow(d *Doodle) error {
// Default scene options.
@ -85,8 +113,8 @@ func (s *MenuScene) setupNewWindow(d *Doodle) error {
window := ui.NewWindow("New Drawing")
window.Configure(ui.Config{
Width: int32(float64(d.width) * 0.8),
Height: int32(float64(d.height) * 0.8),
Width: int32(float64(d.width) * 0.75),
Height: int32(float64(d.height) * 0.75),
Background: render.Grey,
})
window.Compute(d.Engine)
@ -118,10 +146,11 @@ func (s *MenuScene) setupNewWindow(d *Doodle) error {
FillX: true,
})
var types = []struct {
type typeObj struct {
Name string
Value level.PageType
}{
}
var types = []typeObj{
{"Unbounded", level.Unbounded},
{"Bounded", level.Bounded},
{"No Negative Space", level.NoNegativeSpace},
@ -135,6 +164,7 @@ func (s *MenuScene) setupNewWindow(d *Doodle) error {
}
}
func(t typeObj) {
radio := ui.NewRadioButton(t.Name,
&s.newPageType,
t.Value.String(),
@ -143,11 +173,15 @@ func (s *MenuScene) setupNewWindow(d *Doodle) error {
Font: balance.MenuFont,
}),
)
radio.Handle(ui.Click, func(p render.Point) {
s.configureCanvas(d.Engine, t.Value, s.newWallpaper)
})
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,
})
var wallpapers = []struct {
type wallpaperObj struct {
Name string
Value string
}{
}
var wallpapers = []wallpaperObj{
{"Notebook", "notebook.png"},
{"Blueprint", "blueprint.png"},
{"Legal Pad", "legal.png"},
{"Placemat", "placemat.png"},
}
for _, t := range wallpapers {
func(t wallpaperObj) {
radio := ui.NewRadioButton(t.Name, &s.newWallpaper, t.Value, ui.NewLabel(ui.Label{
Text: t.Name,
Font: balance.MenuFont,
}))
radio.Handle(ui.Click, func(p render.Point) {
log.Info("Set wallpaper to %s", t.Value)
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.PageType = pageType
// Blueprint theme palette for the dark wallpaper color.
if lvl.Wallpaper == "blueprint.png" {
lvl.Palette = level.NewBlueprintPalette()
}
d.Goto(&EditorScene{
DrawingType: enum.LevelDrawing,
Level: lvl,
@ -257,8 +305,8 @@ func (s *MenuScene) setupNewWindow(d *Doodle) error {
func (s *MenuScene) setupLoadWindow(d *Doodle) error {
window := ui.NewWindow("Open Drawing")
window.Configure(ui.Config{
Width: int32(float64(d.width) * 0.8),
Height: int32(float64(d.height) * 0.8),
Width: int32(float64(d.width) * 0.75),
Height: int32(float64(d.height) * 0.75),
Background: render.Grey,
})
window.Compute(d.Engine)
@ -424,6 +472,9 @@ func (s *MenuScene) Draw(d *Doodle) error {
// Clear the canvas and fill it with white.
d.Engine.Clear(render.White)
// Draw the background canvas.
s.canvas.Present(d.Engine, render.Origin)
s.window.Compute(d.Engine)
s.window.MoveTo(render.Point{
X: (int32(d.width) / 2) - (s.window.Size().W / 2),