You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

350 lines
8.2KB

  1. #include <widget/event.hpp>
  2. #include <widget/Widget.hpp>
  3. #include <context.hpp>
  4. #include <window.hpp>
  5. #include <system.hpp>
  6. namespace rack {
  7. namespace widget {
  8. void EventState::setHovered(widget::Widget* w) {
  9. if (w == hoveredWidget)
  10. return;
  11. if (hoveredWidget) {
  12. // Dispatch LeaveEvent
  13. Widget::LeaveEvent eLeave;
  14. hoveredWidget->onLeave(eLeave);
  15. hoveredWidget = NULL;
  16. }
  17. if (w) {
  18. // Dispatch EnterEvent
  19. EventContext cEnter;
  20. cEnter.target = w;
  21. Widget::EnterEvent eEnter;
  22. eEnter.context = &cEnter;
  23. w->onEnter(eEnter);
  24. hoveredWidget = cEnter.target;
  25. }
  26. }
  27. void EventState::setDragged(widget::Widget* w, int button) {
  28. if (w == draggedWidget)
  29. return;
  30. if (draggedWidget) {
  31. // Dispatch DragEndEvent
  32. Widget::DragEndEvent eDragEnd;
  33. eDragEnd.button = dragButton;
  34. draggedWidget->onDragEnd(eDragEnd);
  35. draggedWidget = NULL;
  36. }
  37. dragButton = button;
  38. if (w) {
  39. // Dispatch DragStartEvent
  40. EventContext cDragStart;
  41. cDragStart.target = w;
  42. Widget::DragStartEvent eDragStart;
  43. eDragStart.context = &cDragStart;
  44. eDragStart.button = dragButton;
  45. w->onDragStart(eDragStart);
  46. draggedWidget = cDragStart.target;
  47. }
  48. }
  49. void EventState::setDragHovered(widget::Widget* w) {
  50. if (w == dragHoveredWidget)
  51. return;
  52. if (dragHoveredWidget) {
  53. // Dispatch DragLeaveEvent
  54. Widget::DragLeaveEvent eDragLeave;
  55. eDragLeave.button = dragButton;
  56. eDragLeave.origin = draggedWidget;
  57. dragHoveredWidget->onDragLeave(eDragLeave);
  58. dragHoveredWidget = NULL;
  59. }
  60. if (w) {
  61. // Dispatch DragEnterEvent
  62. EventContext cDragEnter;
  63. cDragEnter.target = w;
  64. Widget::DragEnterEvent eDragEnter;
  65. eDragEnter.context = &cDragEnter;
  66. eDragEnter.button = dragButton;
  67. eDragEnter.origin = draggedWidget;
  68. w->onDragEnter(eDragEnter);
  69. dragHoveredWidget = cDragEnter.target;
  70. }
  71. }
  72. void EventState::setSelected(widget::Widget* w) {
  73. if (w == selectedWidget)
  74. return;
  75. if (selectedWidget) {
  76. // Dispatch DeselectEvent
  77. Widget::DeselectEvent eDeselect;
  78. selectedWidget->onDeselect(eDeselect);
  79. selectedWidget = NULL;
  80. }
  81. if (w) {
  82. // Dispatch SelectEvent
  83. EventContext cSelect;
  84. cSelect.target = w;
  85. Widget::SelectEvent eSelect;
  86. eSelect.context = &cSelect;
  87. w->onSelect(eSelect);
  88. selectedWidget = cSelect.target;
  89. }
  90. }
  91. void EventState::finalizeWidget(widget::Widget* w) {
  92. if (hoveredWidget == w)
  93. setHovered(NULL);
  94. if (draggedWidget == w)
  95. setDragged(NULL, 0);
  96. if (dragHoveredWidget == w)
  97. setDragHovered(NULL);
  98. if (selectedWidget == w)
  99. setSelected(NULL);
  100. if (lastClickedWidget == w)
  101. lastClickedWidget = NULL;
  102. }
  103. bool EventState::handleButton(math::Vec pos, int button, int action, int mods) {
  104. bool cursorLocked = APP->window->isCursorLocked();
  105. widget::Widget* clickedWidget = NULL;
  106. if (!cursorLocked) {
  107. // Dispatch ButtonEvent
  108. EventContext cButton;
  109. Widget::ButtonEvent eButton;
  110. eButton.context = &cButton;
  111. eButton.pos = pos;
  112. eButton.button = button;
  113. eButton.action = action;
  114. eButton.mods = mods;
  115. rootWidget->onButton(eButton);
  116. clickedWidget = cButton.target;
  117. }
  118. if (action == GLFW_PRESS) {
  119. setDragged(clickedWidget, button);
  120. }
  121. if (action == GLFW_RELEASE) {
  122. setDragHovered(NULL);
  123. if (clickedWidget && draggedWidget) {
  124. // Dispatch DragDropEvent
  125. Widget::DragDropEvent eDragDrop;
  126. eDragDrop.button = dragButton;
  127. eDragDrop.origin = draggedWidget;
  128. clickedWidget->onDragDrop(eDragDrop);
  129. }
  130. setDragged(NULL, 0);
  131. }
  132. if (button == GLFW_MOUSE_BUTTON_LEFT) {
  133. if (action == GLFW_PRESS) {
  134. setSelected(clickedWidget);
  135. }
  136. if (action == GLFW_PRESS) {
  137. const double doubleClickDuration = 0.3;
  138. double clickTime = system::getTime();
  139. if (clickedWidget
  140. && clickTime - lastClickTime <= doubleClickDuration
  141. && lastClickedWidget == clickedWidget) {
  142. // Dispatch DoubleClickEvent
  143. Widget::DoubleClickEvent eDoubleClick;
  144. clickedWidget->onDoubleClick(eDoubleClick);
  145. // Reset double click
  146. lastClickTime = -INFINITY;
  147. lastClickedWidget = NULL;
  148. }
  149. else {
  150. lastClickTime = clickTime;
  151. lastClickedWidget = clickedWidget;
  152. }
  153. }
  154. }
  155. return !!clickedWidget;
  156. }
  157. bool EventState::handleHover(math::Vec pos, math::Vec mouseDelta) {
  158. bool cursorLocked = APP->window->isCursorLocked();
  159. // Fake a key RACK_HELD event for each held key
  160. if (!cursorLocked) {
  161. int mods = APP->window->getMods();
  162. for (int key : heldKeys) {
  163. int scancode = glfwGetKeyScancode(key);
  164. handleKey(pos, key, scancode, RACK_HELD, mods);
  165. }
  166. }
  167. if (draggedWidget) {
  168. bool dragHovered = false;
  169. if (!cursorLocked) {
  170. // Dispatch DragHoverEvent
  171. EventContext cDragHover;
  172. Widget::DragHoverEvent eDragHover;
  173. eDragHover.context = &cDragHover;
  174. eDragHover.button = dragButton;
  175. eDragHover.pos = pos;
  176. eDragHover.mouseDelta = mouseDelta;
  177. eDragHover.origin = draggedWidget;
  178. rootWidget->onDragHover(eDragHover);
  179. setDragHovered(cDragHover.target);
  180. // If consumed, don't continue after DragMoveEvent so HoverEvent is not triggered.
  181. if (cDragHover.target)
  182. dragHovered = true;
  183. }
  184. // Dispatch DragMoveEvent
  185. Widget::DragMoveEvent eDragMove;
  186. eDragMove.button = dragButton;
  187. eDragMove.mouseDelta = mouseDelta;
  188. draggedWidget->onDragMove(eDragMove);
  189. if (dragHovered)
  190. return true;
  191. }
  192. if (!cursorLocked) {
  193. // Dispatch HoverEvent
  194. EventContext cHover;
  195. Widget::HoverEvent eHover;
  196. eHover.context = &cHover;
  197. eHover.pos = pos;
  198. eHover.mouseDelta = mouseDelta;
  199. rootWidget->onHover(eHover);
  200. setHovered(cHover.target);
  201. if (cHover.target)
  202. return true;
  203. }
  204. return false;
  205. }
  206. bool EventState::handleLeave() {
  207. heldKeys.clear();
  208. // When leaving the window, don't un-hover widgets because the mouse might be dragging.
  209. // setDragHovered(NULL);
  210. // setHovered(NULL);
  211. return true;
  212. }
  213. bool EventState::handleScroll(math::Vec pos, math::Vec scrollDelta) {
  214. // Dispatch HoverScrollEvent
  215. EventContext cHoverScroll;
  216. Widget::HoverScrollEvent eHoverScroll;
  217. eHoverScroll.context = &cHoverScroll;
  218. eHoverScroll.pos = pos;
  219. eHoverScroll.scrollDelta = scrollDelta;
  220. rootWidget->onHoverScroll(eHoverScroll);
  221. return !!cHoverScroll.target;
  222. }
  223. bool EventState::handleDrop(math::Vec pos, const std::vector<std::string>& paths) {
  224. // Dispatch PathDropEvent
  225. EventContext cPathDrop;
  226. Widget::PathDropEvent ePathDrop(paths);
  227. ePathDrop.context = &cPathDrop;
  228. ePathDrop.pos = pos;
  229. rootWidget->onPathDrop(ePathDrop);
  230. return !!cPathDrop.target;
  231. }
  232. bool EventState::handleText(math::Vec pos, int codepoint) {
  233. if (selectedWidget) {
  234. // Dispatch SelectTextEvent
  235. EventContext cSelectText;
  236. Widget::SelectTextEvent eSelectText;
  237. eSelectText.context = &cSelectText;
  238. eSelectText.codepoint = codepoint;
  239. selectedWidget->onSelectText(eSelectText);
  240. if (cSelectText.target)
  241. return true;
  242. }
  243. // Dispatch HoverText
  244. EventContext cHoverText;
  245. Widget::HoverTextEvent eHoverText;
  246. eHoverText.context = &cHoverText;
  247. eHoverText.pos = pos;
  248. eHoverText.codepoint = codepoint;
  249. rootWidget->onHoverText(eHoverText);
  250. return !!cHoverText.target;
  251. }
  252. bool EventState::handleKey(math::Vec pos, int key, int scancode, int action, int mods) {
  253. // Update heldKey state
  254. if (action == GLFW_PRESS) {
  255. heldKeys.insert(key);
  256. }
  257. else if (action == GLFW_RELEASE) {
  258. auto it = heldKeys.find(key);
  259. if (it != heldKeys.end())
  260. heldKeys.erase(it);
  261. }
  262. if (selectedWidget) {
  263. // Dispatch SelectKeyEvent
  264. EventContext cSelectKey;
  265. Widget::SelectKeyEvent eSelectKey;
  266. eSelectKey.context = &cSelectKey;
  267. eSelectKey.key = key;
  268. eSelectKey.scancode = scancode;
  269. const char* keyName = glfwGetKeyName(key, scancode);
  270. if (keyName)
  271. eSelectKey.keyName = keyName;
  272. eSelectKey.action = action;
  273. eSelectKey.mods = mods;
  274. selectedWidget->onSelectKey(eSelectKey);
  275. if (cSelectKey.target)
  276. return true;
  277. }
  278. // Dispatch HoverKeyEvent
  279. EventContext cHoverKey;
  280. Widget::HoverKeyEvent eHoverKey;
  281. eHoverKey.context = &cHoverKey;
  282. eHoverKey.pos = pos;
  283. eHoverKey.key = key;
  284. eHoverKey.scancode = scancode;
  285. const char* keyName = glfwGetKeyName(key, scancode);
  286. if (keyName)
  287. eHoverKey.keyName = keyName;
  288. eHoverKey.action = action;
  289. eHoverKey.mods = mods;
  290. rootWidget->onHoverKey(eHoverKey);
  291. return !!cHoverKey.target;
  292. }
  293. bool EventState::handleDirty() {
  294. // Dispatch DirtyEvent
  295. EventContext cDirty;
  296. Widget::DirtyEvent eDirty;
  297. eDirty.context = &cDirty;
  298. rootWidget->onDirty(eDirty);
  299. return true;
  300. }
  301. } // namespace widget
  302. } // namespace rack