From 3d3561b8e696d52b652fae1b3111cb2f6a47c5c8 Mon Sep 17 00:00:00 2001 From: Noah Petherbridge Date: Tue, 25 Jun 2019 17:43:23 -0700 Subject: [PATCH] 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. --- pkg/balance/debug.go | 2 +- pkg/editor_scene.go | 3 ++ pkg/editor_ui.go | 89 +++---------------------------- pkg/editor_ui_palette.go | 82 ++++++++++++++++++++++++++++- pkg/level/palette.go | 32 +++++++++++ pkg/menu_scene.go | 111 ++++++++++++++++++++++++++++----------- 6 files changed, 206 insertions(+), 113 deletions(-) diff --git a/pkg/balance/debug.go b/pkg/balance/debug.go index 6e8d50f..5e51ba8 100644 --- a/pkg/balance/debug.go +++ b/pkg/balance/debug.go @@ -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() { diff --git a/pkg/editor_scene.go b/pkg/editor_scene.go index d1678d4..4435329 100644 --- a/pkg/editor_scene.go +++ b/pkg/editor_scene.go @@ -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 diff --git a/pkg/editor_ui.go b/pkg/editor_ui.go index 47ea54e..20b24b1 100644 --- a/pkg/editor_ui.go +++ b/pkg/editor_ui.go @@ -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") diff --git a/pkg/editor_ui_palette.go b/pkg/editor_ui_palette.go index 114ad28..9fd7544 100644 --- a/pkg/editor_ui_palette.go +++ b/pkg/editor_ui_palette.go @@ -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) diff --git a/pkg/level/palette.go b/pkg/level/palette.go index b5991d5..55c609b 100644 --- a/pkg/level/palette.go +++ b/pkg/level/palette.go @@ -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{ diff --git a/pkg/menu_scene.go b/pkg/menu_scene.go index 3f5f703..ef89421 100644 --- a/pkg/menu_scene.go +++ b/pkg/menu_scene.go @@ -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,19 +164,24 @@ func (s *MenuScene) setupNewWindow(d *Doodle) error { } } - radio := ui.NewRadioButton(t.Name, - &s.newPageType, - t.Value.String(), - ui.NewLabel(ui.Label{ - Text: t.Name, - Font: balance.MenuFont, - }), - ) - s.Supervisor.Add(radio) - typeFrame.Pack(radio, ui.Pack{ - Anchor: ui.W, - PadX: 4, - }) + func(t typeObj) { + radio := ui.NewRadioButton(t.Name, + &s.newPageType, + t.Value.String(), + ui.NewLabel(ui.Label{ + Text: t.Name, + 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 { - radio := ui.NewRadioButton(t.Name, &s.newWallpaper, t.Value, ui.NewLabel(ui.Label{ - Text: t.Name, - Font: balance.MenuFont, - })) - s.Supervisor.Add(radio) - wpFrame.Pack(radio, ui.Pack{ - Anchor: ui.W, - PadX: 4, - }) + 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),