Noah Petherbridge
5434484b6e
The `level.Canvas` is a widget that holds onto its Palette and Grid and has interactions to allow scrolling and editing the grid using the swatches available on the palette. Thus all of the logic in the Editor Mode for drawing directly onto the root SDL surface are now handled inside a level.Canvas instance. The `level.Canvas` widget has the following properties: * Like any widget it has an X,Y position and a width/height. * It has a Scroll position to control which slice of its drawing will be visible inside its bounding box. * It supports levels having negative coordinates for their pixels. It doesn't care. The default Scroll position is (0,0) at the top left corner of the widget but you can scroll into the negatives and see the negative pixels. * Keyboard keys will scroll the viewport inside the canvas. * The canvas draws only the pixels that are visible inside its bounding box. This feature will eventually pave the way toward: * Doodads being dropped on top of your map, each Doodad being its own Canvas widget. * Using drawings as button icons for the user interface, as the Canvas is a normal widget.
109 lines
2.4 KiB
Go
109 lines
2.4 KiB
Go
package level
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"git.kirsle.net/apps/doodle/render"
|
|
)
|
|
|
|
// DefaultPalette returns a sensible default palette.
|
|
func DefaultPalette() *Palette {
|
|
return &Palette{
|
|
Swatches: []*Swatch{
|
|
&Swatch{
|
|
Name: "solid",
|
|
Color: render.Black,
|
|
Solid: true,
|
|
},
|
|
&Swatch{
|
|
Name: "decoration",
|
|
Color: render.Grey,
|
|
},
|
|
&Swatch{
|
|
Name: "fire",
|
|
Color: render.Red,
|
|
Fire: true,
|
|
},
|
|
&Swatch{
|
|
Name: "water",
|
|
Color: render.Blue,
|
|
Water: true,
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
// NewPalette initializes a blank palette.
|
|
func NewPalette() *Palette {
|
|
return &Palette{
|
|
Swatches: []*Swatch{},
|
|
byName: map[string]int{},
|
|
}
|
|
}
|
|
|
|
// Palette holds an index of colors used in a drawing.
|
|
type Palette struct {
|
|
Swatches []*Swatch `json:"swatches"`
|
|
|
|
// Private runtime values
|
|
ActiveSwatch *Swatch `json:"-"` // name of the actively selected color
|
|
byName map[string]int // Cache map of swatches by name
|
|
}
|
|
|
|
// Swatch holds details about a single value in the palette.
|
|
type Swatch struct {
|
|
Name string `json:"name"`
|
|
Color render.Color `json:"color"`
|
|
|
|
// Optional attributes.
|
|
Solid bool `json:"solid,omitempty"`
|
|
Fire bool `json:"fire,omitempty"`
|
|
Water bool `json:"water,omitempty"`
|
|
|
|
// Private runtime attributes.
|
|
index int // position in the Palette, for reverse of `Palette.byName`
|
|
}
|
|
|
|
func (s Swatch) String() string {
|
|
return s.Name
|
|
}
|
|
|
|
// Index returns the Swatch's position in the palette.
|
|
func (s Swatch) Index() int {
|
|
fmt.Printf("%+v index: %d", s, s.index)
|
|
return s.index
|
|
}
|
|
|
|
// Inflate the palette swatch caches. Always call this method after you have
|
|
// initialized the palette (i.e. loaded it from JSON); this will update the
|
|
// "color by name" cache and assign the index numbers to each swatch.
|
|
func (p *Palette) Inflate() {
|
|
p.update()
|
|
}
|
|
|
|
// Get a swatch by name.
|
|
func (p *Palette) Get(name string) (result *Swatch, exists bool) {
|
|
p.update()
|
|
|
|
if index, ok := p.byName[name]; ok && index < len(p.Swatches) {
|
|
result = p.Swatches[index]
|
|
exists = true
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
// update the internal caches and such.
|
|
func (p *Palette) update() {
|
|
// Initialize the name cache if nil or if the size disagrees with the
|
|
// length of the swatches available.
|
|
if p.byName == nil || len(p.byName) != len(p.Swatches) {
|
|
// Initialize the name cache.
|
|
p.byName = map[string]int{}
|
|
for i, swatch := range p.Swatches {
|
|
swatch.index = i
|
|
p.byName[swatch.Name] = i
|
|
}
|
|
}
|
|
}
|