Link Tool UX

* On the Doodads tab is the Link button to enter the Link Tool.
* Click Link, then click the 1st doodad on the level, then click the 2nd
  doodad to complete the link.
* The actors struct in the Level holds the link IDs for each actor.
physics
Noah 2019-06-23 16:15:09 -07:00
parent b06c52a705
commit 87416f9740
6 changed files with 102 additions and 4 deletions

View File

@ -267,6 +267,17 @@ func (u *EditorUI) SetupCanvas(d *Doodle) *uix.Canvas {
u.startDragActor(doodad)
}
// A link event to connect two actors together.
drawing.OnLinkActors = func(a, b *level.Actor) {
d.Flash("Link %s and %s", a.Filename, b.Filename)
idA, idB := a.ID(), b.ID()
a.AddLink(idB)
b.AddLink(idA)
// Reset the Link tool.
drawing.Tool = uix.ActorTool
}
// Set up the drop handler for draggable doodads.
// NOTE: The drag event begins at editor_ui_doodad.go when configuring the
// Doodad Palette buttons.

View File

@ -57,7 +57,7 @@ func (u *EditorUI) setupDoodadFrame(e render.Engine, window *ui.Window) (*ui.Fra
Background: render.Grey,
BorderSize: 2,
BorderStyle: ui.BorderRaised,
Height: 20,
Height: 24,
})
{
// Link button.
@ -65,7 +65,8 @@ func (u *EditorUI) setupDoodadFrame(e render.Engine, window *ui.Window) (*ui.Fra
Text: "Link Doodads",
}))
linkButton.Handle(ui.Click, func(p render.Point) {
u.d.Flash("Hello world")
u.Canvas.LinkStart()
u.d.Flash("Click on the first Doodad to link to another one.")
})
u.Supervisor.Add(linkButton)
@ -81,6 +82,9 @@ func (u *EditorUI) setupDoodadFrame(e render.Engine, window *ui.Window) (*ui.Fra
// 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: "<",
@ -109,6 +113,7 @@ func (u *EditorUI) setupDoodadFrame(e render.Engine, window *ui.Window) (*ui.Fra
frame.Pack(pager, ui.Pack{
Anchor: ui.N,
Fill: true,
PadY: 5,
})
doodadsAvailable, err := doodads.ListDoodads()

View File

@ -39,9 +39,21 @@ type Actor struct {
id string // NOTE: read only, use ID() to access.
Filename string `json:"filename"` // like "exit.doodad"
Point render.Point `json:"point"`
Links []string `json:"links,omitempty"` // IDs of linked actors
}
// ID returns the actor's ID.
func (a *Actor) ID() string {
return a.id
}
// AddLink adds a linked Actor to an Actor. Add the linked actor by its ID.
func (a *Actor) AddLink(id string) {
// Don't add a duplicate ID to the links array.
for _, exist := range a.Links {
if exist == id {
return
}
}
a.Links = append(a.Links, id)
}

View File

@ -65,9 +65,11 @@ type Canvas struct {
OnDeleteActors func([]*level.Actor)
OnDragStart func(filename string)
// -- WHEN Canvas.Tool is "Link" --
// When the Canvas wants to link two actors together. Arguments are the IDs
// of the two actors.
OnLinkActors func(a, b string)
OnLinkActors func(a, b *level.Actor)
linkFirst *Actor
// Tracking pixels while editing. TODO: get rid of pixelHistory?
pixelHistory []*level.Pixel

View File

@ -58,7 +58,6 @@ func (w *Canvas) loopEditable(ev *events.State) error {
case ActorTool:
// See if any of the actors are below the mouse cursor.
var WP = w.WorldIndexAt(cursor)
_ = WP
var deleteActors = []*level.Actor{}
for _, actor := range w.actors {
@ -100,6 +99,47 @@ func (w *Canvas) loopEditable(ev *events.State) error {
if len(deleteActors) > 0 && w.OnDeleteActors != nil {
w.OnDeleteActors(deleteActors)
}
case LinkTool:
// See if any of the actors are below the mouse cursor.
var WP = w.WorldIndexAt(cursor)
for _, actor := range w.actors {
// Permanently color the actor if it's the current subject of the
// Link Tool (after 1st click, until 2nd click of other actor)
if w.linkFirst == actor {
actor.Canvas.Configure(ui.Config{
Background: render.RGBA(255, 153, 255, 153),
})
continue
}
box := render.Rect{
X: actor.Actor.Point.X - P.X - w.Scroll.X,
Y: actor.Actor.Point.Y - P.Y - w.Scroll.Y,
W: actor.Canvas.Size().W,
H: actor.Canvas.Size().H,
}
if WP.Inside(box) {
actor.Canvas.Configure(ui.Config{
BorderSize: 1,
BorderColor: render.RGBA(255, 153, 255, 255),
BorderStyle: ui.BorderSolid,
Background: render.White, // TODO: cuz the border draws a bgcolor
})
// Click handler to start linking this actor.
if ev.Button1.Read() {
if err := w.LinkAdd(actor); err != nil {
return err
}
break
}
} else {
actor.Canvas.SetBorderSize(0)
actor.Canvas.SetBackground(render.RGBA(0, 0, 1, 0)) // TODO
}
}
}
return nil

View File

@ -0,0 +1,28 @@
package uix
import "errors"
// LinkStart initializes the Link tool.
func (w *Canvas) LinkStart() {
w.Tool = LinkTool
w.linkFirst = nil
}
// LinkAdd adds an actor to be linked in the Link tool.
func (w *Canvas) LinkAdd(a *Actor) error {
if w.linkFirst == nil {
// First click, hold onto this actor.
w.linkFirst = a
} else {
// Second click, call the OnLinkActors handler with the two actors.
if w.OnLinkActors != nil {
w.OnLinkActors(w.linkFirst.Actor, a.Actor)
} else {
return errors.New("Canvas.LinkAdd: no OnLinkActors handler is ready")
}
// Reset the link state.
w.linkFirst = nil
}
return nil
}