doodle/pkg/windows/layers_window.go

291 lines
5.9 KiB
Go
Raw Permalink Normal View History

package windows
import (
"fmt"
"math"
2022-09-24 22:17:25 +00:00
"git.kirsle.net/SketchyMaze/doodle/pkg/balance"
"git.kirsle.net/SketchyMaze/doodle/pkg/doodads"
"git.kirsle.net/SketchyMaze/doodle/pkg/shmem"
"git.kirsle.net/go/render"
"git.kirsle.net/go/ui"
)
// Layers shows the layers when editing a doodad file.
type Layers struct {
Supervisor *ui.Supervisor
Engine render.Engine
// Pointer to the currently edited level.
EditDoodad *doodads.Doodad
ActiveLayer int // pointer to selected layer
activeLayer string // cached string for radio button
// Callback functions.
OnChange func(*doodads.Doodad) // Doodad data was modified, reload the Canvas etc.
OnAddLayer func() // "Add Layer" button was clicked
OnCancel func() // Close button was clicked.
// Editor should change the active layer
OnChangeLayer func(index int)
}
// NewLayerWindow initializes the window.
func NewLayerWindow(config Layers) *ui.Window {
// Default options.
var (
title = "Layers"
rows = []*ui.Frame{}
// size of the popup window
width = 320
height = 300
// Column sizes of the palette table.
col1 = 40 // Index
col3 = 120 // Name
col4 = 60 // Edit button
// col5 = 150 // Delete
// pagination values
page = 1
perPage = 5
)
config.activeLayer = fmt.Sprintf("%d", config.ActiveLayer)
window := ui.NewWindow(title)
window.SetButtons(ui.CloseButton)
window.Configure(ui.Config{
Width: width,
Height: height,
Background: render.Grey,
})
frame := ui.NewFrame("Window Body Frame")
window.Pack(frame, ui.Pack{
Side: ui.N,
Fill: true,
Expand: true,
})
// Draw the header row.
headers := []struct {
Name string
Size int
}{
{"Index", col1},
{"Name", col3},
{"Edit", col4},
}
header := ui.NewFrame("Header")
for _, col := range headers {
labelFrame := ui.NewFrame(col.Name)
labelFrame.Configure(ui.Config{
Width: col.Size,
Height: 24,
})
label := ui.NewLabel(ui.Label{
Text: col.Name,
Font: balance.MenuFontBold,
})
labelFrame.Pack(label, ui.Pack{
Side: ui.N,
})
header.Pack(labelFrame, ui.Pack{
Side: ui.W,
Padding: 2,
})
}
header.Compute(config.Engine)
frame.Pack(header, ui.Pack{
Side: ui.N,
})
// Draw the rows for each Layer in the given doodad.
if doodad := config.EditDoodad; doodad != nil {
for i, _ := range doodad.Layers {
i := i // rescope
var idStr = fmt.Sprintf("%d", i)
row := ui.NewFrame("Layer " + idStr)
rows = append(rows, row)
// Off the end of the first page?
if i >= perPage {
row.Hide()
}
// ID label.
idLabel := ui.NewLabel(ui.Label{
Text: idStr + ".",
Font: balance.MenuFont,
})
idLabel.Configure(ui.Config{
Width: col1,
Height: 24,
})
// Name button (click to rename the swatch)
btnName := ui.NewButton("Name", ui.NewLabel(ui.Label{
TextVariable: &doodad.Layers[i].Name,
}))
btnName.Configure(ui.Config{
Width: col3,
Height: 24,
})
btnName.Handle(ui.Click, func(ed ui.EventData) error {
shmem.Prompt("New layer name ["+doodad.Layers[i].Name+"]: ", func(answer string) {
if answer != "" {
doodad.Layers[i].Name = answer
if config.OnChange != nil {
config.OnChange(config.EditDoodad)
}
}
})
return nil
})
config.Supervisor.Add(btnName)
// Edit button (open layer for editing)
// btnEdit := ui.NewButton("Edit", ui.NewLabel(ui.Label{
// Text: "Edit",
// }))
btnEdit := ui.NewRadioButton("Edit",
&config.activeLayer, idStr, ui.NewLabel(ui.Label{
Text: "Edit",
}))
btnEdit.Configure(ui.Config{
Width: col4,
Height: 24,
})
btnEdit.Handle(ui.Click, func(ed ui.EventData) error {
if config.OnChangeLayer != nil {
config.OnChangeLayer(i)
}
return nil
})
config.Supervisor.Add(btnEdit)
// Pack all the widgets.
row.Pack(idLabel, ui.Pack{
Side: ui.W,
PadX: 2,
})
row.Pack(btnName, ui.Pack{
Side: ui.W,
PadX: 2,
})
row.Pack(btnEdit, ui.Pack{
Side: ui.W,
PadX: 2,
})
row.Compute(config.Engine)
frame.Pack(row, ui.Pack{
Side: ui.N,
PadY: 2,
})
}
}
{
/******************
* Confirm/cancel buttons.
******************/
bottomFrame := ui.NewFrame("Button Frame")
frame.Pack(bottomFrame, ui.Pack{
Side: ui.S,
FillX: true,
})
// Pager for the doodads.
pager := ui.NewPager(ui.Pager{
Name: "Layers Window Pager",
Page: page,
Pages: int(math.Ceil(
float64(len(rows)) / float64(perPage),
)),
PerPage: perPage,
MaxPageButtons: 10,
Font: balance.MenuFont,
OnChange: func(newPage, perPage int) {
page = newPage
// Re-evaluate which rows are shown/hidden for this page.
var (
minRow = (page - 1) * perPage
visible = 0
)
for i, row := range rows {
if visible >= perPage {
row.Hide()
continue
}
if i < minRow {
row.Hide()
} else {
row.Show()
visible++
}
}
},
})
pager.Compute(config.Engine)
pager.Supervise(config.Supervisor)
bottomFrame.Place(pager, ui.Place{
Top: 20,
Left: 20,
})
btnFrame := ui.NewFrame("Window Buttons")
var buttons = []struct {
Label string
F func(ui.EventData) error
}{
{"Add Layer", func(ed ui.EventData) error {
if config.OnAddLayer != nil {
config.OnAddLayer()
}
if config.OnChange != nil {
config.OnChange(config.EditDoodad)
}
return nil
}},
{"Close", func(ed ui.EventData) error {
if config.OnCancel != nil {
config.OnCancel()
}
return nil
}},
}
for _, t := range buttons {
btn := ui.NewButton(t.Label, ui.NewLabel(ui.Label{
Text: t.Label,
Font: balance.MenuFont,
}))
btn.Handle(ui.Click, t.F)
btn.Compute(config.Engine)
config.Supervisor.Add(btn)
btnFrame.Pack(btn, ui.Pack{
Side: ui.W,
PadX: 4,
})
}
bottomFrame.Place(btnFrame, ui.Place{
Top: 60,
Center: true,
})
}
window.Hide()
return window
}