Add Tool Bar to Editor Mode
* Toolbar has icon buttons for the Pencil Tool, Line Tool, Rect Tool, Actor Tool and Link Tool. * Remove the tab buttons from the top of the Palette window. The palette tab is now toggled between Swatches and Doodads by the tool selected on the tool bar, instead of the tab buttons setting the tool. * Remove the "Link Doodads" button from the Doodad Palette. The Link Tool has its own dedicated toolbar button with the others.
This commit is contained in:
parent
5a1ec156ca
commit
12d34517e9
BIN
assets/sprites/actor-tool.png
Normal file
BIN
assets/sprites/actor-tool.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 687 B |
BIN
assets/sprites/line-tool.png
Normal file
BIN
assets/sprites/line-tool.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 626 B |
BIN
assets/sprites/link-tool.png
Normal file
BIN
assets/sprites/link-tool.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 679 B |
BIN
assets/sprites/new-button.png
Normal file
BIN
assets/sprites/new-button.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 709 B |
BIN
assets/sprites/pencil-tool.png
Normal file
BIN
assets/sprites/pencil-tool.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 752 B |
BIN
assets/sprites/rect-tool.png
Normal file
BIN
assets/sprites/rect-tool.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 648 B |
|
@ -41,6 +41,13 @@ func NewImage(c Image) *Image {
|
||||||
return w
|
return w
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ImageFromTexture creates an Image from a texture.
|
||||||
|
func ImageFromTexture(tex render.Texturer) *Image {
|
||||||
|
return &Image{
|
||||||
|
texture: tex,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// OpenImage initializes an Image with a given file name.
|
// OpenImage initializes an Image with a given file name.
|
||||||
//
|
//
|
||||||
// The file extension is important and should be a supported ImageType.
|
// The file extension is important and should be a supported ImageType.
|
||||||
|
|
|
@ -41,6 +41,7 @@ type EditorUI struct {
|
||||||
Workspace *ui.Frame
|
Workspace *ui.Frame
|
||||||
MenuBar *ui.Frame
|
MenuBar *ui.Frame
|
||||||
StatusBar *ui.Frame
|
StatusBar *ui.Frame
|
||||||
|
ToolBar *ui.Frame
|
||||||
PlayButton *ui.Button
|
PlayButton *ui.Button
|
||||||
|
|
||||||
// Palette window.
|
// Palette window.
|
||||||
|
@ -48,6 +49,9 @@ type EditorUI struct {
|
||||||
PaletteTab *ui.Frame
|
PaletteTab *ui.Frame
|
||||||
DoodadTab *ui.Frame
|
DoodadTab *ui.Frame
|
||||||
|
|
||||||
|
// ToolBar window.
|
||||||
|
activeTool *string
|
||||||
|
|
||||||
// Draggable Doodad canvas.
|
// Draggable Doodad canvas.
|
||||||
DraggableActor *DraggableActor
|
DraggableActor *DraggableActor
|
||||||
|
|
||||||
|
@ -67,6 +71,10 @@ func NewEditorUI(d *Doodle, s *EditorScene) *EditorUI {
|
||||||
StatusScrollText: "Hello world",
|
StatusScrollText: "Hello world",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Default tool in the toolbox.
|
||||||
|
activeTool := drawtool.PencilTool.String()
|
||||||
|
u.activeTool = &activeTool
|
||||||
|
|
||||||
// Bind the StatusBoxes arrays to the text variables.
|
// Bind the StatusBoxes arrays to the text variables.
|
||||||
u.StatusBoxes = []*string{
|
u.StatusBoxes = []*string{
|
||||||
&u.StatusMouseText,
|
&u.StatusMouseText,
|
||||||
|
@ -78,6 +86,7 @@ func NewEditorUI(d *Doodle, s *EditorScene) *EditorUI {
|
||||||
u.Canvas = u.SetupCanvas(d)
|
u.Canvas = u.SetupCanvas(d)
|
||||||
u.MenuBar = u.SetupMenuBar(d)
|
u.MenuBar = u.SetupMenuBar(d)
|
||||||
u.StatusBar = u.SetupStatusBar(d)
|
u.StatusBar = u.SetupStatusBar(d)
|
||||||
|
u.ToolBar = u.SetupToolbar(d)
|
||||||
u.Workspace = u.SetupWorkspace(d) // important that this is last!
|
u.Workspace = u.SetupWorkspace(d) // important that this is last!
|
||||||
|
|
||||||
u.PlayButton = ui.NewButton("Play", ui.NewLabel(ui.Label{
|
u.PlayButton = ui.NewButton("Play", ui.NewLabel(ui.Label{
|
||||||
|
@ -147,16 +156,31 @@ func (u *EditorUI) Resized(d *Doodle) {
|
||||||
u.Palette.Compute(d.Engine)
|
u.Palette.Compute(d.Engine)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var innerHeight = int32(u.d.height) - u.MenuBar.Size().H - u.StatusBar.Size().H
|
||||||
|
|
||||||
|
// Tool Bar.
|
||||||
|
{
|
||||||
|
u.ToolBar.Configure(ui.Config{
|
||||||
|
Width: toolbarWidth,
|
||||||
|
Height: innerHeight,
|
||||||
|
})
|
||||||
|
u.ToolBar.MoveTo(render.NewPoint(
|
||||||
|
0,
|
||||||
|
u.MenuBar.BoxSize().H,
|
||||||
|
))
|
||||||
|
u.ToolBar.Compute(d.Engine)
|
||||||
|
}
|
||||||
|
|
||||||
// Position the workspace around with the other widgets.
|
// Position the workspace around with the other widgets.
|
||||||
{
|
{
|
||||||
|
|
||||||
frame := u.Workspace
|
frame := u.Workspace
|
||||||
frame.MoveTo(render.NewPoint(
|
frame.MoveTo(render.NewPoint(
|
||||||
0,
|
u.ToolBar.Size().W,
|
||||||
u.MenuBar.Size().H,
|
u.MenuBar.Size().H,
|
||||||
))
|
))
|
||||||
frame.Resize(render.NewRect(
|
frame.Resize(render.NewRect(
|
||||||
int32(d.width)-u.Palette.Size().W,
|
int32(d.width)-u.Palette.Size().W-u.ToolBar.Size().W,
|
||||||
int32(d.height)-u.MenuBar.Size().H-u.StatusBar.Size().H,
|
int32(d.height)-u.MenuBar.Size().H-u.StatusBar.Size().H,
|
||||||
))
|
))
|
||||||
frame.Compute(d.Engine)
|
frame.Compute(d.Engine)
|
||||||
|
@ -227,9 +251,14 @@ func (u *EditorUI) Loop(ev *events.State) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Recompute widgets.
|
// Recompute widgets.
|
||||||
|
// Explanation: if I don't, the UI packing algorithm somehow causes widgets
|
||||||
|
// to creep away every frame and fly right off the screen. For example the
|
||||||
|
// ToolBar's buttons would start packed at the top of the bar but then just
|
||||||
|
// move themselves every frame downward and away.
|
||||||
u.MenuBar.Compute(u.d.Engine)
|
u.MenuBar.Compute(u.d.Engine)
|
||||||
u.StatusBar.Compute(u.d.Engine)
|
u.StatusBar.Compute(u.d.Engine)
|
||||||
u.Palette.Compute(u.d.Engine)
|
u.Palette.Compute(u.d.Engine)
|
||||||
|
u.ToolBar.Compute(u.d.Engine)
|
||||||
|
|
||||||
// Only forward events to the Canvas if the UI hasn't stopped them.
|
// Only forward events to the Canvas if the UI hasn't stopped them.
|
||||||
if !stopPropagation {
|
if !stopPropagation {
|
||||||
|
@ -249,6 +278,7 @@ func (u *EditorUI) Present(e render.Engine) {
|
||||||
u.Palette.Present(e, u.Palette.Point())
|
u.Palette.Present(e, u.Palette.Point())
|
||||||
u.MenuBar.Present(e, u.MenuBar.Point())
|
u.MenuBar.Present(e, u.MenuBar.Point())
|
||||||
u.StatusBar.Present(e, u.StatusBar.Point())
|
u.StatusBar.Present(e, u.StatusBar.Point())
|
||||||
|
u.ToolBar.Present(e, u.ToolBar.Point())
|
||||||
u.Workspace.Present(e, u.Workspace.Point())
|
u.Workspace.Present(e, u.Workspace.Point())
|
||||||
u.PlayButton.Present(e, u.PlayButton.Point())
|
u.PlayButton.Present(e, u.PlayButton.Point())
|
||||||
|
|
||||||
|
|
|
@ -51,35 +51,6 @@ func (u *EditorUI) setupDoodadFrame(e render.Engine, window *ui.Window) (*ui.Fra
|
||||||
|
|
||||||
frame.SetBackground(render.RGBA(0, 153, 255, 153))
|
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 buttons on top of the doodad list.
|
||||||
pager := ui.NewFrame("Doodad Pager")
|
pager := ui.NewFrame("Doodad Pager")
|
||||||
pager.SetBackground(render.RGBA(255, 0, 0, 20)) // TODO: if I don't set a background color,
|
pager.SetBackground(render.RGBA(255, 0, 0, 20)) // TODO: if I don't set a background color,
|
||||||
|
|
|
@ -4,8 +4,6 @@ import (
|
||||||
"git.kirsle.net/apps/doodle/lib/render"
|
"git.kirsle.net/apps/doodle/lib/render"
|
||||||
"git.kirsle.net/apps/doodle/lib/ui"
|
"git.kirsle.net/apps/doodle/lib/ui"
|
||||||
"git.kirsle.net/apps/doodle/pkg/balance"
|
"git.kirsle.net/apps/doodle/pkg/balance"
|
||||||
"git.kirsle.net/apps/doodle/pkg/drawtool"
|
|
||||||
"git.kirsle.net/apps/doodle/pkg/enum"
|
|
||||||
"git.kirsle.net/apps/doodle/pkg/log"
|
"git.kirsle.net/apps/doodle/pkg/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -19,46 +17,6 @@ func (u *EditorUI) SetupPalette(d *Doodle) *ui.Window {
|
||||||
BorderColor: balance.WindowBorder,
|
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 = drawtool.PencilTool
|
|
||||||
u.PaletteTab.Show()
|
|
||||||
u.DoodadTab.Hide()
|
|
||||||
} else {
|
|
||||||
u.Canvas.Tool = drawtool.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.
|
// Doodad frame.
|
||||||
{
|
{
|
||||||
frame, err := u.setupDoodadFrame(d.Engine, window)
|
frame, err := u.setupDoodadFrame(d.Engine, window)
|
||||||
|
|
123
pkg/editor_ui_toolbar.go
Normal file
123
pkg/editor_ui_toolbar.go
Normal file
|
@ -0,0 +1,123 @@
|
||||||
|
package doodle
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.kirsle.net/apps/doodle/lib/render"
|
||||||
|
"git.kirsle.net/apps/doodle/lib/ui"
|
||||||
|
"git.kirsle.net/apps/doodle/pkg/drawtool"
|
||||||
|
"git.kirsle.net/apps/doodle/pkg/log"
|
||||||
|
"git.kirsle.net/apps/doodle/pkg/sprites"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Width of the toolbar frame.
|
||||||
|
var toolbarWidth int32 = 44 // 38px button (32px sprite + borders) + padding
|
||||||
|
var toolbarSpriteSize int32 = 32 // 32x32 sprites.
|
||||||
|
|
||||||
|
// SetupToolbar configures the UI for the Tools panel.
|
||||||
|
func (u *EditorUI) SetupToolbar(d *Doodle) *ui.Frame {
|
||||||
|
frame := ui.NewFrame("Tool Bar")
|
||||||
|
frame.Resize(render.NewRect(toolbarWidth, 100))
|
||||||
|
frame.Configure(ui.Config{
|
||||||
|
BorderSize: 2,
|
||||||
|
BorderStyle: ui.BorderRaised,
|
||||||
|
Background: render.Grey,
|
||||||
|
})
|
||||||
|
|
||||||
|
btnFrame := ui.NewFrame("Tool Buttons")
|
||||||
|
frame.Pack(btnFrame, ui.Pack{
|
||||||
|
Anchor: ui.N,
|
||||||
|
})
|
||||||
|
|
||||||
|
// Buttons.
|
||||||
|
var buttons = []struct {
|
||||||
|
Value string
|
||||||
|
Icon string
|
||||||
|
Click func()
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
Value: drawtool.PencilTool.String(),
|
||||||
|
Icon: "assets/sprites/pencil-tool.png",
|
||||||
|
Click: func() {
|
||||||
|
u.Canvas.Tool = drawtool.PencilTool
|
||||||
|
u.DoodadTab.Hide()
|
||||||
|
u.PaletteTab.Show()
|
||||||
|
d.Flash("Pencil Tool selected.")
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
Value: drawtool.LineTool.String(),
|
||||||
|
Icon: "assets/sprites/line-tool.png",
|
||||||
|
Click: func() {
|
||||||
|
u.Canvas.Tool = drawtool.LineTool
|
||||||
|
u.DoodadTab.Hide()
|
||||||
|
u.PaletteTab.Show()
|
||||||
|
d.Flash("Line Tool selected.")
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
Value: drawtool.RectTool.String(),
|
||||||
|
Icon: "assets/sprites/rect-tool.png",
|
||||||
|
Click: func() {
|
||||||
|
u.Canvas.Tool = drawtool.RectTool
|
||||||
|
u.DoodadTab.Hide()
|
||||||
|
u.PaletteTab.Show()
|
||||||
|
d.Flash("Rectangle Tool selected.")
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
Value: drawtool.ActorTool.String(),
|
||||||
|
Icon: "assets/sprites/actor-tool.png",
|
||||||
|
Click: func() {
|
||||||
|
u.Canvas.Tool = drawtool.ActorTool
|
||||||
|
u.PaletteTab.Hide()
|
||||||
|
u.DoodadTab.Show()
|
||||||
|
d.Flash("Actor Tool selected. Drag a Doodad from the drawer into your level.")
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
Value: drawtool.LinkTool.String(),
|
||||||
|
Icon: "assets/sprites/link-tool.png",
|
||||||
|
Click: func() {
|
||||||
|
u.Canvas.Tool = drawtool.LinkTool
|
||||||
|
u.PaletteTab.Hide()
|
||||||
|
u.DoodadTab.Show()
|
||||||
|
d.Flash("Link Tool selected. Click a doodad in your level to link it to another.")
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, button := range buttons {
|
||||||
|
button := button
|
||||||
|
image, err := sprites.LoadImage(d.Engine, button.Icon)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
btn := ui.NewRadioButton(
|
||||||
|
button.Value,
|
||||||
|
u.activeTool,
|
||||||
|
button.Value,
|
||||||
|
image,
|
||||||
|
)
|
||||||
|
|
||||||
|
var btnSize int32 = btn.BoxThickness(2) + toolbarSpriteSize
|
||||||
|
log.Info("BtnSize: %d", btnSize)
|
||||||
|
btn.Resize(render.NewRect(btnSize, btnSize))
|
||||||
|
|
||||||
|
btn.Handle(ui.Click, func(p render.Point) {
|
||||||
|
button.Click()
|
||||||
|
})
|
||||||
|
u.Supervisor.Add(btn)
|
||||||
|
|
||||||
|
btnFrame.Pack(btn, ui.Pack{
|
||||||
|
Anchor: ui.N,
|
||||||
|
PadY: 2,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
frame.Compute(d.Engine)
|
||||||
|
|
||||||
|
return frame
|
||||||
|
}
|
|
@ -326,7 +326,7 @@ func (s *Shell) Draw(d *Doodle, ev *events.State) error {
|
||||||
// Otherwise, just draw flashed messages.
|
// Otherwise, just draw flashed messages.
|
||||||
valid := false // Did we actually draw any?
|
valid := false // Did we actually draw any?
|
||||||
|
|
||||||
outputY := int32(d.height - (lineHeight * 2))
|
outputY := int32(d.height - (lineHeight * 2) - 16)
|
||||||
for i := len(s.Flashes); i > 0; i-- {
|
for i := len(s.Flashes); i > 0; i-- {
|
||||||
flash := s.Flashes[i-1]
|
flash := s.Flashes[i-1]
|
||||||
if d.ticks >= flash.Expires {
|
if d.ticks >= flash.Expires {
|
||||||
|
@ -342,7 +342,7 @@ func (s *Shell) Draw(d *Doodle, ev *events.State) error {
|
||||||
Shadow: render.Black,
|
Shadow: render.Black,
|
||||||
},
|
},
|
||||||
render.Point{
|
render.Point{
|
||||||
X: balance.ShellPadding,
|
X: balance.ShellPadding + toolbarWidth,
|
||||||
Y: outputY,
|
Y: outputY,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
61
pkg/sprites/sprites.go
Normal file
61
pkg/sprites/sprites.go
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
package sprites
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"errors"
|
||||||
|
"image/png"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"git.kirsle.net/apps/doodle/lib/render"
|
||||||
|
"git.kirsle.net/apps/doodle/lib/ui"
|
||||||
|
"git.kirsle.net/apps/doodle/pkg/bindata"
|
||||||
|
"git.kirsle.net/apps/doodle/pkg/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
// LoadImage loads a sprite as a ui.Image object. It checks Doodle's embedded
|
||||||
|
// bindata, then the filesystem before erroring out.
|
||||||
|
//
|
||||||
|
// NOTE: only .png images supported as of now. TODO
|
||||||
|
func LoadImage(e render.Engine, filename string) (*ui.Image, error) {
|
||||||
|
// Try the bindata first.
|
||||||
|
if data, err := bindata.Asset(filename); err == nil {
|
||||||
|
log.Debug("sprites.LoadImage: %s from bindata", filename)
|
||||||
|
|
||||||
|
img, err := png.Decode(bytes.NewBuffer(data))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
tex, err := e.StoreTexture(filename, img)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return ui.ImageFromTexture(tex), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Then try the file system.
|
||||||
|
if _, err := os.Stat(filename); !os.IsNotExist(err) {
|
||||||
|
log.Debug("sprites.LoadImage: %s from filesystem", filename)
|
||||||
|
|
||||||
|
data, err := ioutil.ReadFile(filename)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
img, err := png.Decode(bytes.NewBuffer(data))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
tex, err := e.StoreTexture(filename, img)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return ui.ImageFromTexture(tex), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, errors.New("no such sprite found")
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user