@@ -39,7 +39,9 @@ public class Dispatcher {
3939 private var registeredEntityMouseUpHandlers = [ EntityMouseUpHandler] ( )
4040 private var registeredEntityMouseClickHandlers = [ EntityMouseClickHandler] ( )
4141 private var registeredEntityMouseDragHandlers = [ EntityMouseDragHandler] ( )
42- private var mostRecentEntityMouseDownHandler : EntityMouseDownHandler ? = nil
42+
43+ // Keep track of the name for EntityMouseClick/EntityMouseDrag events
44+ private var mostRecentEntityNameForMouseClickOrDrag : String ? = nil
4345
4446 // Mouse State
4547 private var previousMouseLocation : Point ? = nil
@@ -148,8 +150,8 @@ public class Dispatcher {
148150 // Raise the event for entities
149151 raiseEntityMouseUpEvent ( globalLocation: globalLocation)
150152
151- // Clear the most recent entity mouseDown handler
152- mostRecentEntityMouseDownHandler = nil
153+ // Clear the most recent name for handling clicks and drags
154+ mostRecentEntityNameForMouseClickOrDrag = nil
153155 }
154156
155157 // ========== WindowMouseUpHandler ==========
@@ -235,8 +237,8 @@ public class Dispatcher {
235237 }
236238
237239 internal func raiseEntityMouseDownEvent( globalLocation: Point ) {
238- // This is easy if there are no registered handlers
239- if !registeredEntityMouseDownHandlers. isEmpty {
240+ // We only need to proceed if we have either EntityMouseDown, EntityMouseClick, or EntityMouseDrag handlers
241+ if !registeredEntityMouseDownHandlers. isEmpty || !registeredEntityMouseClickHandlers . isEmpty || !registeredEntityMouseDragHandlers . isEmpty {
240242 guard let director = director else {
241243 fatalError ( " raiseEntityMouseDownEvent requires a director " )
242244 }
@@ -251,15 +253,39 @@ public class Dispatcher {
251253 // Otherwise, this is likely an error
252254 for entity in frontToBackList {
253255 if entity. hitTest ( globalLocation: globalLocation) {
254- let matchingRegisteredEntities = registeredEntityMouseDownHandlers. filter { $0. name == entity. name}
255- precondition ( matchingRegisteredEntities. count <= 1 , " raiseEntityMouseDownEvent found non-unique entity names for ' \( entity. name) ' " )
256- if matchingRegisteredEntities. count == 1 {
257- let handler = matchingRegisteredEntities [ 0 ]
256+ // Find a candidate for EntityMouseDown
257+ let matchingRegisteredMouseDownEntities = registeredEntityMouseDownHandlers. filter { $0. name == entity. name}
258+ precondition ( matchingRegisteredMouseDownEntities. count <= 1 , " raiseEntityMouseDownEvent found non-unique entity names for ' \( entity. name) for EntityMouseDown' " )
259+
260+ // Find a candidate for EntityMouseClick
261+ let matchingRegisteredMouseClickEntities = registeredEntityMouseClickHandlers. filter { $0. name == entity. name}
262+ precondition ( matchingRegisteredMouseClickEntities. count <= 1 , " raiseEntityMouseDownEvent found non-unique entity names for ' \( entity. name) ' for EntityMouseClick' " )
263+
264+ // Find a candidate for EntityMouseDrag
265+ let matchingRegisteredMouseDragEntities = registeredEntityMouseDragHandlers. filter { $0. name == entity. name}
266+ precondition ( matchingRegisteredMouseDragEntities. count <= 1 , " raiseEntityMouseDownEvent found non-unique entity names for ' \( entity. name) ' for EntityMouseDrag " )
267+
268+ // Track to see if we consume the event so that we can offer a helpful error message
269+ var eventWasConsumed = false
270+
271+ // Handle EntityMouseDown
272+ if matchingRegisteredMouseDownEntities. count == 1 {
273+ let handler = matchingRegisteredMouseDownEntities [ 0 ]
258274 handler. onEntityMouseDown ( globalLocation: globalLocation)
259- mostRecentEntityMouseDownHandler = handler
260- } else {
261- print ( " WARNING: hitTest for entity ' \( entity. name) ' intercepted hit for raiseEntityMouseDown event but is unregistered " )
275+ eventWasConsumed = true
276+ }
277+
278+ // and/or handle EntityMouseDrag or EntityMouseClick
279+ if matchingRegisteredMouseClickEntities. count == 1 || matchingRegisteredMouseDragEntities. count == 1 {
280+ mostRecentEntityNameForMouseClickOrDrag = entity. name
281+ eventWasConsumed = true
282+ }
283+
284+ if !eventWasConsumed {
285+ print ( " WARNING: hitTest for entity ' \( entity. name) ' intercepted hit for raiseEntityMouseDown/Click/Drag event but is unregistered " )
262286 }
287+
288+ // We only search for the top-most entity that has a hit-test that succeeds
263289 break
264290 }
265291 }
@@ -279,8 +305,8 @@ public class Dispatcher {
279305 }
280306
281307 internal func raiseEntityMouseUpEvent( globalLocation: Point ) {
282- // This is easy if there are no registered handlers
283- if !registeredEntityMouseUpHandlers. isEmpty {
308+ // We only need to proceed if we have either EntityMouseUpHandlers or EntityMouseClickHandlers
309+ if !registeredEntityMouseUpHandlers. isEmpty || !registeredEntityMouseClickHandlers . isEmpty {
284310 guard let director = director else {
285311 fatalError ( " raiseEntityMouseUpEvent requires a director " )
286312 }
@@ -295,16 +321,36 @@ public class Dispatcher {
295321 // Otherwise, this is likely an error
296322 for entity in frontToBackList {
297323 if entity. hitTest ( globalLocation: globalLocation) {
298- let matchingRegisteredEntities = registeredEntityMouseUpHandlers. filter { $0. name == entity. name}
299- precondition ( matchingRegisteredEntities. count <= 1 , " raiseEntityMouseUpEvent found non-unique entity names for ' \( entity. name) ' " )
300- if matchingRegisteredEntities. count == 1 {
301- let handler = matchingRegisteredEntities [ 0 ]
324+ // Find a candidate for EntityMouseUp
325+ let matchingRegisteredMouseUpEntities = registeredEntityMouseUpHandlers. filter { $0. name == entity. name}
326+ precondition ( matchingRegisteredMouseUpEntities. count <= 1 , " raiseEntityMouseUpEvent found non-unique entity names for ' \( entity. name) ' for EntityMouseUp " )
327+
328+ // Track to see if we consume the event so that we can offer a helpful error message
329+ var wasEventConsumed = false
330+
331+ // Handle EntityMouseClick
332+ if let mostRecentEntityNameForMouseClickOrDrag = mostRecentEntityNameForMouseClickOrDrag,
333+ entity. name == mostRecentEntityNameForMouseClickOrDrag {
334+ // Find a candiate for EntityMouseClick
335+ let matchingRegisteredMouseClickEntities = registeredEntityMouseClickHandlers. filter { $0. name == entity. name}
336+ precondition ( matchingRegisteredMouseClickEntities. count <= 1 , " raiseEntityMouseUpEvent found non-unique entity names for ' \( entity. name) ' for EntityMouseClick " )
337+
338+ if matchingRegisteredMouseClickEntities. count == 1 {
339+ let handler = matchingRegisteredMouseClickEntities [ 0 ]
340+ handler. onEntityMouseClick ( globalLocation: globalLocation)
341+ wasEventConsumed = true
342+ }
343+ }
344+
345+ // and/or Handle EntityMouseUp
346+ if matchingRegisteredMouseUpEntities. count == 1 {
347+ let handler = matchingRegisteredMouseUpEntities [ 0 ]
302348 handler. onEntityMouseUp ( globalLocation: globalLocation)
349+ wasEventConsumed = true
350+ }
303351
304- // Raise a click event for this entity
305- raiseEntityMouseClickEvent ( globalLocation: globalLocation, entityMouseUpHandler: handler)
306- } else {
307- print ( " WARNING: hitTest for entity ' \( entity. name) ' intercepted hit for raiseEntityMouseUp event but is unregistered " )
352+ if !wasEventConsumed {
353+ print ( " WARNING: hitTest for entity ' \( entity. name) ' intercepted hit for raiseEntityMouseUp/Click event but is unregistered " )
308354 }
309355 break
310356 }
@@ -325,18 +371,11 @@ public class Dispatcher {
325371 registeredEntityMouseClickHandlers. removeAll ( where: { $0. name == handler. name} )
326372 }
327373
374+ /* NOTE: This event is raised by raiseEntityMouseUpEvent
328375 internal func raiseEntityMouseClickEvent(globalLocation:Point, entityMouseUpHandler:EntityMouseUpHandler) {
329- // This is easy if there are no registered handlers or if the upHandler was different than the downHandler
330- if let mostRecentEntityMouseDownHandler = mostRecentEntityMouseDownHandler,
331- !registeredEntityMouseClickHandlers. isEmpty && ( mostRecentEntityMouseDownHandler. name == entityMouseUpHandler. name) {
332- let matchingRegisteredEntities = registeredEntityMouseClickHandlers. filter { $0. name == entityMouseUpHandler. name}
333- precondition ( matchingRegisteredEntities. count <= 1 , " raiseEntityMouseClickEvent found non-unique entity names for ' \( entityMouseUpHandler. name) ' " )
334- if matchingRegisteredEntities. count == 1 {
335- let handler = matchingRegisteredEntities [ 0 ]
336- handler. onEntityMouseClick ( globalLocation: globalLocation)
337- }
338- }
376+
339377 }
378+ */
340379
341380 // ========== EntityMouseDragHandler ==========
342381 public func registerEntityMouseDragHandler( handler: EntityMouseDragHandler ) {
@@ -350,11 +389,11 @@ public class Dispatcher {
350389 }
351390
352391 internal func raiseEntityMouseDragEvent( globalLocation: Point , movement: Point ) {
353- // This is easy if there are no registered handlers or if there's no moseRecentEntityMouseDownHandler
354- if let mostRecentEntityMouseDownHandler = mostRecentEntityMouseDownHandler ,
392+ // This is easy if there is not a mostRecentEntityNameFrMouseClickOrDrag or there are no registered handlers
393+ if let mostRecentEntityNameForMouseClickOrDrag = mostRecentEntityNameForMouseClickOrDrag ,
355394 !registeredEntityMouseDragHandlers. isEmpty {
356- let matchingRegisteredEntities = registeredEntityMouseDragHandlers. filter { $0. name == mostRecentEntityMouseDownHandler . name }
357- precondition ( matchingRegisteredEntities. count <= 1 , " raiseEntityMouseDragEvent found non-unique entity names for ' \( mostRecentEntityMouseDownHandler . name ) ' " )
395+ let matchingRegisteredEntities = registeredEntityMouseDragHandlers. filter { $0. name == mostRecentEntityNameForMouseClickOrDrag }
396+ precondition ( matchingRegisteredEntities. count <= 1 , " raiseEntityMouseDragEvent found non-unique entity names for ' \( mostRecentEntityNameForMouseClickOrDrag ) ' " )
358397 if matchingRegisteredEntities. count == 1 {
359398 let handler = matchingRegisteredEntities [ 0 ]
360399 handler. onEntityMouseDrag ( globalLocation: globalLocation, movement: movement)
0 commit comments