diff --git a/pkg/editor_ui.go b/pkg/editor_ui.go index e77937e..c7d8199 100644 --- a/pkg/editor_ui.go +++ b/pkg/editor_ui.go @@ -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. diff --git a/pkg/editor_ui_doodad.go b/pkg/editor_ui_doodad.go index fa09133..f86f6da 100644 --- a/pkg/editor_ui_doodad.go +++ b/pkg/editor_ui_doodad.go @@ -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() diff --git a/pkg/level/actors.go b/pkg/level/actors.go index caeb08d..ffa1ee5 100644 --- a/pkg/level/actors.go +++ b/pkg/level/actors.go @@ -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) +} diff --git a/pkg/uix/canvas.go b/pkg/uix/canvas.go index 557c483..7d22faf 100644 --- a/pkg/uix/canvas.go +++ b/pkg/uix/canvas.go @@ -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 diff --git a/pkg/uix/canvas_editable.go b/pkg/uix/canvas_editable.go index b0656cd..e0cee35 100644 --- a/pkg/uix/canvas_editable.go +++ b/pkg/uix/canvas_editable.go @@ -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 diff --git a/pkg/uix/canvas_link_tool.go b/pkg/uix/canvas_link_tool.go new file mode 100644 index 0000000..e29b074 --- /dev/null +++ b/pkg/uix/canvas_link_tool.go @@ -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 +}