github.com/jmigpin/editor@v1.6.0/util/uiutil/widget/applyevent.go (about)

     1  package widget
     2  
     3  import (
     4  	"image"
     5  
     6  	"github.com/jmigpin/editor/util/uiutil/event"
     7  )
     8  
     9  type ApplyEvent struct {
    10  	drag AEDragState
    11  	cctx CursorContext
    12  }
    13  
    14  func NewApplyEvent(cctx CursorContext) *ApplyEvent {
    15  	ae := &ApplyEvent{cctx: cctx}
    16  	return ae
    17  }
    18  
    19  //----------
    20  
    21  func (ae *ApplyEvent) Apply(node Node, ev interface{}, p image.Point) {
    22  	if !ae.drag.dragging {
    23  		ae.mouseEnterLeave(node, p)
    24  	}
    25  
    26  	switch evt := ev.(type) {
    27  	case nil: // allow running the rest of the function without an event
    28  	case *event.MouseDown:
    29  		ae.depthFirstEv(node, evt, p)
    30  	case *event.MouseMove:
    31  		ae.depthFirstEv(node, evt, p)
    32  	case *event.MouseUp:
    33  		ae.depthFirstEv(node, evt, p)
    34  	case *event.MouseDragStart:
    35  		ae.dragStart(node, evt, p)
    36  		if ae.drag.dragging {
    37  			ae.mouseEnterLeave(node, ae.drag.startEv.Point)
    38  		}
    39  	case *event.MouseDragMove:
    40  		ae.dragMove(evt, p)
    41  	case *event.MouseDragEnd:
    42  		ae.dragEnd(evt, p)
    43  		if !ae.drag.dragging {
    44  			ae.mouseEnterLeave(node, p)
    45  		}
    46  	case *event.KeyDown:
    47  		isLatch := event.ComposeDiacritic(&evt.KeySym, &evt.Rune)
    48  		if !isLatch {
    49  			ae.depthFirstEv(node, evt, p)
    50  		}
    51  	default:
    52  		// ex: event.KeyUp
    53  		ae.depthFirstEv(node, evt, p)
    54  	}
    55  
    56  	ae.setCursor(node, p)
    57  }
    58  
    59  //----------
    60  
    61  func (ae *ApplyEvent) setCursor(node Node, p image.Point) {
    62  	var c event.Cursor
    63  	if ae.drag.dragging {
    64  		c = ae.drag.node.Embed().Cursor
    65  	} else {
    66  		c = ae.treeCursor(node, p)
    67  	}
    68  	ae.cctx.SetCursor(c)
    69  }
    70  
    71  func (ae *ApplyEvent) treeCursor(node Node, p image.Point) event.Cursor {
    72  	ne := node.Embed()
    73  	if !p.In(ne.Bounds) {
    74  		return 0
    75  	}
    76  	var c event.Cursor
    77  	ne.IterateWrappersReverse(func(child Node) bool {
    78  		c = ae.treeCursor(child, p)
    79  		return c == 0 // continue while no cursor was set
    80  	})
    81  	if c == 0 {
    82  		c = ne.Cursor
    83  	}
    84  	return c
    85  }
    86  
    87  //----------
    88  
    89  func (ae *ApplyEvent) mouseEnterLeave(node Node, p image.Point) {
    90  	ae.mouseLeave(node, p) // run leave first
    91  	ae.mouseEnter(node, p)
    92  }
    93  
    94  //----------
    95  
    96  func (ae *ApplyEvent) mouseEnter(node Node, p image.Point) event.Handled {
    97  	ne := node.Embed()
    98  
    99  	if !p.In(ne.Bounds) {
   100  		return false
   101  	}
   102  
   103  	// execute on childs
   104  	h := event.Handled(false)
   105  	// later childs are drawn over previous ones, run loop backwards
   106  	ne.IterateWrappersReverse(func(c Node) bool {
   107  		h = ae.mouseEnter(c, p)
   108  		return h == false // continue while not handled
   109  	})
   110  
   111  	// execute on node
   112  	if !h {
   113  		if !ne.HasAnyMarks(MarkPointerInside) {
   114  			ne.AddMarks(MarkPointerInside)
   115  			ev2 := &event.MouseEnter{}
   116  			h = ae.runEv(node, ev2, p)
   117  		}
   118  	}
   119  
   120  	if ne.HasAnyMarks(MarkInBoundsHandlesEvent) {
   121  		h = true
   122  	}
   123  
   124  	return h
   125  }
   126  
   127  //----------
   128  
   129  func (ae *ApplyEvent) mouseLeave(node Node, p image.Point) event.Handled {
   130  	ne := node.Embed()
   131  
   132  	// execute on childs
   133  	h := event.Handled(false)
   134  	// later childs are drawn over previous ones, run loop backwards
   135  	ne.IterateWrappersReverse(func(c Node) bool {
   136  		h = ae.mouseLeave(c, p)
   137  		return h == false // continue while not handled
   138  	})
   139  
   140  	// execute on node
   141  	if !h {
   142  		if ne.HasAnyMarks(MarkPointerInside) && !p.In(ne.Bounds) {
   143  			ne.RemoveMarks(MarkPointerInside)
   144  			ev2 := &event.MouseLeave{}
   145  			h = ae.runEv(node, ev2, p)
   146  		}
   147  	}
   148  
   149  	return h
   150  }
   151  
   152  //----------
   153  
   154  func (ae *ApplyEvent) dragStart(node Node, ev *event.MouseDragStart, p image.Point) {
   155  	if ae.drag.dragging {
   156  		return
   157  	}
   158  	p = ev.Point // use the starting point, not the current point
   159  	ae.findDragNode2(node, ev, p)
   160  }
   161  
   162  // Depth first, reverse order.
   163  func (ae *ApplyEvent) findDragNode2(node Node, ev *event.MouseDragStart, p image.Point) bool {
   164  	if !p.In(node.Embed().Bounds) {
   165  		return false
   166  	}
   167  
   168  	// execute on childs
   169  	found := false
   170  	node.Embed().IterateWrappersReverse(func(c Node) bool {
   171  		found = ae.findDragNode2(c, ev, p)
   172  		return !found // continue while not found
   173  	})
   174  
   175  	if !found {
   176  		// deepest node
   177  		canDrag := !node.Embed().HasAnyMarks(MarkNotDraggable)
   178  		if canDrag {
   179  			ae.drag.dragging = true
   180  			ae.drag.startEv = ev
   181  			ae.drag.node = node
   182  			ae.runEv(ae.drag.node, ev, p)
   183  			return true
   184  		}
   185  	}
   186  
   187  	return found
   188  }
   189  
   190  //----------
   191  
   192  func (ae *ApplyEvent) dragMove(ev *event.MouseDragMove, p image.Point) {
   193  	if !ae.drag.dragging {
   194  		return
   195  	}
   196  	ae.runEv(ae.drag.node, ev, p)
   197  }
   198  
   199  //----------
   200  
   201  func (ae *ApplyEvent) dragEnd(ev *event.MouseDragEnd, p image.Point) {
   202  	if !ae.drag.dragging {
   203  		return
   204  	}
   205  	if ev.Button != ae.drag.startEv.Button {
   206  		return
   207  	}
   208  	ae.runEv(ae.drag.node, ev, p)
   209  	ae.drag = AEDragState{}
   210  }
   211  
   212  //----------
   213  
   214  func (ae *ApplyEvent) depthFirstEv(node Node, ev interface{}, p image.Point) event.Handled {
   215  	if !p.In(node.Embed().Bounds) {
   216  		return false
   217  	}
   218  
   219  	// execute on childs
   220  	h := event.Handled(false)
   221  	// later childs are drawn over previous ones, run loop backwards
   222  	node.Embed().IterateWrappersReverse(func(c Node) bool {
   223  		h = ae.depthFirstEv(c, ev, p)
   224  		return h == false // continue while not handled
   225  	})
   226  
   227  	// execute on node
   228  	if !h {
   229  		h = ae.runEv(node, ev, p)
   230  	}
   231  
   232  	if node.Embed().HasAnyMarks(MarkInBoundsHandlesEvent) {
   233  		h = true
   234  	}
   235  
   236  	return h
   237  }
   238  
   239  //----------
   240  
   241  func (ae *ApplyEvent) runEv(node Node, ev interface{}, p image.Point) event.Handled {
   242  	return node.OnInputEvent(ev, p)
   243  }
   244  
   245  //----------
   246  
   247  type AEDragState struct {
   248  	dragging bool
   249  	startEv  *event.MouseDragStart
   250  	node     Node
   251  }