Noah Petherbridge
b17ca34de2
* Use `go-bindata` to embed built-in doodads and levels directly into the Doodle binary. `make bindata` produces the bindata source file. * Add `FromJSON()` method to Levels and Doodads to load objects from JSON strings in memory (for bindata built-ins or WASM ajax requests) * Update file loading functions to check the embedded bindata files. * pkg/config.go#EditFile: * Supports editing a level from bindata (TODO: remove this support) * If the "assets/levels/%(simple-name.level)" exists in bindata, edits that drawing. * No such support for editing built-in doodads. * WASM has no filesystem access to edit files except built-in levels (yet) * pkg/doodads#ListDoodads: * Prepends built-in doodads from bindata to the returned list. * WASM: no filesystem access so gets only the built-ins. * pkg/doodads#LoadFile: * Checks built-in bindata store first for doodad files. * WASM: tries an HTTP request if not found in bindata but can go no further if not found (no filesystem access) * pkg/filesystem#FindFile: * This function finds a level/doodad by checking all the places. * If the level or doodad exists in bindata built-in, always returns its system path like "assets/doodads/test.doodad" * WASM: always returns the built-in candidate path even if not found in bindata so that ajax GET can be attempted. * pkg/level#ListSystemLevels: * New function that lists the system level files, similar to the equivalent doodads function. * Prepends the bindata built-in level files. * WASM: only returns the built-ins (no filesystem support) * Desktop: also lists and returns the assets/levels/ directory. * pkg/level#LoadFile: * Like the doodads.LoadFile, tries from built-in bindata first, then ajax request (WASM) before accessing the filesystem (desktop) * Menu Scene: TODO, list the built-in levels in the Load Level menu. This feature will soon go away when WASM gets its own storage for user levels (localStorage instead of filesystem)
189 lines
4.9 KiB
Go
189 lines
4.9 KiB
Go
package doodle
|
|
|
|
// XXX REFACTOR XXX
|
|
// This function only uses EditorUI and not Doodle and is a candidate for
|
|
// refactor into a subpackage if EditorUI itself can ever be decoupled.
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"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/doodads"
|
|
"git.kirsle.net/apps/doodle/pkg/log"
|
|
"git.kirsle.net/apps/doodle/pkg/uix"
|
|
)
|
|
|
|
// DraggableActor is a Doodad being dragged from the Doodad palette.
|
|
type DraggableActor struct {
|
|
canvas *uix.Canvas
|
|
doodad *doodads.Doodad
|
|
}
|
|
|
|
// startDragActor begins the drag event for a Doodad onto a level.
|
|
func (u *EditorUI) startDragActor(doodad *doodads.Doodad) {
|
|
u.Supervisor.DragStart()
|
|
|
|
// Create the canvas to render on the mouse cursor.
|
|
drawing := uix.NewCanvas(doodad.Layers[0].Chunker.Size, false)
|
|
drawing.LoadDoodad(doodad)
|
|
drawing.Resize(doodad.Rect())
|
|
drawing.SetBackground(render.RGBA(0, 0, 1, 0)) // TODO: invisible becomes white
|
|
drawing.MaskColor = balance.DragColor // blueprint effect
|
|
u.DraggableActor = &DraggableActor{
|
|
canvas: drawing,
|
|
doodad: doodad,
|
|
}
|
|
}
|
|
|
|
// setupDoodadFrame configures the Doodad Palette tab for Edit Mode.
|
|
// This is a subroutine of editor_ui.go#SetupPalette()
|
|
//
|
|
// Can return an error if userdir.ListDoodads() returns an error (like directory
|
|
// not found), but it will *ALWAYS* return a valid ui.Frame -- it will just be
|
|
// empty and uninitialized.
|
|
func (u *EditorUI) setupDoodadFrame(e render.Engine, window *ui.Window) (*ui.Frame, error) {
|
|
var (
|
|
frame = ui.NewFrame("Doodad Tab")
|
|
perRow = balance.UIDoodadsPerRow
|
|
)
|
|
|
|
frame.SetBackground(render.RGBA(0, 153, 255, 153))
|
|
|
|
// Toolbar on top of the Doodad panel.
|
|
toolbar := ui.NewFrame("Doodad Palette Toolbar")
|
|
toolbar.Configure(ui.Config{
|
|
Background: render.Grey,
|
|
BorderSize: 2,
|
|
BorderStyle: ui.BorderRaised,
|
|
Height: 24,
|
|
})
|
|
{
|
|
// Link button.
|
|
linkButton := ui.NewButton("Link", ui.NewLabel(ui.Label{
|
|
Text: "Link Doodads",
|
|
}))
|
|
linkButton.Handle(ui.Click, func(p render.Point) {
|
|
u.Canvas.LinkStart()
|
|
u.d.Flash("Click on the first Doodad to link to another one.")
|
|
})
|
|
u.Supervisor.Add(linkButton)
|
|
|
|
toolbar.Pack(linkButton, ui.Pack{
|
|
Anchor: ui.N,
|
|
FillX: true,
|
|
})
|
|
}
|
|
frame.Pack(toolbar, ui.Pack{
|
|
Anchor: ui.N,
|
|
Fill: true,
|
|
})
|
|
|
|
// Pager buttons on top of the doodad list.
|
|
pager := ui.NewFrame("Doodad Pager")
|
|
pager.SetBackground(render.RGBA(255, 0, 0, 20)) // TODO: if I don't set a background color,
|
|
// this frame will light up the same color as the Link button on mouse
|
|
// over. somewhere some memory might be shared between the recent widgets
|
|
{
|
|
leftBtn := ui.NewButton("Prev Page", ui.NewLabel(ui.Label{
|
|
Text: "<",
|
|
}))
|
|
u.Supervisor.Add(leftBtn)
|
|
pager.Pack(leftBtn, ui.Pack{
|
|
Anchor: ui.W,
|
|
})
|
|
|
|
pageLabel := ui.NewLabel(ui.Label{
|
|
Text: " Page 1 of 20",
|
|
})
|
|
pager.Pack(pageLabel, ui.Pack{
|
|
Anchor: ui.W,
|
|
Expand: true,
|
|
})
|
|
|
|
rightBtn := ui.NewButton("Next Page", ui.NewLabel(ui.Label{
|
|
Text: ">",
|
|
}))
|
|
u.Supervisor.Add(rightBtn)
|
|
pager.Pack(rightBtn, ui.Pack{
|
|
Anchor: ui.W,
|
|
})
|
|
}
|
|
frame.Pack(pager, ui.Pack{
|
|
Anchor: ui.N,
|
|
Fill: true,
|
|
PadY: 5,
|
|
})
|
|
|
|
doodadsAvailable, err := doodads.ListDoodads()
|
|
if err != nil {
|
|
return frame, fmt.Errorf(
|
|
"setupDoodadFrame: doodads.ListDoodads: %s",
|
|
err,
|
|
)
|
|
}
|
|
|
|
var buttonSize = (paletteWidth - window.BoxThickness(2)) / int32(perRow)
|
|
|
|
// Draw the doodad buttons in a grid `perRow` buttons wide.
|
|
var (
|
|
row *ui.Frame
|
|
rowCount int // for labeling the ui.Frame for each row
|
|
)
|
|
for i, filename := range doodadsAvailable {
|
|
if row == nil || i%perRow == 0 {
|
|
rowCount++
|
|
row = ui.NewFrame(fmt.Sprintf("Doodad Row %d", rowCount))
|
|
row.SetBackground(balance.WindowBackground)
|
|
frame.Pack(row, ui.Pack{
|
|
Anchor: ui.N,
|
|
Fill: true,
|
|
})
|
|
}
|
|
|
|
func(filename string) {
|
|
doodad, err := doodads.LoadFile(filename)
|
|
if err != nil {
|
|
log.Error(err.Error())
|
|
doodad = doodads.New(balance.DoodadSize)
|
|
}
|
|
|
|
can := uix.NewCanvas(int(buttonSize), true)
|
|
can.Name = filename
|
|
can.SetBackground(render.White)
|
|
can.LoadDoodad(doodad)
|
|
|
|
btn := ui.NewButton(filename, can)
|
|
btn.Resize(render.NewRect(
|
|
buttonSize-2, // TODO: without the -2 the button border
|
|
buttonSize-2, // rests on top of the window border.
|
|
))
|
|
row.Pack(btn, ui.Pack{
|
|
Anchor: ui.W,
|
|
})
|
|
|
|
// Begin the drag event to grab this Doodad.
|
|
// NOTE: The drag target is the EditorUI.Canvas in
|
|
// editor_ui.go#SetupCanvas()
|
|
btn.Handle(ui.MouseDown, func(e render.Point) {
|
|
log.Warn("MouseDown on doodad %s (%s)", doodad.Filename, doodad.Title)
|
|
u.startDragActor(doodad)
|
|
})
|
|
u.Supervisor.Add(btn)
|
|
|
|
// Resize the canvas to fill the button interior.
|
|
btnSize := btn.Size()
|
|
can.Resize(render.NewRect(
|
|
btnSize.W-btn.BoxThickness(2),
|
|
btnSize.H-btn.BoxThickness(2),
|
|
),
|
|
)
|
|
|
|
btn.Compute(e)
|
|
}(filename)
|
|
}
|
|
|
|
return frame, nil
|
|
}
|