mouseEventController.lua 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480
  1. --[[
  2. readme:has a special mouse event in mouse right button event
  3. It was used to on the platform expeat window replacing check root node
  4. You can return -1 to continue propagation on the mouse button event but moving.
  5. mouse move event params
  6. param = {
  7. enter = function, --on enter callback
  8. leave = function, --on leave callback
  9. inside = function, -- inside moving callback
  10. }
  11. mouse button event params
  12. param = {
  13. down_r = function, --right button down 函数会传入 touchPos
  14. up_r = function, --right button up 函数会传入 touchPos
  15. special_r = function, --special : imitate left button down on mobile 函数会传入 touchPos
  16. double_l = function, --left button double click 函数会传入 touchPos
  17. moving = function, -- on moving 函数会传入 touchPos
  18. scroll = function -- on scroll moving 函数会传入 scrollOff = { x = 0, y = 1} x值目前没变动 Y 值 大于零 向后滚动 小于零 向前
  19. swallow = number, > 0 stopPropagation
  20. checkIsVisible = bool,
  21. CheckTouchEnable = bool,
  22. moveTouch = bool --该参数目前只用于移动
  23. }
  24. **self.registerAllChilderMouseRButtonEvent was only used to add swallow mouse event.
  25. It will let all children on the father node to get mouse event.
  26. ]]
  27. local mouseEventController = class("mouseEventController")
  28. function mouseEventController:ctor()
  29. self.onDoubleEvent = false
  30. self.doubleClickDelayTime = 0.3
  31. self.lastInsideNodeParam = nil
  32. self.mouseMoveOffPos = nil
  33. end
  34. function mouseEventController:destory()
  35. if mouseEventController.instance then
  36. mouseEventController.instance = nil
  37. end
  38. end
  39. function mouseEventController:Inst()
  40. if not mouseEventController.instance then
  41. mouseEventController.instance = mouseEventController.new()
  42. end
  43. return mouseEventController.instance
  44. end
  45. function mouseEventController:GetNodeLastState(node)
  46. return node._nodeState or false
  47. end
  48. function mouseEventController:SetNodeLastState(node, bool)
  49. if not tolua.isnull(node) then
  50. node._nodeState = bool
  51. end
  52. end
  53. function mouseEventController:SetLastInsideNode( node, param )
  54. self.lastInsideNodeParam = nil
  55. if node and param and not tolua.isnull(node) then
  56. self.lastInsideNodeParam = {
  57. sideNode = node,
  58. param = param
  59. }
  60. end
  61. end
  62. function mouseEventController:ClearLastInsideNode(node)
  63. local lastData = self.lastInsideNodeParam
  64. if lastData and lastData.sideNode and not tolua.isnull(lastData.sideNode) then
  65. self:SetNodeLastState(lastData.sideNode, false)
  66. end
  67. self.lastInsideNodeParam = nil
  68. end
  69. function mouseEventController:GetLastInsideNode()
  70. local lastData = self.lastInsideNodeParam
  71. if lastData and lastData.sideNode and not tolua.isnull(lastData.sideNode) then
  72. return lastData.sideNode
  73. end
  74. return nil
  75. end
  76. function mouseEventController:LeaveLastNode( )
  77. local lastData = self.lastInsideNodeParam
  78. if lastData and lastData.sideNode and not tolua.isnull(lastData.sideNode) then
  79. self:SetNodeLastState(lastData.sideNode, false)
  80. local param = lastData.param
  81. if not param or not next(param) then
  82. return
  83. end
  84. local leaveCallBack = param.leave
  85. if leaveCallBack then
  86. leaveCallBack()
  87. end
  88. end
  89. end
  90. function mouseEventController:OnMouseMoveEvent( pos )
  91. if self.onDoubleEvent then
  92. if not self.mouseMoveOffPos then
  93. self.mouseMoveOffPos = pos
  94. else
  95. local offPos = math.pow((self.mouseMoveOffPos.x - pos.x), 2) + math.pow((self.mouseMoveOffPos.y - pos.y), 2)
  96. if offPos > 200 then
  97. self.onDoubleEvent = false
  98. self.mouseMoveOffPos = nil
  99. end
  100. end
  101. else
  102. self.mouseMoveOffPos = nil
  103. end
  104. end
  105. function mouseEventController:registerMouseMoveEvent(node, param)
  106. local eventCallbacks = param or {}
  107. if not eventCallbacks.show then
  108. if not global.MouseEventOpen then
  109. return false
  110. end
  111. end
  112. local enterCallback = eventCallbacks.enter
  113. local leaveCallback = eventCallbacks.leave
  114. local insideCallback = eventCallbacks.inside
  115. local checkIsVisible = eventCallbacks.checkIsVisible
  116. local listener = cc.EventListenerMouse:create()
  117. local eventDispatcher = cc.Director:getInstance():getEventDispatcher()
  118. local function onMouseMoved(sender)
  119. if checkIsVisible and (not node:isVisible() or (node:getParent() and not node:getParent():isVisible())) then
  120. return
  121. end
  122. local lastTimeNodeState = self:GetNodeLastState(node)
  123. local mousePosX = sender:getCursorX()
  124. local mousePosY = sender:getCursorY()
  125. local touchPos = {
  126. x = mousePosX,
  127. y = mousePosY
  128. }
  129. self:OnMouseMoveEvent( touchPos )
  130. local isInSide = self:checkNodePos(node, touchPos)
  131. if lastTimeNodeState and isInSide then --一直在内部
  132. if insideCallback then
  133. insideCallback()
  134. end
  135. self:SetNodeLastState(node, true)
  136. sender:stopPropagation()
  137. elseif lastTimeNodeState and not isInSide then --移出
  138. if leaveCallback then
  139. leaveCallback()
  140. end
  141. self:SetNodeLastState(node, false)
  142. elseif not lastTimeNodeState and isInSide then --移入
  143. self:LeaveLastNode()
  144. if enterCallback then
  145. enterCallback(touchPos)
  146. end
  147. self:SetNodeLastState(node, true)
  148. self:SetLastInsideNode(node, param)
  149. sender:stopPropagation()
  150. end
  151. end
  152. listener:registerScriptHandler( onMouseMoved, cc.Handler.EVENT_MOUSE_MOVE )
  153. eventDispatcher:addEventListenerWithSceneGraphPriority( listener, node )
  154. end
  155. function mouseEventController:checkNodePos(node, touchPos)
  156. if tolua.isnull(node) or not next(touchPos) then
  157. return false
  158. end
  159. local worldPos = node:getWorldPosition()
  160. local anchor = node:getAnchorPoint()
  161. local content = node:getContentSize()
  162. local scaleX = node:getScaleX()
  163. local scaleY = node:getScaleY()
  164. local leftPos = worldPos.x - anchor.x * content.width * scaleX
  165. local rightPos = worldPos.x + (1 - anchor.x) * content.width * scaleX
  166. local bottomPos = worldPos.y - anchor.y * content.height * scaleY
  167. local topPos = worldPos.y + (1 - anchor.y) * content.height * scaleY
  168. local isInSide = false
  169. if touchPos.x > leftPos and touchPos.x < rightPos and
  170. touchPos.y > bottomPos and touchPos.y < topPos then
  171. isInSide = true
  172. end
  173. return isInSide
  174. end
  175. function mouseEventController:CancelMove(sender, isStop, isReturn)
  176. local ItemMoveProxy = global.Facade:retrieveProxy(global.ProxyTable.ItemMoveProxy)
  177. local state = ItemMoveProxy:GetMovingItemState()
  178. if state then
  179. global.Facade:sendNotification(global.NoticeTable.Layer_Moved_Cancel)
  180. if isStop then
  181. sender:stopPropagation()
  182. end
  183. if isReturn then
  184. return false
  185. end
  186. end
  187. end
  188. function mouseEventController:registerMouseButtonEvent(node, param)
  189. local eventCallbacks = param or {}
  190. local call_down_r = eventCallbacks.down_r
  191. local call_up_r = eventCallbacks.up_r
  192. local call_special_r = eventCallbacks.special_r
  193. local call_double_l = eventCallbacks.double_l
  194. local call_moving = eventCallbacks.moving
  195. local call_scrolling = eventCallbacks.scroll
  196. local swallowMouse = eventCallbacks.swallow or 1
  197. local checkIsVisible = eventCallbacks.checkIsVisible
  198. local CheckTouchEnable = eventCallbacks.checkTouchEnable
  199. local checkSwallowTouches = eventCallbacks.checkSwallowTouches
  200. local checkVisibleLevel = eventCallbacks.checkVisibleLevel or 2
  201. local listener = cc.EventListenerMouse:create()
  202. local eventDispatcher = cc.Director:getInstance():getEventDispatcher()
  203. local isNeedNodeParam = false
  204. if not call_scrolling and node.RegisterWin32MouseMoveScrollCall then --GoodsItem注册的鼠标滚动回调
  205. call_scrolling = node.RegisterWin32MouseMoveScrollCall
  206. isNeedNodeParam = true
  207. end
  208. local function checkVisibleParent(node, level)
  209. local maxTimes = math.min(level, 6)
  210. local times = 2
  211. local parent = node:getParent()
  212. local visible = true
  213. local function checkParent(childNode)
  214. if times >= maxTimes then
  215. visible = true
  216. return
  217. end
  218. if not tolua.isnull(childNode) then
  219. local parent = childNode:getParent()
  220. if not tolua.isnull(parent) then
  221. if not parent:isVisible() then
  222. visible = false
  223. return
  224. end
  225. times = times + 1
  226. checkParent(parent)
  227. end
  228. end
  229. end
  230. checkParent(parent)
  231. return visible
  232. end
  233. local function onMouseDown(sender)
  234. if checkIsVisible and (not node:isVisible() or (node:getParent() and not node:getParent():isVisible())) then
  235. return
  236. end
  237. if checkIsVisible and checkVisibleLevel and checkVisibleLevel > 2 and not checkVisibleParent(node, checkVisibleLevel) then
  238. return
  239. end
  240. if CheckTouchEnable and not node:isTouchEnabled() then
  241. return
  242. end
  243. if checkSwallowTouches and not node:isSwallowTouches() then
  244. return
  245. end
  246. local mousePosX = sender:getCursorX()
  247. local mousePosY = sender:getCursorY()
  248. local touchPos = {
  249. x = mousePosX,
  250. y = mousePosY
  251. }
  252. local isInSide = self:checkNodePos(node, touchPos)
  253. local button = sender:getMouseButton()
  254. if button == cc.MouseButton.BUTTON_RIGHT then
  255. if sender.specialRight then
  256. if isInSide then
  257. if call_special_r then
  258. swallowMouse = call_special_r( touchPos ) or 1
  259. else
  260. self:CancelMove(sender, true, false)
  261. end
  262. if swallowMouse > 0 then
  263. sender:stopPropagation()
  264. end
  265. end
  266. return
  267. end
  268. self:CancelMove(sender, true, true)
  269. if isInSide then
  270. if call_down_r then
  271. if eventCallbacks.moveTouch then
  272. swallowMouse = call_down_r( touchPos ) or 1
  273. else
  274. swallowMouse = call_down_r() or 1
  275. end
  276. end
  277. if swallowMouse > 0 then
  278. sender:stopPropagation()
  279. end
  280. end
  281. else
  282. if isInSide then
  283. if call_double_l then
  284. if not node._onDoubleClickEvent then
  285. node._onDoubleClickEvent = true
  286. self.onDoubleEvent = true
  287. -- 记录单击触发
  288. node._clickDelayHandler =
  289. PerformWithDelayGlobal(
  290. function()
  291. if call_special_r then
  292. swallowMouse = call_special_r( touchPos ) or 1
  293. end
  294. node._onDoubleClickEvent = nil
  295. self.onDoubleEvent = false
  296. end,
  297. self.doubleClickDelayTime
  298. )
  299. else
  300. if node._clickDelayHandler then
  301. UnSchedule(node._clickDelayHandler)
  302. node._clickDelayHandler = nil
  303. end
  304. self:CancelMove(sender, false, false)
  305. swallowMouse = call_double_l( touchPos ) or 1
  306. node._onDoubleClickEvent = nil
  307. self.onDoubleEvent = false
  308. end
  309. elseif call_special_r then
  310. if not self.onDoubleEvent then
  311. swallowMouse = call_special_r( touchPos ) or 1
  312. end
  313. end
  314. if swallowMouse > 0 then
  315. sender:stopPropagation()
  316. end
  317. end
  318. end
  319. end
  320. local function onMouseUp(sender)
  321. global.Facade:sendNotification(global.NoticeTable.Layer_RTouch_State_Change, false)
  322. if checkIsVisible and (not node:isVisible() or (node:getParent() and not node:getParent():isVisible())) then
  323. return
  324. end
  325. if CheckTouchEnable and not node:isTouchEnabled() then
  326. return
  327. end
  328. if checkSwallowTouches and not node:isSwallowTouches() then
  329. return
  330. end
  331. local button = sender:getMouseButton()
  332. if button == cc.MouseButton.BUTTON_RIGHT then
  333. local mousePosX = sender:getCursorX()
  334. local mousePosY = sender:getCursorY()
  335. local touchPos = {
  336. x = mousePosX,
  337. y = mousePosY
  338. }
  339. local isInSide = self:checkNodePos(node, touchPos)
  340. if isInSide then
  341. if call_up_r then
  342. swallowMouse = call_up_r() or 1
  343. end
  344. if swallowMouse > 0 then
  345. sender:stopPropagation()
  346. end
  347. end
  348. end
  349. end
  350. if eventCallbacks.moveTouch then --only moving
  351. local function onMouseMoved(sender)
  352. if eventCallbacks.moveTouch then
  353. local mousePosX = sender:getCursorX()
  354. local mousePosY = sender:getCursorY()
  355. if call_moving then
  356. call_moving({x = mousePosX, y = mousePosY})
  357. end
  358. end
  359. end
  360. listener:registerScriptHandler( onMouseMoved, cc.Handler.EVENT_MOUSE_MOVE )
  361. end
  362. if call_scrolling then
  363. local function omMouseScroll(sender)
  364. local mousePosX = sender:getCursorX()
  365. local mousePosY = sender:getCursorY()
  366. local touchPos = {
  367. x = mousePosX,
  368. y = mousePosY
  369. }
  370. local isInSide = self:checkNodePos(node, touchPos)
  371. if isInSide then
  372. local scrollX = sender:getScrollX()
  373. local scrollY = sender:getScrollY()
  374. local scrollData = {
  375. x = scrollX,
  376. y = scrollY
  377. }
  378. if isNeedNodeParam then
  379. call_scrolling(node,scrollData)
  380. else
  381. call_scrolling(scrollData)
  382. end
  383. end
  384. end
  385. listener:registerScriptHandler( omMouseScroll, cc.Handler.EVENT_MOUSE_SCROLL)
  386. end
  387. if node and node.isSignMouListner then
  388. if node.signRegisterMouseListner then
  389. eventDispatcher:removeEventListener( node.signRegisterMouseListner )
  390. node.signRegisterMouseListner = nil
  391. end
  392. node.signRegisterMouseListner = listener
  393. end
  394. listener:registerScriptHandler( onMouseDown, cc.Handler.EVENT_MOUSE_DOWN )
  395. listener:registerScriptHandler( onMouseUp, cc.Handler.EVENT_MOUSE_UP )
  396. eventDispatcher:addEventListenerWithSceneGraphPriority( listener, node )
  397. end
  398. -- readme: 本方法只适用于添加吞噬 不建议添加回调
  399. function mouseEventController:registerAllChilderMouseRButtonEvent(node, param)
  400. if not node or tolua.isnull(node) then
  401. return
  402. end
  403. local allNode = {}
  404. local function addToTable(Widget)
  405. if tolua.iskindof(Widget,"ccui.Widget")then
  406. table.insert(allNode, Widget)
  407. end
  408. end
  409. addToTable(node)
  410. local function checkChild(parent)
  411. local childCount = parent:getChildrenCount()
  412. if childCount > 0 then
  413. local childern = parent:getChildren()
  414. for _,child in pairs(childern) do
  415. addToTable(child)
  416. checkChild(child)
  417. end
  418. end
  419. end
  420. checkChild(node)
  421. for k,v in pairs(allNode) do
  422. if not v._noAutoRegisterMouseSwollow then
  423. self:registerMouseButtonEvent( v ,param )
  424. end
  425. end
  426. end
  427. return mouseEventController