2018-10-20 22:42:49 +00:00
|
|
|
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"
|
|
|
|
|
2019-04-10 00:35:44 +00:00
|
|
|
"git.kirsle.net/apps/doodle/pkg/balance"
|
|
|
|
"git.kirsle.net/apps/doodle/pkg/doodads"
|
2019-07-05 23:04:36 +00:00
|
|
|
"git.kirsle.net/apps/doodle/pkg/level"
|
2019-04-10 00:35:44 +00:00
|
|
|
"git.kirsle.net/apps/doodle/pkg/log"
|
|
|
|
"git.kirsle.net/apps/doodle/pkg/uix"
|
2019-12-28 03:16:34 +00:00
|
|
|
"git.kirsle.net/go/render"
|
|
|
|
"git.kirsle.net/go/ui"
|
2018-10-20 22:42:49 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// DraggableActor is a Doodad being dragged from the Doodad palette.
|
|
|
|
type DraggableActor struct {
|
|
|
|
canvas *uix.Canvas
|
2019-07-05 23:04:36 +00:00
|
|
|
doodad *doodads.Doodad // if a new one from the palette
|
|
|
|
actor *level.Actor // if a level actor
|
2018-10-20 22:42:49 +00:00
|
|
|
}
|
|
|
|
|
2018-10-21 00:08:20 +00:00
|
|
|
// startDragActor begins the drag event for a Doodad onto a level.
|
2019-07-05 23:04:36 +00:00
|
|
|
// actor may be nil (if you drag a new doodad from the palette) or otherwise
|
|
|
|
// is an existing actor from the level.
|
|
|
|
func (u *EditorUI) startDragActor(doodad *doodads.Doodad, actor *level.Actor) {
|
2018-10-21 00:08:20 +00:00
|
|
|
u.Supervisor.DragStart()
|
|
|
|
|
2019-07-05 23:04:36 +00:00
|
|
|
if doodad == nil {
|
|
|
|
if actor != nil {
|
|
|
|
obj, err := doodads.LoadFile(actor.Filename)
|
|
|
|
if err != nil {
|
|
|
|
log.Error("startDragExistingActor: actor doodad name %s not found: %s", actor.Filename, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
doodad = obj
|
|
|
|
} else {
|
|
|
|
panic("EditorUI.startDragActor: doodad AND/OR actor is required, but neither were given")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-21 00:08:20 +00:00
|
|
|
// 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,
|
2019-07-05 23:04:36 +00:00
|
|
|
actor: actor,
|
2018-10-21 00:08:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-20 22:42:49 +00:00
|
|
|
// 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
|
|
|
|
)
|
|
|
|
|
2019-06-09 00:02:28 +00:00
|
|
|
// Pager buttons on top of the doodad list.
|
|
|
|
pager := ui.NewFrame("Doodad Pager")
|
2019-06-23 23:15:09 +00:00
|
|
|
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
|
2019-06-09 00:02:28 +00:00
|
|
|
{
|
|
|
|
leftBtn := ui.NewButton("Prev Page", ui.NewLabel(ui.Label{
|
|
|
|
Text: "<",
|
2019-07-04 04:55:15 +00:00
|
|
|
Font: balance.MenuFont,
|
2019-06-09 00:02:28 +00:00
|
|
|
}))
|
2019-07-04 04:55:15 +00:00
|
|
|
leftBtn.Handle(ui.Click, func(p render.Point) {
|
|
|
|
u.scrollDoodadFrame(-1)
|
|
|
|
})
|
2019-06-09 00:02:28 +00:00
|
|
|
u.Supervisor.Add(leftBtn)
|
|
|
|
pager.Pack(leftBtn, ui.Pack{
|
|
|
|
Anchor: ui.W,
|
|
|
|
})
|
|
|
|
|
2019-07-04 04:55:15 +00:00
|
|
|
scroller := ui.NewFrame("Doodad Scroll Progressbar")
|
|
|
|
scroller.Configure(ui.Config{
|
|
|
|
Width: 20,
|
|
|
|
Height: 20,
|
|
|
|
Background: render.RGBA(128, 128, 128, 128),
|
2019-06-09 00:02:28 +00:00
|
|
|
})
|
2019-07-04 04:55:15 +00:00
|
|
|
pager.Pack(scroller, ui.Pack{
|
2019-06-09 00:02:28 +00:00
|
|
|
Anchor: ui.W,
|
|
|
|
})
|
2019-07-04 04:55:15 +00:00
|
|
|
u.doodadScroller = scroller
|
2019-06-09 00:02:28 +00:00
|
|
|
|
|
|
|
rightBtn := ui.NewButton("Next Page", ui.NewLabel(ui.Label{
|
|
|
|
Text: ">",
|
2019-07-04 04:55:15 +00:00
|
|
|
Font: balance.MenuFont,
|
2019-06-09 00:02:28 +00:00
|
|
|
}))
|
2019-07-04 04:55:15 +00:00
|
|
|
rightBtn.Handle(ui.Click, func(p render.Point) {
|
|
|
|
u.scrollDoodadFrame(1)
|
|
|
|
})
|
2019-06-09 00:02:28 +00:00
|
|
|
u.Supervisor.Add(rightBtn)
|
|
|
|
pager.Pack(rightBtn, ui.Pack{
|
2019-07-04 04:55:15 +00:00
|
|
|
Anchor: ui.E,
|
2019-06-09 00:02:28 +00:00
|
|
|
})
|
|
|
|
}
|
2019-07-04 04:55:15 +00:00
|
|
|
u.doodadPager = pager
|
2019-06-09 00:02:28 +00:00
|
|
|
frame.Pack(pager, ui.Pack{
|
|
|
|
Anchor: ui.N,
|
|
|
|
Fill: true,
|
2019-06-23 23:15:09 +00:00
|
|
|
PadY: 5,
|
2019-06-09 00:02:28 +00:00
|
|
|
})
|
|
|
|
|
2019-05-05 22:12:15 +00:00
|
|
|
doodadsAvailable, err := doodads.ListDoodads()
|
2018-10-20 22:42:49 +00:00
|
|
|
if err != nil {
|
|
|
|
return frame, fmt.Errorf(
|
2019-05-05 22:12:15 +00:00
|
|
|
"setupDoodadFrame: doodads.ListDoodads: %s",
|
2018-10-20 22:42:49 +00:00
|
|
|
err,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2019-12-28 03:16:34 +00:00
|
|
|
var buttonSize = (paletteWidth - window.BoxThickness(2)) / perRow
|
2019-07-04 04:55:15 +00:00
|
|
|
u.doodadButtonSize = buttonSize
|
2018-10-20 22:42:49 +00:00
|
|
|
|
2019-07-07 06:28:11 +00:00
|
|
|
// Load all the doodads, skip hidden ones.
|
|
|
|
var items []*doodads.Doodad
|
|
|
|
for _, filename := range doodadsAvailable {
|
|
|
|
doodad, err := doodads.LoadFile(filename)
|
|
|
|
if err != nil {
|
|
|
|
log.Error(err.Error())
|
|
|
|
doodad = doodads.New(balance.DoodadSize)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Skip hidden doodads.
|
|
|
|
if doodad.Hidden && !balance.ShowHiddenDoodads {
|
|
|
|
log.Info("skip %s: hidden doodad", filename)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
doodad.Filename = filename
|
|
|
|
items = append(items, doodad)
|
|
|
|
}
|
|
|
|
|
2018-10-20 22:42:49 +00:00
|
|
|
// Draw the doodad buttons in a grid `perRow` buttons wide.
|
|
|
|
var (
|
|
|
|
row *ui.Frame
|
2019-07-04 04:55:15 +00:00
|
|
|
rowCount int // for labeling the ui.Frame for each row
|
|
|
|
btnRows = []*ui.Frame{} // Collect the row frames for the buttons.
|
2018-10-20 22:42:49 +00:00
|
|
|
)
|
2019-07-07 06:28:11 +00:00
|
|
|
for i, doodad := range items {
|
|
|
|
doodad := doodad
|
2019-07-04 04:55:15 +00:00
|
|
|
|
2018-10-20 22:42:49 +00:00
|
|
|
if row == nil || i%perRow == 0 {
|
|
|
|
rowCount++
|
|
|
|
row = ui.NewFrame(fmt.Sprintf("Doodad Row %d", rowCount))
|
|
|
|
row.SetBackground(balance.WindowBackground)
|
2019-07-04 04:55:15 +00:00
|
|
|
btnRows = append(btnRows, row)
|
2018-10-20 22:42:49 +00:00
|
|
|
frame.Pack(row, ui.Pack{
|
|
|
|
Anchor: ui.N,
|
|
|
|
Fill: true,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2019-07-04 04:55:15 +00:00
|
|
|
can := uix.NewCanvas(int(buttonSize), true)
|
2019-07-07 06:28:11 +00:00
|
|
|
can.Name = doodad.Title
|
2019-07-04 04:55:15 +00:00
|
|
|
can.SetBackground(render.White)
|
|
|
|
can.LoadDoodad(doodad)
|
|
|
|
|
2019-07-07 06:28:11 +00:00
|
|
|
btn := ui.NewButton(doodad.Title, can)
|
2019-07-04 04:55:15 +00:00
|
|
|
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)
|
2019-07-05 23:04:36 +00:00
|
|
|
u.startDragActor(doodad, nil)
|
2019-07-04 04:55:15 +00:00
|
|
|
})
|
|
|
|
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)
|
2018-10-20 22:42:49 +00:00
|
|
|
}
|
|
|
|
|
2019-07-04 04:55:15 +00:00
|
|
|
u.doodadRows = btnRows
|
|
|
|
u.scrollDoodadFrame(0)
|
|
|
|
|
2018-10-20 22:42:49 +00:00
|
|
|
return frame, nil
|
|
|
|
}
|
2019-07-04 04:55:15 +00:00
|
|
|
|
|
|
|
// scrollDoodadFrame handles the Page Up/Down buttons to adjust the number of
|
|
|
|
// Doodads visible on screen.
|
|
|
|
//
|
|
|
|
// rows is the number of rows to scroll. Positive values mean scroll *down*
|
|
|
|
// the list.
|
|
|
|
func (u *EditorUI) scrollDoodadFrame(rows int) {
|
|
|
|
u.doodadSkip += rows
|
|
|
|
if u.doodadSkip < 0 {
|
|
|
|
u.doodadSkip = 0
|
|
|
|
}
|
|
|
|
|
|
|
|
// Calculate about how many rows we can see given our current window size.
|
|
|
|
var (
|
2019-12-28 03:16:34 +00:00
|
|
|
maxVisibleHeight = u.d.height - 86
|
|
|
|
calculatedHeight int
|
2019-07-04 04:55:15 +00:00
|
|
|
rowsBefore int // count of rows hidden before
|
|
|
|
rowsVisible int
|
|
|
|
rowsAfter int // count of rows hidden after
|
|
|
|
rowsEstimated = maxVisibleHeight / u.doodadButtonSize // estimated number rows shown
|
|
|
|
maxSkip = ((len(u.doodadRows) * int(u.doodadButtonSize)) - int(u.doodadButtonSize*rowsEstimated)) / int(u.doodadButtonSize)
|
|
|
|
)
|
|
|
|
|
|
|
|
if maxSkip < 0 {
|
|
|
|
maxSkip = 0
|
|
|
|
}
|
|
|
|
|
|
|
|
if u.doodadSkip > maxSkip {
|
|
|
|
u.doodadSkip = maxSkip
|
|
|
|
}
|
|
|
|
|
|
|
|
// If the window is big enough to encompass all the doodads, don't show
|
|
|
|
// the pager toolbar, its just confusing.
|
|
|
|
if maxSkip == 0 {
|
|
|
|
u.doodadPager.Hide()
|
|
|
|
} else {
|
|
|
|
u.doodadPager.Show()
|
|
|
|
}
|
|
|
|
|
|
|
|
// Comb through the doodads and show/hide the relevant buttons.
|
|
|
|
for i, row := range u.doodadRows {
|
|
|
|
if i < u.doodadSkip {
|
|
|
|
row.Hide()
|
|
|
|
rowsBefore++
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
calculatedHeight += u.doodadButtonSize
|
|
|
|
if calculatedHeight > maxVisibleHeight {
|
|
|
|
row.Hide()
|
|
|
|
rowsAfter++
|
|
|
|
} else {
|
|
|
|
row.Show()
|
|
|
|
rowsVisible++
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
var viewPercent = float64(rowsBefore+rowsVisible) / float64(len(u.doodadRows))
|
|
|
|
u.doodadScroller.Configure(ui.Config{
|
2019-12-28 03:16:34 +00:00
|
|
|
Width: int(float64(paletteWidth-50) * viewPercent), // TODO: hacky magic number
|
2019-07-04 04:55:15 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
}
|