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 }