Skip to content

Commit

Permalink
Update Drag And Drop
Browse files Browse the repository at this point in the history
  • Loading branch information
mcarpenter622 committed Mar 21, 2023
1 parent 6eb2b13 commit c93cdfa
Show file tree
Hide file tree
Showing 9 changed files with 70 additions and 47 deletions.
2 changes: 1 addition & 1 deletion _examples/widget_demos/draganddrop/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ type dndWidget struct {
//
// Inputs:
// - parent - The widget that triggered this Drag and drop event
func (dnd *dndWidget) Create(parent *widget.Widget) (*widget.Container, interface{}) {
func (dnd *dndWidget) Create(parent widget.HasWidget) (*widget.Container, interface{}) {
// For this example we do not need to recreate the Dragged element each time. We can re-use it.
if dnd.dndObj == nil {
// load text font
Expand Down
29 changes: 17 additions & 12 deletions _examples/widget_demos/textinput/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,18 @@ import (

// Game object used by ebiten
type game struct {
ui *ebitenui.UI
ui *ebitenui.UI
standardTextInput *widget.TextInput
}

func main() {

// Ebiten setup
ebiten.SetWindowSize(400, 400)
ebiten.SetWindowTitle("Ebiten UI - TextInput")

game := game{}

// load the font
face, _ := loadFont(20)

Expand All @@ -40,7 +47,7 @@ func main() {
)

// construct a standard textinput widget
standardTextInput := widget.NewTextInput(
game.standardTextInput = widget.NewTextInput(
widget.TextInputOpts.WidgetOpts(
//Set the layout information to center the textbox in the parent
widget.WidgetOpts.LayoutData(widget.RowLayoutData{
Expand Down Expand Up @@ -91,7 +98,7 @@ func main() {
}),
)

rootContainer.AddChild(standardTextInput)
rootContainer.AddChild(game.standardTextInput)

// construct a disabled textinput widget
disabledTextInput := widget.NewTextInput(
Expand Down Expand Up @@ -270,19 +277,11 @@ func main() {
)

rootContainer.AddChild(allCapsTextInput)

// construct the UI
ui := ebitenui.UI{
Container: rootContainer,
}

// Ebiten setup
ebiten.SetWindowSize(400, 400)
ebiten.SetWindowTitle("Ebiten UI - TextInput")

game := game{
ui: &ui,
}
game.ui = &ui

// run Ebiten main loop
err := ebiten.RunGame(&game)
Expand All @@ -306,6 +305,12 @@ func (g *game) Update() error {
if inpututil.IsKeyJustPressed(ebiten.KeyPageDown) {
g.ui.ChangeFocus(ebitenui.FOCUS_NEXT)
}

if inpututil.IsKeyJustPressed(ebiten.KeyEnd) {
if g.ui.GetFocusedWidget() == g.standardTextInput {
fmt.Println("standardTextInput selected")
}
}
g.ui.Update()
return nil
}
Expand Down
12 changes: 10 additions & 2 deletions ui.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ func (u *UI) handleFocusEvent(args interface{}) {

func (u *UI) handleToolTipEvent(args interface{}) {
a := args.(*widget.WidgetToolTipEventArgs)
a.Window.GetContainer().GetWidget().CustomData = "tooltip"
a.Window.Ephemeral = true
if a.Show {
u.addWindow(a.Window)
} else {
Expand All @@ -114,6 +114,7 @@ func (u *UI) handleToolTipEvent(args interface{}) {
func (u *UI) handleDragAndDropEvent(args interface{}) {
a := args.(*widget.WidgetDragAndDropEventArgs)
if a.Show {
a.Window.Ephemeral = true
a.DnD.AvailableDropTargets = u.getDropTargets()
u.addWindow(a.Window)
} else {
Expand Down Expand Up @@ -296,7 +297,7 @@ func (u *UI) removeWindow(w *widget.Window) {
}
if windowIdx != -1 {
for i := len(u.windows) - 1; i >= windowIdx; i-- {
if u.windows[i].GetContainer().GetWidget().CustomData == "tooltip" {
if u.windows[i].Ephemeral {
u.windows = append(u.windows[:i], u.windows[i+1:]...)
}
}
Expand Down Expand Up @@ -326,3 +327,10 @@ func (u *UI) ClearFocus() {
u.focusedWidget.(widget.Focuser).Focus(false)
}
}

func (u *UI) GetFocusedWidget() widget.Focuser {
if u.focusedWidget != nil {
return u.focusedWidget.(widget.Focuser)
}
return nil
}
12 changes: 2 additions & 10 deletions widget/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ func (c *Container) AddChild(child PreferredSizeLocateableWidget) RemoveChildFun
c.children = append(c.children, child)

child.GetWidget().parent = c.widget
child.GetWidget().self = child

child.GetWidget().ContextMenuEvent.AddHandler(func(args interface{}) {
a := args.(*WidgetContextMenuEventArgs)
Expand Down Expand Up @@ -262,16 +263,7 @@ func (c *Container) GetDropTargets() []HasWidget {
result = append(result, c)
}
for _, child := range c.children {
switch v := child.(type) {
case *Container:
result = append(result, v.GetDropTargets()...)
case *FlipBook:
result = append(result, v.GetDropTargets()...)
case *TabBook:
result = append(result, v.container.GetDropTargets()...)
case *TabBookTab:
result = append(result, v.GetDropTargets()...)
case *ScrollContainer:
if v, ok := child.(Dropper); ok {
result = append(result, v.GetDropTargets()...)
}
}
Expand Down
34 changes: 24 additions & 10 deletions widget/dnd.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ type DragAndDropOptions struct {
var DragAndDropOpts DragAndDropOptions

type DragContentsCreater interface {
Create(*Widget) (*Container, interface{})
Create(HasWidget) (*Container, interface{})
}

type DragContentsUpdater interface {
Expand All @@ -53,7 +53,14 @@ type DragContentsUpdater interface {
Update(bool, HasWidget, interface{})
}

type dragAndDropState func(*Widget) (dragAndDropState, bool)
type DragContentsEnder interface {
// arg1 - Drop was successful
// arg2 - Source Widget
// arg3 - DragData
EndDrag(bool, HasWidget, interface{})
}

type dragAndDropState func(HasWidget) (dragAndDropState, bool)

func NewDragAndDrop(opts ...DragAndDropOpt) *DragAndDrop {
d := &DragAndDrop{
Expand Down Expand Up @@ -142,28 +149,28 @@ func (d *DragAndDrop) SetupInputLayer(def input.DeferredSetupInputLayerFunc) {
}
}

func (d *DragAndDrop) Render(parent *Widget, screen *ebiten.Image, def DeferredRenderFunc) {
func (d *DragAndDrop) Render(parent HasWidget, screen *ebiten.Image, def DeferredRenderFunc) {
newState, _ := d.state(parent)
if newState != nil {
d.state = newState
}
}

func (d *DragAndDrop) idleState() dragAndDropState {
return func(parent *Widget) (dragAndDropState, bool) {
return func(parent HasWidget) (dragAndDropState, bool) {
d.dragWidget = nil
if (!input.MouseButtonJustPressed(ebiten.MouseButtonLeft) && !d.dndTriggered) || d.dndStopped {
d.dndStopped = false
if d.window != nil {
parent.FireDragAndDropEvent(d.window, false, d)
parent.GetWidget().FireDragAndDropEvent(d.window, false, d)
d.window = nil
}
return nil, false
}

x, y := input.CursorPosition()
p := image.Point{x, y}
if !p.In(parent.Rect) {
if !p.In(parent.GetWidget().Rect) && !d.dndTriggered {
return nil, false
}

Expand All @@ -172,7 +179,7 @@ func (d *DragAndDrop) idleState() dragAndDropState {
}

func (d *DragAndDrop) dragArmedState(srcX int, srcY int) dragAndDropState {
return func(_ *Widget) (dragAndDropState, bool) {
return func(_ HasWidget) (dragAndDropState, bool) {
if !input.MouseButtonPressed(ebiten.MouseButtonLeft) && !d.dndTriggered {
return d.idleState(), false
}
Expand All @@ -189,7 +196,7 @@ func (d *DragAndDrop) dragArmedState(srcX int, srcY int) dragAndDropState {
}

func (d *DragAndDrop) draggingState(srcX int, srcY int, dragWidget *Container, dragData interface{}, mousePressed bool) dragAndDropState {
return func(parent *Widget) (dragAndDropState, bool) {
return func(parent HasWidget) (dragAndDropState, bool) {
x, y := input.CursorPosition()

d.dndTriggered = false
Expand All @@ -207,7 +214,7 @@ func (d *DragAndDrop) draggingState(srcX int, srcY int, dragWidget *Container, d
WindowOpts.CloseMode(NONE),
WindowOpts.Contents(dragWidget),
)
parent.FireDragAndDropEvent(d.window, true, d)
parent.GetWidget().FireDragAndDropEvent(d.window, true, d)
}

defer func() {
Expand Down Expand Up @@ -257,7 +264,7 @@ func (d *DragAndDrop) draggingState(srcX int, srcY int, dragWidget *Container, d
}

func (d *DragAndDrop) droppingState(srcX int, srcY int, x int, y int, dragData interface{}) dragAndDropState {
return func(parent *Widget) (dragAndDropState, bool) {
return func(parent HasWidget) (dragAndDropState, bool) {
args := &DragAndDropDroppedEventArgs{
Source: parent,
SourceX: srcX,
Expand All @@ -267,15 +274,22 @@ func (d *DragAndDrop) droppingState(srcX int, srcY int, x int, y int, dragData i
Data: dragData,
}
p := image.Point{x, y}
dropSuccessful := false
for _, target := range d.AvailableDropTargets {
if p.In(target.GetWidget().Rect) && target.GetWidget().canDrop(args) {
if target.GetWidget().drop != nil {
args.Target = target
target.GetWidget().drop(args)
dropSuccessful = true
}
break
}
}

if e, ok := d.contentsCreater.(DragContentsEnder); ok {
e.EndDrag(dropSuccessful, parent, dragData)
}

return d.idleState(), false
}
}
Expand Down
12 changes: 2 additions & 10 deletions widget/scrollcontainer.go
Original file line number Diff line number Diff line change
Expand Up @@ -182,16 +182,8 @@ func (s *ScrollContainer) GetDropTargets() []HasWidget {
if s.GetWidget().drop != nil {
result = append(result, s)
}
switch v := s.content.(type) {
case *Container:
result = append(result, v.GetDropTargets()...)
case *FlipBook:
result = append(result, v.GetDropTargets()...)
case *TabBook:
result = append(result, v.container.GetDropTargets()...)
case *TabBookTab:
result = append(result, v.GetDropTargets()...)
case *ScrollContainer:

if v, ok := s.content.(Dropper); ok {
result = append(result, v.GetDropTargets()...)
}

Expand Down
4 changes: 4 additions & 0 deletions widget/tabbook.go
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,10 @@ func (t *TabBook) SetupInputLayer(def input.DeferredSetupInputLayerFunc) {
t.container.SetupInputLayer(def)
}

func (t *TabBook) GetDropTargets() []HasWidget {
return t.container.GetDropTargets()
}

func (t *TabBook) Render(screen *ebiten.Image, def DeferredRenderFunc) {
t.init.Do()

Expand Down
10 changes: 8 additions & 2 deletions widget/widget.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ type Widget struct {
drop DropFunc

parent *Widget
self HasWidget
lastUpdateCursorEntered bool
lastUpdateMouseLeftPressed bool
lastUpdateMouseRightPressed bool
Expand Down Expand Up @@ -103,6 +104,10 @@ type Focuser interface {
TabOrder() int
}

type Dropper interface {
GetDropTargets() []HasWidget
}

// RenderFunc is a function that renders a widget onto screen. def may be called to defer
// additional rendering.
type RenderFunc func(screen *ebiten.Image, def DeferredRenderFunc)
Expand Down Expand Up @@ -182,9 +187,10 @@ type WidgetDragAndDropEventArgs struct { //nolint:golint
}

type DragAndDropDroppedEventArgs struct { //nolint:golint
Source *Widget
Source HasWidget
SourceX int
SourceY int
Target HasWidget
TargetX int
TargetY int
Data interface{}
Expand Down Expand Up @@ -378,7 +384,7 @@ func (w *Widget) Render(screen *ebiten.Image, def DeferredRenderFunc) {
w.ToolTip.Render(w, screen, def)
}
if w.DragAndDrop != nil {
w.DragAndDrop.Render(w, screen, def)
w.DragAndDrop.Render(w.self, screen, def)
}
}

Expand Down
2 changes: 2 additions & 0 deletions widget/window.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ type Window struct {
MinSize *image.Point
MaxSize *image.Point
DrawLayer int
//Used to indicate this window should close if other windows close.
Ephemeral bool

closeMode WindowCloseMode
closeFunc RemoveWindowFunc
Expand Down

0 comments on commit c93cdfa

Please sign in to comment.