InterfaceEventDispatcher.cpp 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. /*
  2. * CGuiHandler.cpp, part of VCMI engine
  3. *
  4. * Authors: listed in file AUTHORS in main folder
  5. *
  6. * License: GNU General Public License v2.0 or later
  7. * Full text of license available in license.txt file, in main folder
  8. *
  9. */
  10. #include "StdInc.h"
  11. #include "InterfaceEventDispatcher.h"
  12. #include "CIntObject.h"
  13. #include "CGuiHandler.h"
  14. #include "FramerateManager.h"
  15. void InterfaceEventDispatcher::processList(const ui16 mask, const ui16 flag, CIntObjectList *lst, std::function<void (CIntObjectList *)> cb)
  16. {
  17. if (mask & flag)
  18. cb(lst);
  19. }
  20. void InterfaceEventDispatcher::processLists(ui16 activityFlag, std::function<void (CIntObjectList *)> cb)
  21. {
  22. processList(AEventsReceiver::LCLICK,activityFlag,&lclickable,cb);
  23. processList(AEventsReceiver::RCLICK,activityFlag,&rclickable,cb);
  24. processList(AEventsReceiver::MCLICK,activityFlag,&mclickable,cb);
  25. processList(AEventsReceiver::HOVER,activityFlag,&hoverable,cb);
  26. processList(AEventsReceiver::MOVE,activityFlag,&motioninterested,cb);
  27. processList(AEventsReceiver::KEYBOARD,activityFlag,&keyinterested,cb);
  28. processList(AEventsReceiver::TIME,activityFlag,&timeinterested,cb);
  29. processList(AEventsReceiver::WHEEL,activityFlag,&wheelInterested,cb);
  30. processList(AEventsReceiver::DOUBLECLICK,activityFlag,&doubleClickInterested,cb);
  31. processList(AEventsReceiver::TEXTINPUT,activityFlag,&textInterested,cb);
  32. }
  33. void InterfaceEventDispatcher::handleElementActivate(AEventsReceiver * elem, ui16 activityFlag)
  34. {
  35. processLists(activityFlag,[&](CIntObjectList * lst){
  36. lst->push_front(elem);
  37. });
  38. elem->activeState |= activityFlag;
  39. }
  40. void InterfaceEventDispatcher::handleElementDeActivate(AEventsReceiver * elem, ui16 activityFlag)
  41. {
  42. processLists(activityFlag,[&](CIntObjectList * lst){
  43. auto hlp = std::find(lst->begin(),lst->end(),elem);
  44. assert(hlp != lst->end());
  45. lst->erase(hlp);
  46. });
  47. elem->activeState &= ~activityFlag;
  48. }
  49. void InterfaceEventDispatcher::updateTime(uint32_t msPassed)
  50. {
  51. CIntObjectList hlp = timeinterested;
  52. for (auto & elem : hlp)
  53. {
  54. if(!vstd::contains(timeinterested,elem)) continue;
  55. (elem)->tick(msPassed);
  56. }
  57. }
  58. void InterfaceEventDispatcher::dispatchShortcutPressed(const std::vector<EShortcut> & shortcutsVector)
  59. {
  60. bool keysCaptured = false;
  61. for(auto i = keyinterested.begin(); i != keyinterested.end() && GH.continueEventHandling; i++)
  62. for(EShortcut shortcut : shortcutsVector)
  63. if((*i)->captureThisKey(shortcut))
  64. keysCaptured = true;
  65. CIntObjectList miCopy = keyinterested;
  66. for(auto i = miCopy.begin(); i != miCopy.end() && GH.continueEventHandling; i++)
  67. for(EShortcut shortcut : shortcutsVector)
  68. if(vstd::contains(keyinterested, *i) && (!keysCaptured || (*i)->captureThisKey(shortcut)))
  69. (**i).keyPressed(shortcut);
  70. }
  71. void InterfaceEventDispatcher::dispatchShortcutReleased(const std::vector<EShortcut> & shortcutsVector)
  72. {
  73. bool keysCaptured = false;
  74. for(auto i = keyinterested.begin(); i != keyinterested.end() && GH.continueEventHandling; i++)
  75. for(EShortcut shortcut : shortcutsVector)
  76. if((*i)->captureThisKey(shortcut))
  77. keysCaptured = true;
  78. CIntObjectList miCopy = keyinterested;
  79. for(auto i = miCopy.begin(); i != miCopy.end() && GH.continueEventHandling; i++)
  80. for(EShortcut shortcut : shortcutsVector)
  81. if(vstd::contains(keyinterested, *i) && (!keysCaptured || (*i)->captureThisKey(shortcut)))
  82. (**i).keyReleased(shortcut);
  83. }
  84. InterfaceEventDispatcher::CIntObjectList & InterfaceEventDispatcher::getListForMouseButton(MouseButton button)
  85. {
  86. switch (button)
  87. {
  88. case MouseButton::LEFT:
  89. return lclickable;
  90. case MouseButton::RIGHT:
  91. return rclickable;
  92. case MouseButton::MIDDLE:
  93. return mclickable;
  94. }
  95. throw std::runtime_error("Invalid mouse button in getListForMouseButton");
  96. }
  97. void InterfaceEventDispatcher::dispatchMouseButtonPressed(const MouseButton & button, const Point & position)
  98. {
  99. // if (button == MouseButton::LEFT)
  100. // {
  101. // auto doubleClicked = false;
  102. // if(lastClick == getCursorPosition() && (SDL_GetTicks() - lastClickTime) < 300)
  103. // {
  104. // std::list<CIntObject*> hlp = doubleClickInterested;
  105. // for(auto i = hlp.begin(); i != hlp.end() && continueEventHandling; i++)
  106. // {
  107. // if(!vstd::contains(doubleClickInterested, *i)) continue;
  108. // if((*i)->pos.isInside(current.motion.x, current.motion.y))
  109. // {
  110. // (*i)->onDoubleClick();
  111. // doubleClicked = true;
  112. // }
  113. // }
  114. // }
  115. //
  116. // lastClick = current.motion;
  117. // lastClickTime = SDL_GetTicks();
  118. //
  119. // if(doubleClicked)
  120. // return;
  121. // }
  122. handleMouseButtonClick(getListForMouseButton(button), button, true);
  123. }
  124. void InterfaceEventDispatcher::dispatchMouseButtonReleased(const MouseButton & button, const Point & position)
  125. {
  126. handleMouseButtonClick(getListForMouseButton(button), button, false);
  127. }
  128. void InterfaceEventDispatcher::handleMouseButtonClick(CIntObjectList & interestedObjs, MouseButton btn, bool isPressed)
  129. {
  130. auto hlp = interestedObjs;
  131. for(auto i = hlp.begin(); i != hlp.end() && GH.continueEventHandling; i++)
  132. {
  133. if(!vstd::contains(interestedObjs, *i)) continue;
  134. auto prev = (*i)->isMouseButtonPressed(btn);
  135. if(!isPressed)
  136. (*i)->currentMouseState[btn] = isPressed;
  137. if((*i)->isInside(GH.getCursorPosition()))
  138. {
  139. if(isPressed)
  140. (*i)->currentMouseState[btn] = isPressed;
  141. (*i)->click(btn, isPressed, prev);
  142. }
  143. else if(!isPressed)
  144. (*i)->click(btn, boost::logic::indeterminate, prev);
  145. }
  146. }
  147. void InterfaceEventDispatcher::dispatchMouseScrolled(const Point & distance, const Point & position)
  148. {
  149. CIntObjectList hlp = wheelInterested;
  150. for(auto i = hlp.begin(); i != hlp.end() && GH.continueEventHandling; i++)
  151. {
  152. if(!vstd::contains(wheelInterested,*i))
  153. continue;
  154. (*i)->wheelScrolled(distance.y < 0, (*i)->isInside(position));
  155. }
  156. }
  157. void InterfaceEventDispatcher::dispatchTextInput(const std::string & text)
  158. {
  159. for(auto it : textInterested)
  160. {
  161. it->textInputed(text);
  162. }
  163. }
  164. void InterfaceEventDispatcher::dispatchTextEditing(const std::string & text)
  165. {
  166. for(auto it : textInterested)
  167. {
  168. it->textEdited(text);
  169. }
  170. }
  171. void InterfaceEventDispatcher::dispatchMouseMoved(const Point & position)
  172. {
  173. //sending active, hovered hoverable objects hover() call
  174. CIntObjectList hlp;
  175. auto hoverableCopy = hoverable;
  176. for(auto & elem : hoverableCopy)
  177. {
  178. if(elem->isInside(GH.getCursorPosition()))
  179. {
  180. if (!(elem)->isHovered())
  181. hlp.push_back((elem));
  182. }
  183. else if ((elem)->isHovered())
  184. {
  185. (elem)->hover(false);
  186. (elem)->hoveredState = false;
  187. }
  188. }
  189. for(auto & elem : hlp)
  190. {
  191. elem->hover(true);
  192. elem->hoveredState = true;
  193. }
  194. //sending active, MotionInterested objects mouseMoved() call
  195. CIntObjectList miCopy = motioninterested;
  196. for(auto & elem : miCopy)
  197. {
  198. if(elem->strongInterestState || elem->isInside(position)) //checking bounds including border fixes bug #2476
  199. {
  200. (elem)->mouseMoved(position);
  201. }
  202. }
  203. }