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),