test_viewport.h 72 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941
  1. /**************************************************************************/
  2. /* test_viewport.h */
  3. /**************************************************************************/
  4. /* This file is part of: */
  5. /* GODOT ENGINE */
  6. /* https://godotengine.org */
  7. /**************************************************************************/
  8. /* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
  9. /* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
  10. /* */
  11. /* Permission is hereby granted, free of charge, to any person obtaining */
  12. /* a copy of this software and associated documentation files (the */
  13. /* "Software"), to deal in the Software without restriction, including */
  14. /* without limitation the rights to use, copy, modify, merge, publish, */
  15. /* distribute, sublicense, and/or sell copies of the Software, and to */
  16. /* permit persons to whom the Software is furnished to do so, subject to */
  17. /* the following conditions: */
  18. /* */
  19. /* The above copyright notice and this permission notice shall be */
  20. /* included in all copies or substantial portions of the Software. */
  21. /* */
  22. /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
  23. /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
  24. /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
  25. /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
  26. /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
  27. /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
  28. /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
  29. /**************************************************************************/
  30. #ifndef TEST_VIEWPORT_H
  31. #define TEST_VIEWPORT_H
  32. #include "scene/2d/physics/area_2d.h"
  33. #include "scene/2d/physics/collision_shape_2d.h"
  34. #include "scene/gui/control.h"
  35. #include "scene/gui/subviewport_container.h"
  36. #include "scene/main/canvas_layer.h"
  37. #include "scene/main/window.h"
  38. #include "scene/resources/2d/rectangle_shape_2d.h"
  39. #include "servers/physics_server_2d_dummy.h"
  40. #include "tests/test_macros.h"
  41. namespace TestViewport {
  42. class NotificationControlViewport : public Control {
  43. GDCLASS(NotificationControlViewport, Control);
  44. protected:
  45. void _notification(int p_what) {
  46. switch (p_what) {
  47. case NOTIFICATION_MOUSE_ENTER: {
  48. if (mouse_over) {
  49. invalid_order = true;
  50. }
  51. mouse_over = true;
  52. } break;
  53. case NOTIFICATION_MOUSE_EXIT: {
  54. if (!mouse_over) {
  55. invalid_order = true;
  56. }
  57. mouse_over = false;
  58. } break;
  59. case NOTIFICATION_MOUSE_ENTER_SELF: {
  60. if (mouse_over_self) {
  61. invalid_order = true;
  62. }
  63. mouse_over_self = true;
  64. } break;
  65. case NOTIFICATION_MOUSE_EXIT_SELF: {
  66. if (!mouse_over_self) {
  67. invalid_order = true;
  68. }
  69. mouse_over_self = false;
  70. } break;
  71. }
  72. }
  73. public:
  74. bool mouse_over = false;
  75. bool mouse_over_self = false;
  76. bool invalid_order = false;
  77. };
  78. // `NotificationControlViewport`-derived class that additionally
  79. // - allows start Dragging
  80. // - stores mouse information of last event
  81. class DragStart : public NotificationControlViewport {
  82. GDCLASS(DragStart, NotificationControlViewport);
  83. public:
  84. MouseButton last_mouse_button;
  85. Point2i last_mouse_move_position;
  86. StringName drag_data_name = SNAME("Drag Data");
  87. virtual Variant get_drag_data(const Point2 &p_point) override {
  88. return drag_data_name;
  89. }
  90. virtual void gui_input(const Ref<InputEvent> &p_event) override {
  91. Ref<InputEventMouseButton> mb = p_event;
  92. if (mb.is_valid()) {
  93. last_mouse_button = mb->get_button_index();
  94. return;
  95. }
  96. Ref<InputEventMouseMotion> mm = p_event;
  97. if (mm.is_valid()) {
  98. last_mouse_move_position = mm->get_position();
  99. return;
  100. }
  101. }
  102. };
  103. // `NotificationControlViewport`-derived class that acts as a Drag and Drop target.
  104. class DragTarget : public NotificationControlViewport {
  105. GDCLASS(DragTarget, NotificationControlViewport);
  106. protected:
  107. void _notification(int p_what) {
  108. switch (p_what) {
  109. case NOTIFICATION_DRAG_BEGIN: {
  110. during_drag = true;
  111. } break;
  112. case NOTIFICATION_DRAG_END: {
  113. during_drag = false;
  114. } break;
  115. }
  116. }
  117. public:
  118. Variant drag_data;
  119. bool valid_drop = false;
  120. bool during_drag = false;
  121. virtual bool can_drop_data(const Point2 &p_point, const Variant &p_data) const override {
  122. StringName string_data = p_data;
  123. // Verify drag data is compatible.
  124. if (string_data != SNAME("Drag Data")) {
  125. return false;
  126. }
  127. // Only the left half is droppable area.
  128. if (p_point.x * 2 > get_size().x) {
  129. return false;
  130. }
  131. return true;
  132. }
  133. virtual void drop_data(const Point2 &p_point, const Variant &p_data) override {
  134. drag_data = p_data;
  135. valid_drop = true;
  136. }
  137. };
  138. TEST_CASE("[SceneTree][Viewport] Controls and InputEvent handling") {
  139. DragStart *node_a = memnew(DragStart);
  140. NotificationControlViewport *node_b = memnew(NotificationControlViewport);
  141. Node2D *node_c = memnew(Node2D);
  142. DragTarget *node_d = memnew(DragTarget);
  143. NotificationControlViewport *node_e = memnew(NotificationControlViewport);
  144. Node *node_f = memnew(Node);
  145. NotificationControlViewport *node_g = memnew(NotificationControlViewport);
  146. NotificationControlViewport *node_h = memnew(NotificationControlViewport);
  147. NotificationControlViewport *node_i = memnew(NotificationControlViewport);
  148. NotificationControlViewport *node_j = memnew(NotificationControlViewport);
  149. node_a->set_name(SNAME("NodeA"));
  150. node_b->set_name(SNAME("NodeB"));
  151. node_c->set_name(SNAME("NodeC"));
  152. node_d->set_name(SNAME("NodeD"));
  153. node_e->set_name(SNAME("NodeE"));
  154. node_f->set_name(SNAME("NodeF"));
  155. node_g->set_name(SNAME("NodeG"));
  156. node_h->set_name(SNAME("NodeH"));
  157. node_i->set_name(SNAME("NodeI"));
  158. node_j->set_name(SNAME("NodeJ"));
  159. node_a->set_position(Point2i(0, 0));
  160. node_b->set_position(Point2i(10, 10));
  161. node_c->set_position(Point2i(0, 0));
  162. node_d->set_position(Point2i(10, 10));
  163. node_e->set_position(Point2i(10, 100));
  164. node_g->set_position(Point2i(10, 100));
  165. node_h->set_position(Point2i(10, 120));
  166. node_i->set_position(Point2i(2, 0));
  167. node_j->set_position(Point2i(2, 0));
  168. node_a->set_size(Point2i(30, 30));
  169. node_b->set_size(Point2i(30, 30));
  170. node_d->set_size(Point2i(30, 30));
  171. node_e->set_size(Point2i(10, 10));
  172. node_g->set_size(Point2i(10, 10));
  173. node_h->set_size(Point2i(10, 10));
  174. node_i->set_size(Point2i(10, 10));
  175. node_j->set_size(Point2i(10, 10));
  176. node_a->set_focus_mode(Control::FOCUS_CLICK);
  177. node_b->set_focus_mode(Control::FOCUS_CLICK);
  178. node_d->set_focus_mode(Control::FOCUS_CLICK);
  179. node_e->set_focus_mode(Control::FOCUS_CLICK);
  180. node_g->set_focus_mode(Control::FOCUS_CLICK);
  181. node_h->set_focus_mode(Control::FOCUS_CLICK);
  182. node_i->set_focus_mode(Control::FOCUS_CLICK);
  183. node_j->set_focus_mode(Control::FOCUS_CLICK);
  184. Window *root = SceneTree::get_singleton()->get_root();
  185. DisplayServerMock *DS = (DisplayServerMock *)(DisplayServer::get_singleton());
  186. // Scene tree:
  187. // - root
  188. // - a (Control)
  189. // - b (Control)
  190. // - c (Node2D)
  191. // - d (Control)
  192. // - e (Control)
  193. // - f (Node)
  194. // - g (Control)
  195. // - h (Control)
  196. // - i (Control)
  197. // - j (Control)
  198. root->add_child(node_a);
  199. root->add_child(node_b);
  200. node_b->add_child(node_c);
  201. node_c->add_child(node_d);
  202. root->add_child(node_e);
  203. node_e->add_child(node_f);
  204. node_f->add_child(node_g);
  205. root->add_child(node_h);
  206. node_h->add_child(node_i);
  207. node_i->add_child(node_j);
  208. Point2i on_a = Point2i(5, 5);
  209. Point2i on_b = Point2i(15, 15);
  210. Point2i on_d = Point2i(25, 25);
  211. Point2i on_e = Point2i(15, 105);
  212. Point2i on_g = Point2i(15, 105);
  213. Point2i on_i = Point2i(13, 125);
  214. Point2i on_j = Point2i(15, 125);
  215. Point2i on_background = Point2i(500, 500);
  216. Point2i on_outside = Point2i(-1, -1);
  217. // Unit tests for Viewport::gui_find_control and Viewport::_gui_find_control_at_pos
  218. SUBCASE("[VIEWPORT][GuiFindControl] Finding Controls at a Viewport-position") {
  219. // FIXME: It is extremely difficult to create a situation where the Control has a zero determinant.
  220. // Leaving that if-branch untested.
  221. SUBCASE("[VIEWPORT][GuiFindControl] Basic position tests") {
  222. CHECK(root->gui_find_control(on_a) == node_a);
  223. CHECK(root->gui_find_control(on_b) == node_b);
  224. CHECK(root->gui_find_control(on_d) == node_d);
  225. CHECK(root->gui_find_control(on_e) == node_g); // Node F makes G a Root Control at the same position as E
  226. CHECK(root->gui_find_control(on_g) == node_g);
  227. CHECK_FALSE(root->gui_find_control(on_background));
  228. }
  229. SUBCASE("[VIEWPORT][GuiFindControl] Invisible nodes are not considered as results.") {
  230. // Non-Root Control
  231. node_d->hide();
  232. CHECK(root->gui_find_control(on_d) == node_b);
  233. // Root Control
  234. node_b->hide();
  235. CHECK(root->gui_find_control(on_b) == node_a);
  236. }
  237. SUBCASE("[VIEWPORT][GuiFindControl] Root Control with CanvasItem as parent is affected by parent's transform.") {
  238. node_b->remove_child(node_c);
  239. node_c->set_position(Point2i(50, 50));
  240. root->add_child(node_c);
  241. CHECK(root->gui_find_control(Point2i(65, 65)) == node_d);
  242. }
  243. SUBCASE("[VIEWPORT][GuiFindControl] Control Contents Clipping clips accessible position of children.") {
  244. CHECK_FALSE(node_b->is_clipping_contents());
  245. CHECK(root->gui_find_control(on_d + Point2i(20, 20)) == node_d);
  246. node_b->set_clip_contents(true);
  247. CHECK(root->gui_find_control(on_d) == node_d);
  248. CHECK_FALSE(root->gui_find_control(on_d + Point2i(20, 20)));
  249. }
  250. SUBCASE("[VIEWPORT][GuiFindControl] Top Level Control as descendant of CanvasItem isn't affected by parent's transform.") {
  251. CHECK(root->gui_find_control(on_d + Point2i(20, 20)) == node_d);
  252. node_d->set_as_top_level(true);
  253. CHECK_FALSE(root->gui_find_control(on_d + Point2i(20, 20)));
  254. CHECK(root->gui_find_control(on_b) == node_d);
  255. }
  256. }
  257. SUBCASE("[Viewport][GuiInputEvent] nullptr as argument doesn't lead to a crash.") {
  258. ERR_PRINT_OFF;
  259. root->push_input(nullptr);
  260. ERR_PRINT_ON;
  261. }
  262. // Unit tests for Viewport::_gui_input_event (Mouse Buttons)
  263. SUBCASE("[Viewport][GuiInputEvent] Mouse Button Down/Up.") {
  264. SUBCASE("[Viewport][GuiInputEvent] Mouse Button Control Focus Change.") {
  265. SUBCASE("[Viewport][GuiInputEvent] Grab Focus while no Control has focus.") {
  266. CHECK_FALSE(root->gui_get_focus_owner());
  267. // Click on A
  268. SEND_GUI_MOUSE_BUTTON_EVENT(on_a, MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
  269. CHECK(node_a->has_focus());
  270. SEND_GUI_MOUSE_BUTTON_RELEASED_EVENT(on_a, MouseButton::LEFT, MouseButtonMask::NONE, Key::NONE);
  271. }
  272. SUBCASE("[Viewport][GuiInputEvent] Grab Focus from other Control.") {
  273. node_a->grab_focus();
  274. CHECK(node_a->has_focus());
  275. // Click on D
  276. SEND_GUI_MOUSE_BUTTON_EVENT(on_d, MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
  277. CHECK(node_d->has_focus());
  278. SEND_GUI_MOUSE_BUTTON_RELEASED_EVENT(on_d, MouseButton::LEFT, MouseButtonMask::NONE, Key::NONE);
  279. }
  280. SUBCASE("[Viewport][GuiInputEvent] Non-CanvasItem breaks Transform hierarchy.") {
  281. CHECK_FALSE(root->gui_get_focus_owner());
  282. // Click on G absolute coordinates
  283. SEND_GUI_MOUSE_BUTTON_EVENT(Point2i(15, 105), MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
  284. CHECK(node_g->has_focus());
  285. SEND_GUI_MOUSE_BUTTON_RELEASED_EVENT(Point2i(15, 105), MouseButton::LEFT, MouseButtonMask::NONE, Key::NONE);
  286. }
  287. SUBCASE("[Viewport][GuiInputEvent] No Focus change when clicking in background.") {
  288. CHECK_FALSE(root->gui_get_focus_owner());
  289. SEND_GUI_MOUSE_BUTTON_EVENT(on_background, MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
  290. CHECK_FALSE(root->gui_get_focus_owner());
  291. SEND_GUI_MOUSE_BUTTON_RELEASED_EVENT(on_background, MouseButton::LEFT, MouseButtonMask::NONE, Key::NONE);
  292. node_a->grab_focus();
  293. CHECK(node_a->has_focus());
  294. SEND_GUI_MOUSE_BUTTON_EVENT(on_background, MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
  295. SEND_GUI_MOUSE_BUTTON_RELEASED_EVENT(on_background, MouseButton::LEFT, MouseButtonMask::NONE, Key::NONE);
  296. CHECK(node_a->has_focus());
  297. }
  298. SUBCASE("[Viewport][GuiInputEvent] Mouse Button No Focus Steal while other Mouse Button is pressed.") {
  299. CHECK_FALSE(root->gui_get_focus_owner());
  300. SEND_GUI_MOUSE_BUTTON_EVENT(on_a, MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
  301. CHECK(node_a->has_focus());
  302. SEND_GUI_MOUSE_BUTTON_EVENT(on_b, MouseButton::RIGHT, (int)MouseButtonMask::LEFT | (int)MouseButtonMask::RIGHT, Key::NONE);
  303. CHECK(node_a->has_focus());
  304. SEND_GUI_MOUSE_BUTTON_RELEASED_EVENT(on_b, MouseButton::RIGHT, MouseButtonMask::LEFT, Key::NONE);
  305. SEND_GUI_MOUSE_BUTTON_RELEASED_EVENT(on_b, MouseButton::LEFT, MouseButtonMask::NONE, Key::NONE);
  306. CHECK(node_a->has_focus());
  307. }
  308. SUBCASE("[Viewport][GuiInputEvent] Allow Focus Steal with LMB while other Mouse Button is held down and was initially pressed without being over a Control.") {
  309. // TODO: Not sure, if this is intended behavior, but this is an edge case.
  310. CHECK_FALSE(root->gui_get_focus_owner());
  311. SEND_GUI_MOUSE_BUTTON_EVENT(on_background, MouseButton::RIGHT, MouseButtonMask::RIGHT, Key::NONE);
  312. CHECK_FALSE(root->gui_get_focus_owner());
  313. SEND_GUI_MOUSE_BUTTON_EVENT(on_a, MouseButton::LEFT, (int)MouseButtonMask::LEFT | (int)MouseButtonMask::RIGHT, Key::NONE);
  314. CHECK(node_a->has_focus());
  315. SEND_GUI_MOUSE_BUTTON_RELEASED_EVENT(on_a, MouseButton::LEFT, MouseButtonMask::RIGHT, Key::NONE);
  316. CHECK(node_a->has_focus());
  317. SEND_GUI_MOUSE_BUTTON_EVENT(on_b, MouseButton::LEFT, (int)MouseButtonMask::LEFT | (int)MouseButtonMask::RIGHT, Key::NONE);
  318. CHECK(node_b->has_focus());
  319. SEND_GUI_MOUSE_BUTTON_RELEASED_EVENT(on_d, MouseButton::LEFT, MouseButtonMask::RIGHT, Key::NONE);
  320. SEND_GUI_MOUSE_BUTTON_RELEASED_EVENT(on_d, MouseButton::RIGHT, MouseButtonMask::NONE, Key::NONE);
  321. CHECK(node_b->has_focus());
  322. }
  323. SUBCASE("[Viewport][GuiInputEvent] Ignore Focus from Mouse Buttons when mouse-filter is set to ignore.") {
  324. node_d->grab_focus();
  325. node_d->set_mouse_filter(Control::MOUSE_FILTER_IGNORE);
  326. CHECK(node_d->has_focus());
  327. // Click on overlapping area B&D.
  328. SEND_GUI_MOUSE_BUTTON_EVENT(on_d, MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
  329. CHECK(node_b->has_focus());
  330. SEND_GUI_MOUSE_BUTTON_RELEASED_EVENT(on_d, MouseButton::LEFT, MouseButtonMask::NONE, Key::NONE);
  331. }
  332. SUBCASE("[Viewport][GuiInputEvent] RMB doesn't grab focus.") {
  333. node_a->grab_focus();
  334. CHECK(node_a->has_focus());
  335. SEND_GUI_MOUSE_BUTTON_EVENT(on_d, MouseButton::RIGHT, MouseButtonMask::RIGHT, Key::NONE);
  336. SEND_GUI_MOUSE_BUTTON_RELEASED_EVENT(on_d, MouseButton::RIGHT, MouseButtonMask::NONE, Key::NONE);
  337. CHECK(node_a->has_focus());
  338. }
  339. SUBCASE("[Viewport][GuiInputEvent] LMB on unfocusable Control doesn't grab focus.") {
  340. CHECK_FALSE(node_g->has_focus());
  341. node_g->set_focus_mode(Control::FOCUS_NONE);
  342. SEND_GUI_MOUSE_BUTTON_EVENT(on_g, MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
  343. SEND_GUI_MOUSE_BUTTON_RELEASED_EVENT(on_g, MouseButton::LEFT, MouseButtonMask::NONE, Key::NONE);
  344. CHECK_FALSE(node_g->has_focus());
  345. // Now verify the opposite with FOCUS_CLICK
  346. node_g->set_focus_mode(Control::FOCUS_CLICK);
  347. SEND_GUI_MOUSE_BUTTON_EVENT(on_g, MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
  348. SEND_GUI_MOUSE_BUTTON_RELEASED_EVENT(on_g, MouseButton::LEFT, MouseButtonMask::NONE, Key::NONE);
  349. CHECK(node_g->has_focus());
  350. node_g->set_focus_mode(Control::FOCUS_CLICK);
  351. }
  352. SUBCASE("[Viewport][GuiInputEvent] Signal 'gui_focus_changed' is only emitted if a previously unfocused Control grabs focus.") {
  353. SIGNAL_WATCH(root, SNAME("gui_focus_changed"));
  354. Array node_array;
  355. node_array.push_back(node_a);
  356. Array signal_args;
  357. signal_args.push_back(node_array);
  358. SEND_GUI_MOUSE_BUTTON_EVENT(on_a, MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
  359. SEND_GUI_MOUSE_BUTTON_RELEASED_EVENT(on_a, MouseButton::LEFT, MouseButtonMask::NONE, Key::NONE);
  360. SIGNAL_CHECK(SNAME("gui_focus_changed"), signal_args);
  361. SEND_GUI_MOUSE_BUTTON_EVENT(on_a, MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
  362. SEND_GUI_MOUSE_BUTTON_RELEASED_EVENT(on_a, MouseButton::LEFT, MouseButtonMask::NONE, Key::NONE);
  363. CHECK(node_a->has_focus());
  364. SIGNAL_CHECK_FALSE(SNAME("gui_focus_changed"));
  365. SIGNAL_UNWATCH(root, SNAME("gui_focus_changed"));
  366. }
  367. SUBCASE("[Viewport][GuiInputEvent] Focus Propagation to parent items.") {
  368. SUBCASE("[Viewport][GuiInputEvent] Unfocusable Control with MOUSE_FILTER_PASS propagates focus to parent CanvasItem.") {
  369. node_d->set_focus_mode(Control::FOCUS_NONE);
  370. node_d->set_mouse_filter(Control::MOUSE_FILTER_PASS);
  371. SEND_GUI_MOUSE_BUTTON_EVENT(on_d + Point2i(20, 20), MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
  372. CHECK(node_b->has_focus());
  373. SEND_GUI_MOUSE_BUTTON_RELEASED_EVENT(on_d + Point2i(20, 20), MouseButton::LEFT, MouseButtonMask::NONE, Key::NONE);
  374. // Verify break condition for Root Control.
  375. node_a->set_focus_mode(Control::FOCUS_NONE);
  376. node_a->set_mouse_filter(Control::MOUSE_FILTER_PASS);
  377. SEND_GUI_MOUSE_BUTTON_EVENT(on_a, MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
  378. SEND_GUI_MOUSE_BUTTON_RELEASED_EVENT(on_a, MouseButton::LEFT, MouseButtonMask::NONE, Key::NONE);
  379. CHECK(node_b->has_focus());
  380. }
  381. SUBCASE("[Viewport][GuiInputEvent] Top Level CanvasItem stops focus propagation.") {
  382. node_d->set_focus_mode(Control::FOCUS_NONE);
  383. node_d->set_mouse_filter(Control::MOUSE_FILTER_PASS);
  384. node_c->set_as_top_level(true);
  385. SEND_GUI_MOUSE_BUTTON_EVENT(on_b, MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
  386. SEND_GUI_MOUSE_BUTTON_RELEASED_EVENT(on_b, MouseButton::LEFT, MouseButtonMask::NONE, Key::NONE);
  387. CHECK_FALSE(root->gui_get_focus_owner());
  388. node_d->set_focus_mode(Control::FOCUS_CLICK);
  389. SEND_GUI_MOUSE_BUTTON_EVENT(on_b, MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
  390. SEND_GUI_MOUSE_BUTTON_RELEASED_EVENT(on_b, MouseButton::LEFT, MouseButtonMask::NONE, Key::NONE);
  391. CHECK(node_d->has_focus());
  392. }
  393. }
  394. }
  395. SUBCASE("[Viewport][GuiInputEvent] Process-Mode affects, if GUI Mouse Button Events are processed.") {
  396. node_a->last_mouse_button = MouseButton::NONE;
  397. node_a->set_process_mode(Node::PROCESS_MODE_DISABLED);
  398. SEND_GUI_MOUSE_BUTTON_EVENT(on_a, MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
  399. SEND_GUI_MOUSE_BUTTON_RELEASED_EVENT(on_a, MouseButton::LEFT, MouseButtonMask::NONE, Key::NONE);
  400. CHECK(node_a->last_mouse_button == MouseButton::NONE);
  401. // Now verify that with allowed processing the event is processed.
  402. node_a->set_process_mode(Node::PROCESS_MODE_ALWAYS);
  403. SEND_GUI_MOUSE_BUTTON_EVENT(on_a, MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
  404. SEND_GUI_MOUSE_BUTTON_RELEASED_EVENT(on_a, MouseButton::LEFT, MouseButtonMask::NONE, Key::NONE);
  405. CHECK(node_a->last_mouse_button == MouseButton::LEFT);
  406. }
  407. }
  408. // Unit tests for Viewport::_gui_input_event (Mouse Motion)
  409. SUBCASE("[Viewport][GuiInputEvent] Mouse Motion") {
  410. // FIXME: Tooltips are not yet tested. They likely require an internal clock.
  411. SUBCASE("[Viewport][GuiInputEvent] Mouse Motion changes the Control that it is over.") {
  412. SEND_GUI_MOUSE_MOTION_EVENT(on_background, MouseButtonMask::NONE, Key::NONE);
  413. CHECK_FALSE(node_a->mouse_over);
  414. CHECK_FALSE(node_a->mouse_over_self);
  415. // Move over Control.
  416. SEND_GUI_MOUSE_MOTION_EVENT(on_a, MouseButtonMask::NONE, Key::NONE);
  417. CHECK(node_a->mouse_over);
  418. CHECK(node_a->mouse_over_self);
  419. // No change.
  420. SEND_GUI_MOUSE_MOTION_EVENT(on_a + Point2i(1, 1), MouseButtonMask::NONE, Key::NONE);
  421. CHECK(node_a->mouse_over);
  422. CHECK(node_a->mouse_over_self);
  423. // Move over other Control.
  424. SEND_GUI_MOUSE_MOTION_EVENT(on_d, MouseButtonMask::NONE, Key::NONE);
  425. CHECK_FALSE(node_a->mouse_over);
  426. CHECK_FALSE(node_a->mouse_over_self);
  427. CHECK(node_d->mouse_over);
  428. CHECK(node_d->mouse_over_self);
  429. // Move to background.
  430. SEND_GUI_MOUSE_MOTION_EVENT(on_background, MouseButtonMask::NONE, Key::NONE);
  431. CHECK_FALSE(node_d->mouse_over);
  432. CHECK_FALSE(node_d->mouse_over_self);
  433. CHECK_FALSE(node_a->invalid_order);
  434. CHECK_FALSE(node_d->invalid_order);
  435. }
  436. SUBCASE("[Viewport][GuiInputEvent] Mouse Enter/Exit notification propagation.") {
  437. node_d->set_mouse_filter(Control::MOUSE_FILTER_PASS);
  438. node_g->set_mouse_filter(Control::MOUSE_FILTER_PASS);
  439. SEND_GUI_MOUSE_MOTION_EVENT(on_background, MouseButtonMask::NONE, Key::NONE);
  440. CHECK_FALSE(node_b->mouse_over);
  441. CHECK_FALSE(node_b->mouse_over_self);
  442. CHECK_FALSE(node_d->mouse_over);
  443. CHECK_FALSE(node_d->mouse_over_self);
  444. // Move to Control node_d. node_b receives mouse over since it is only separated by a CanvasItem.
  445. SEND_GUI_MOUSE_MOTION_EVENT(on_d, MouseButtonMask::NONE, Key::NONE);
  446. CHECK(node_b->mouse_over);
  447. CHECK_FALSE(node_b->mouse_over_self);
  448. CHECK(node_d->mouse_over);
  449. CHECK(node_d->mouse_over_self);
  450. // Move to background.
  451. SEND_GUI_MOUSE_MOTION_EVENT(on_background, MouseButtonMask::NONE, Key::NONE);
  452. CHECK_FALSE(node_b->mouse_over);
  453. CHECK_FALSE(node_b->mouse_over_self);
  454. CHECK_FALSE(node_d->mouse_over);
  455. CHECK_FALSE(node_d->mouse_over_self);
  456. CHECK_FALSE(node_e->mouse_over);
  457. CHECK_FALSE(node_e->mouse_over_self);
  458. CHECK_FALSE(node_g->mouse_over);
  459. CHECK_FALSE(node_g->mouse_over_self);
  460. // Move to Control node_g. node_g receives mouse over but node_e does not since it is separated by a non-CanvasItem.
  461. SEND_GUI_MOUSE_MOTION_EVENT(on_g, MouseButtonMask::NONE, Key::NONE);
  462. CHECK_FALSE(node_e->mouse_over);
  463. CHECK_FALSE(node_e->mouse_over_self);
  464. CHECK(node_g->mouse_over);
  465. CHECK(node_g->mouse_over_self);
  466. // Move to background.
  467. SEND_GUI_MOUSE_MOTION_EVENT(on_background, MouseButtonMask::NONE, Key::NONE);
  468. CHECK_FALSE(node_e->mouse_over);
  469. CHECK_FALSE(node_e->mouse_over_self);
  470. CHECK_FALSE(node_g->mouse_over);
  471. CHECK_FALSE(node_g->mouse_over_self);
  472. CHECK_FALSE(node_b->invalid_order);
  473. CHECK_FALSE(node_d->invalid_order);
  474. CHECK_FALSE(node_e->invalid_order);
  475. CHECK_FALSE(node_g->invalid_order);
  476. node_d->set_mouse_filter(Control::MOUSE_FILTER_STOP);
  477. node_g->set_mouse_filter(Control::MOUSE_FILTER_STOP);
  478. }
  479. SUBCASE("[Viewport][GuiInputEvent] Mouse Enter/Exit notification propagation when moving into child.") {
  480. SIGNAL_WATCH(node_i, SceneStringName(mouse_entered));
  481. SIGNAL_WATCH(node_i, SceneStringName(mouse_exited));
  482. Array signal_args;
  483. signal_args.push_back(Array());
  484. node_j->set_mouse_filter(Control::MOUSE_FILTER_PASS);
  485. // Move to background.
  486. SEND_GUI_MOUSE_MOTION_EVENT(on_background, MouseButtonMask::NONE, Key::NONE);
  487. CHECK_FALSE(node_i->mouse_over);
  488. CHECK_FALSE(node_i->mouse_over_self);
  489. CHECK_FALSE(node_j->mouse_over);
  490. CHECK_FALSE(node_j->mouse_over_self);
  491. // Move to Control node_i.
  492. SEND_GUI_MOUSE_MOTION_EVENT(on_i, MouseButtonMask::NONE, Key::NONE);
  493. CHECK(node_i->mouse_over);
  494. CHECK(node_i->mouse_over_self);
  495. CHECK_FALSE(node_j->mouse_over);
  496. CHECK_FALSE(node_j->mouse_over_self);
  497. SIGNAL_CHECK(SceneStringName(mouse_entered), signal_args);
  498. SIGNAL_CHECK_FALSE(SceneStringName(mouse_exited));
  499. // Move to child Control node_j. node_i should not receive any new Mouse Enter signals.
  500. SEND_GUI_MOUSE_MOTION_EVENT(on_j, MouseButtonMask::NONE, Key::NONE);
  501. CHECK(node_i->mouse_over);
  502. CHECK_FALSE(node_i->mouse_over_self);
  503. CHECK(node_j->mouse_over);
  504. CHECK(node_j->mouse_over_self);
  505. SIGNAL_CHECK_FALSE(SceneStringName(mouse_entered));
  506. SIGNAL_CHECK_FALSE(SceneStringName(mouse_exited));
  507. // Move to parent Control node_i. node_i should not receive any new Mouse Enter signals.
  508. SEND_GUI_MOUSE_MOTION_EVENT(on_i, MouseButtonMask::NONE, Key::NONE);
  509. CHECK(node_i->mouse_over);
  510. CHECK(node_i->mouse_over_self);
  511. CHECK_FALSE(node_j->mouse_over);
  512. CHECK_FALSE(node_j->mouse_over_self);
  513. SIGNAL_CHECK_FALSE(SceneStringName(mouse_entered));
  514. SIGNAL_CHECK_FALSE(SceneStringName(mouse_exited));
  515. // Move to background.
  516. SEND_GUI_MOUSE_MOTION_EVENT(on_background, MouseButtonMask::NONE, Key::NONE);
  517. CHECK_FALSE(node_i->mouse_over);
  518. CHECK_FALSE(node_i->mouse_over_self);
  519. CHECK_FALSE(node_j->mouse_over);
  520. CHECK_FALSE(node_j->mouse_over_self);
  521. SIGNAL_CHECK_FALSE(SceneStringName(mouse_entered));
  522. SIGNAL_CHECK(SceneStringName(mouse_exited), signal_args);
  523. CHECK_FALSE(node_i->invalid_order);
  524. CHECK_FALSE(node_j->invalid_order);
  525. node_j->set_mouse_filter(Control::MOUSE_FILTER_STOP);
  526. SIGNAL_UNWATCH(node_i, SceneStringName(mouse_entered));
  527. SIGNAL_UNWATCH(node_i, SceneStringName(mouse_exited));
  528. }
  529. SUBCASE("[Viewport][GuiInputEvent] Mouse Enter/Exit notification propagation with top level.") {
  530. node_c->set_as_top_level(true);
  531. node_i->set_as_top_level(true);
  532. node_c->set_position(node_b->get_global_position());
  533. node_i->set_position(node_h->get_global_position());
  534. node_d->set_mouse_filter(Control::MOUSE_FILTER_PASS);
  535. node_i->set_mouse_filter(Control::MOUSE_FILTER_PASS);
  536. node_j->set_mouse_filter(Control::MOUSE_FILTER_PASS);
  537. SEND_GUI_MOUSE_MOTION_EVENT(on_background, MouseButtonMask::NONE, Key::NONE);
  538. CHECK_FALSE(node_b->mouse_over);
  539. CHECK_FALSE(node_b->mouse_over_self);
  540. CHECK_FALSE(node_d->mouse_over);
  541. CHECK_FALSE(node_d->mouse_over_self);
  542. // Move to Control node_d. node_b does not receive mouse over since node_c is top level.
  543. SEND_GUI_MOUSE_MOTION_EVENT(on_d, MouseButtonMask::NONE, Key::NONE);
  544. CHECK_FALSE(node_b->mouse_over);
  545. CHECK_FALSE(node_b->mouse_over_self);
  546. CHECK(node_d->mouse_over);
  547. CHECK(node_d->mouse_over_self);
  548. // Move to background.
  549. SEND_GUI_MOUSE_MOTION_EVENT(on_background, MouseButtonMask::NONE, Key::NONE);
  550. CHECK_FALSE(node_b->mouse_over);
  551. CHECK_FALSE(node_b->mouse_over_self);
  552. CHECK_FALSE(node_d->mouse_over);
  553. CHECK_FALSE(node_d->mouse_over_self);
  554. CHECK_FALSE(node_g->mouse_over);
  555. CHECK_FALSE(node_g->mouse_over_self);
  556. CHECK_FALSE(node_h->mouse_over);
  557. CHECK_FALSE(node_h->mouse_over_self);
  558. CHECK_FALSE(node_i->mouse_over);
  559. CHECK_FALSE(node_i->mouse_over_self);
  560. // Move to Control node_j. node_h does not receive mouse over since node_i is top level.
  561. SEND_GUI_MOUSE_MOTION_EVENT(on_j, MouseButtonMask::NONE, Key::NONE);
  562. CHECK_FALSE(node_h->mouse_over);
  563. CHECK_FALSE(node_h->mouse_over_self);
  564. CHECK(node_i->mouse_over);
  565. CHECK_FALSE(node_i->mouse_over_self);
  566. CHECK(node_j->mouse_over);
  567. CHECK(node_j->mouse_over_self);
  568. // Move to background.
  569. SEND_GUI_MOUSE_MOTION_EVENT(on_background, MouseButtonMask::NONE, Key::NONE);
  570. CHECK_FALSE(node_h->mouse_over);
  571. CHECK_FALSE(node_h->mouse_over_self);
  572. CHECK_FALSE(node_i->mouse_over);
  573. CHECK_FALSE(node_i->mouse_over_self);
  574. CHECK_FALSE(node_j->mouse_over);
  575. CHECK_FALSE(node_j->mouse_over_self);
  576. CHECK_FALSE(node_b->invalid_order);
  577. CHECK_FALSE(node_d->invalid_order);
  578. CHECK_FALSE(node_e->invalid_order);
  579. CHECK_FALSE(node_h->invalid_order);
  580. CHECK_FALSE(node_i->invalid_order);
  581. CHECK_FALSE(node_j->invalid_order);
  582. node_c->set_as_top_level(false);
  583. node_i->set_as_top_level(false);
  584. node_c->set_position(Point2i(0, 0));
  585. node_i->set_position(Point2i(0, 0));
  586. node_d->set_mouse_filter(Control::MOUSE_FILTER_STOP);
  587. node_i->set_mouse_filter(Control::MOUSE_FILTER_STOP);
  588. node_j->set_mouse_filter(Control::MOUSE_FILTER_STOP);
  589. }
  590. SUBCASE("[Viewport][GuiInputEvent] Mouse Enter/Exit notification propagation with mouse filter stop.") {
  591. node_i->set_mouse_filter(Control::MOUSE_FILTER_STOP);
  592. node_j->set_mouse_filter(Control::MOUSE_FILTER_PASS);
  593. // Move to background.
  594. SEND_GUI_MOUSE_MOTION_EVENT(on_background, MouseButtonMask::NONE, Key::NONE);
  595. CHECK_FALSE(node_h->mouse_over);
  596. CHECK_FALSE(node_h->mouse_over_self);
  597. CHECK_FALSE(node_i->mouse_over);
  598. CHECK_FALSE(node_i->mouse_over_self);
  599. CHECK_FALSE(node_j->mouse_over);
  600. CHECK_FALSE(node_j->mouse_over_self);
  601. // Move to Control node_j. node_h does not receive mouse over since node_i is MOUSE_FILTER_STOP.
  602. SEND_GUI_MOUSE_MOTION_EVENT(on_j, MouseButtonMask::NONE, Key::NONE);
  603. CHECK_FALSE(node_h->mouse_over);
  604. CHECK_FALSE(node_h->mouse_over_self);
  605. CHECK(node_i->mouse_over);
  606. CHECK_FALSE(node_i->mouse_over_self);
  607. CHECK(node_j->mouse_over);
  608. CHECK(node_j->mouse_over_self);
  609. // Move to background.
  610. SEND_GUI_MOUSE_MOTION_EVENT(on_background, MouseButtonMask::NONE, Key::NONE);
  611. CHECK_FALSE(node_h->mouse_over);
  612. CHECK_FALSE(node_h->mouse_over_self);
  613. CHECK_FALSE(node_i->mouse_over);
  614. CHECK_FALSE(node_i->mouse_over_self);
  615. CHECK_FALSE(node_j->mouse_over);
  616. CHECK_FALSE(node_j->mouse_over_self);
  617. CHECK_FALSE(node_h->invalid_order);
  618. CHECK_FALSE(node_i->invalid_order);
  619. CHECK_FALSE(node_j->invalid_order);
  620. node_i->set_mouse_filter(Control::MOUSE_FILTER_STOP);
  621. node_j->set_mouse_filter(Control::MOUSE_FILTER_STOP);
  622. }
  623. SUBCASE("[Viewport][GuiInputEvent] Mouse Enter/Exit notification propagation with mouse filter ignore.") {
  624. node_i->set_mouse_filter(Control::MOUSE_FILTER_IGNORE);
  625. node_j->set_mouse_filter(Control::MOUSE_FILTER_PASS);
  626. // Move to background.
  627. SEND_GUI_MOUSE_MOTION_EVENT(on_background, MouseButtonMask::NONE, Key::NONE);
  628. CHECK_FALSE(node_h->mouse_over);
  629. CHECK_FALSE(node_h->mouse_over_self);
  630. CHECK_FALSE(node_i->mouse_over);
  631. CHECK_FALSE(node_i->mouse_over_self);
  632. CHECK_FALSE(node_j->mouse_over);
  633. CHECK_FALSE(node_j->mouse_over_self);
  634. // Move to Control node_j. node_i does not receive mouse over since node_i is MOUSE_FILTER_IGNORE.
  635. SEND_GUI_MOUSE_MOTION_EVENT(on_j, MouseButtonMask::NONE, Key::NONE);
  636. CHECK(node_h->mouse_over);
  637. CHECK_FALSE(node_h->mouse_over_self);
  638. CHECK_FALSE(node_i->mouse_over);
  639. CHECK_FALSE(node_i->mouse_over_self);
  640. CHECK(node_j->mouse_over);
  641. CHECK(node_j->mouse_over_self);
  642. // Move to background.
  643. SEND_GUI_MOUSE_MOTION_EVENT(on_background, MouseButtonMask::NONE, Key::NONE);
  644. CHECK_FALSE(node_h->mouse_over);
  645. CHECK_FALSE(node_h->mouse_over_self);
  646. CHECK_FALSE(node_i->mouse_over);
  647. CHECK_FALSE(node_i->mouse_over_self);
  648. CHECK_FALSE(node_j->mouse_over);
  649. CHECK_FALSE(node_j->mouse_over_self);
  650. CHECK_FALSE(node_h->invalid_order);
  651. CHECK_FALSE(node_i->invalid_order);
  652. CHECK_FALSE(node_j->invalid_order);
  653. node_i->set_mouse_filter(Control::MOUSE_FILTER_STOP);
  654. node_j->set_mouse_filter(Control::MOUSE_FILTER_STOP);
  655. }
  656. SUBCASE("[Viewport][GuiInputEvent] Mouse Enter/Exit notification when changing top level.") {
  657. SIGNAL_WATCH(node_i, SceneStringName(mouse_entered));
  658. SIGNAL_WATCH(node_i, SceneStringName(mouse_exited));
  659. Array signal_args;
  660. signal_args.push_back(Array());
  661. node_d->set_mouse_filter(Control::MOUSE_FILTER_PASS);
  662. node_i->set_mouse_filter(Control::MOUSE_FILTER_PASS);
  663. node_j->set_mouse_filter(Control::MOUSE_FILTER_PASS);
  664. // Move to Control node_d.
  665. SEND_GUI_MOUSE_MOTION_EVENT(on_d, MouseButtonMask::NONE, Key::NONE);
  666. CHECK(node_b->mouse_over);
  667. CHECK_FALSE(node_b->mouse_over_self);
  668. CHECK(node_d->mouse_over);
  669. CHECK(node_d->mouse_over_self);
  670. // Change node_c to be top level. node_b should receive Mouse Exit.
  671. node_c->set_as_top_level(true);
  672. CHECK_FALSE(node_b->mouse_over);
  673. CHECK_FALSE(node_b->mouse_over_self);
  674. CHECK(node_d->mouse_over);
  675. CHECK(node_d->mouse_over_self);
  676. // Change node_c to be not top level. node_b should receive Mouse Enter.
  677. node_c->set_as_top_level(false);
  678. CHECK(node_b->mouse_over);
  679. CHECK_FALSE(node_b->mouse_over_self);
  680. CHECK(node_d->mouse_over);
  681. CHECK(node_d->mouse_over_self);
  682. // Move to Control node_j.
  683. SEND_GUI_MOUSE_MOTION_EVENT(on_j, MouseButtonMask::NONE, Key::NONE);
  684. CHECK(node_h->mouse_over);
  685. CHECK_FALSE(node_h->mouse_over_self);
  686. CHECK(node_i->mouse_over);
  687. CHECK_FALSE(node_i->mouse_over_self);
  688. CHECK(node_j->mouse_over);
  689. CHECK(node_j->mouse_over_self);
  690. SIGNAL_CHECK(SceneStringName(mouse_entered), signal_args);
  691. SIGNAL_CHECK_FALSE(SceneStringName(mouse_exited));
  692. // Change node_i to top level. node_h should receive Mouse Exit. node_i should not receive any new signals.
  693. node_i->set_as_top_level(true);
  694. CHECK_FALSE(node_h->mouse_over);
  695. CHECK_FALSE(node_h->mouse_over_self);
  696. CHECK(node_i->mouse_over);
  697. CHECK_FALSE(node_i->mouse_over_self);
  698. CHECK(node_j->mouse_over);
  699. CHECK(node_j->mouse_over_self);
  700. SIGNAL_CHECK_FALSE(SceneStringName(mouse_entered));
  701. SIGNAL_CHECK_FALSE(SceneStringName(mouse_exited));
  702. // Change node_i to not top level. node_h should receive Mouse Enter. node_i should not receive any new signals.
  703. node_i->set_as_top_level(false);
  704. CHECK(node_h->mouse_over);
  705. CHECK_FALSE(node_h->mouse_over_self);
  706. CHECK(node_i->mouse_over);
  707. CHECK_FALSE(node_i->mouse_over_self);
  708. CHECK(node_j->mouse_over);
  709. CHECK(node_j->mouse_over_self);
  710. SIGNAL_CHECK_FALSE(SceneStringName(mouse_entered));
  711. SIGNAL_CHECK_FALSE(SceneStringName(mouse_exited));
  712. CHECK_FALSE(node_b->invalid_order);
  713. CHECK_FALSE(node_d->invalid_order);
  714. CHECK_FALSE(node_e->invalid_order);
  715. CHECK_FALSE(node_h->invalid_order);
  716. CHECK_FALSE(node_i->invalid_order);
  717. CHECK_FALSE(node_j->invalid_order);
  718. node_d->set_mouse_filter(Control::MOUSE_FILTER_STOP);
  719. node_i->set_mouse_filter(Control::MOUSE_FILTER_STOP);
  720. node_j->set_mouse_filter(Control::MOUSE_FILTER_STOP);
  721. SIGNAL_UNWATCH(node_i, SceneStringName(mouse_entered));
  722. SIGNAL_UNWATCH(node_i, SceneStringName(mouse_exited));
  723. }
  724. SUBCASE("[Viewport][GuiInputEvent] Mouse Enter/Exit notification when changing the mouse filter to stop.") {
  725. SIGNAL_WATCH(node_i, SceneStringName(mouse_entered));
  726. SIGNAL_WATCH(node_i, SceneStringName(mouse_exited));
  727. Array signal_args;
  728. signal_args.push_back(Array());
  729. node_i->set_mouse_filter(Control::MOUSE_FILTER_PASS);
  730. node_j->set_mouse_filter(Control::MOUSE_FILTER_PASS);
  731. // Move to Control node_j.
  732. SEND_GUI_MOUSE_MOTION_EVENT(on_j, MouseButtonMask::NONE, Key::NONE);
  733. CHECK(node_h->mouse_over);
  734. CHECK_FALSE(node_h->mouse_over_self);
  735. CHECK(node_i->mouse_over);
  736. CHECK_FALSE(node_i->mouse_over_self);
  737. CHECK(node_j->mouse_over);
  738. CHECK(node_j->mouse_over_self);
  739. SIGNAL_CHECK(SceneStringName(mouse_entered), signal_args);
  740. SIGNAL_CHECK_FALSE(SceneStringName(mouse_exited));
  741. // Change node_i to MOUSE_FILTER_STOP. node_h should receive Mouse Exit. node_i should not receive any new signals.
  742. node_i->set_mouse_filter(Control::MOUSE_FILTER_STOP);
  743. CHECK_FALSE(node_h->mouse_over);
  744. CHECK_FALSE(node_h->mouse_over_self);
  745. CHECK(node_i->mouse_over);
  746. CHECK_FALSE(node_i->mouse_over_self);
  747. CHECK(node_j->mouse_over);
  748. CHECK(node_j->mouse_over_self);
  749. SIGNAL_CHECK_FALSE(SceneStringName(mouse_entered));
  750. SIGNAL_CHECK_FALSE(SceneStringName(mouse_exited));
  751. // Change node_i to MOUSE_FILTER_PASS. node_h should receive Mouse Enter. node_i should not receive any new signals.
  752. node_i->set_mouse_filter(Control::MOUSE_FILTER_PASS);
  753. CHECK(node_h->mouse_over);
  754. CHECK_FALSE(node_h->mouse_over_self);
  755. CHECK(node_i->mouse_over);
  756. CHECK_FALSE(node_i->mouse_over_self);
  757. CHECK(node_j->mouse_over);
  758. CHECK(node_j->mouse_over_self);
  759. SIGNAL_CHECK_FALSE(SceneStringName(mouse_entered));
  760. SIGNAL_CHECK_FALSE(SceneStringName(mouse_exited));
  761. CHECK_FALSE(node_h->invalid_order);
  762. CHECK_FALSE(node_i->invalid_order);
  763. CHECK_FALSE(node_j->invalid_order);
  764. node_i->set_mouse_filter(Control::MOUSE_FILTER_STOP);
  765. node_j->set_mouse_filter(Control::MOUSE_FILTER_STOP);
  766. SIGNAL_UNWATCH(node_i, SceneStringName(mouse_entered));
  767. SIGNAL_UNWATCH(node_i, SceneStringName(mouse_exited));
  768. }
  769. SUBCASE("[Viewport][GuiInputEvent] Mouse Enter/Exit notification when changing the mouse filter to ignore.") {
  770. SIGNAL_WATCH(node_i, SceneStringName(mouse_entered));
  771. SIGNAL_WATCH(node_i, SceneStringName(mouse_exited));
  772. Array signal_args;
  773. signal_args.push_back(Array());
  774. node_i->set_mouse_filter(Control::MOUSE_FILTER_PASS);
  775. node_j->set_mouse_filter(Control::MOUSE_FILTER_PASS);
  776. // Move to Control node_j.
  777. SEND_GUI_MOUSE_MOTION_EVENT(on_j, MouseButtonMask::NONE, Key::NONE);
  778. CHECK(node_h->mouse_over);
  779. CHECK_FALSE(node_h->mouse_over_self);
  780. CHECK(node_i->mouse_over);
  781. CHECK_FALSE(node_i->mouse_over_self);
  782. CHECK(node_j->mouse_over);
  783. CHECK(node_j->mouse_over_self);
  784. SIGNAL_CHECK(SceneStringName(mouse_entered), signal_args);
  785. SIGNAL_CHECK_FALSE(SceneStringName(mouse_exited));
  786. // Change node_i to MOUSE_FILTER_IGNORE. node_i should receive Mouse Exit.
  787. node_i->set_mouse_filter(Control::MOUSE_FILTER_IGNORE);
  788. CHECK(node_h->mouse_over);
  789. CHECK_FALSE(node_h->mouse_over_self);
  790. CHECK_FALSE(node_i->mouse_over);
  791. CHECK_FALSE(node_i->mouse_over_self);
  792. CHECK(node_j->mouse_over);
  793. CHECK(node_j->mouse_over_self);
  794. SIGNAL_CHECK_FALSE(SceneStringName(mouse_entered));
  795. SIGNAL_CHECK(SceneStringName(mouse_exited), signal_args);
  796. // Change node_i to MOUSE_FILTER_PASS. node_i should receive Mouse Enter.
  797. node_i->set_mouse_filter(Control::MOUSE_FILTER_PASS);
  798. CHECK(node_h->mouse_over);
  799. CHECK_FALSE(node_h->mouse_over_self);
  800. CHECK(node_i->mouse_over);
  801. CHECK_FALSE(node_i->mouse_over_self);
  802. CHECK(node_j->mouse_over);
  803. CHECK(node_j->mouse_over_self);
  804. SIGNAL_CHECK(SceneStringName(mouse_entered), signal_args);
  805. SIGNAL_CHECK_FALSE(SceneStringName(mouse_exited));
  806. // Change node_j to MOUSE_FILTER_IGNORE. After updating the mouse motion, node_i should now have mouse_over_self.
  807. node_j->set_mouse_filter(Control::MOUSE_FILTER_IGNORE);
  808. SEND_GUI_MOUSE_MOTION_EVENT(on_j, MouseButtonMask::NONE, Key::NONE);
  809. CHECK(node_h->mouse_over);
  810. CHECK_FALSE(node_h->mouse_over_self);
  811. CHECK(node_i->mouse_over);
  812. CHECK(node_i->mouse_over_self);
  813. CHECK_FALSE(node_j->mouse_over);
  814. CHECK_FALSE(node_j->mouse_over_self);
  815. SIGNAL_CHECK_FALSE(SceneStringName(mouse_entered));
  816. SIGNAL_CHECK_FALSE(SceneStringName(mouse_exited));
  817. // Change node_j to MOUSE_FILTER_PASS. After updating the mouse motion, node_j should now have mouse_over_self.
  818. node_j->set_mouse_filter(Control::MOUSE_FILTER_PASS);
  819. SEND_GUI_MOUSE_MOTION_EVENT(on_j, MouseButtonMask::NONE, Key::NONE);
  820. CHECK(node_h->mouse_over);
  821. CHECK_FALSE(node_h->mouse_over_self);
  822. CHECK(node_i->mouse_over);
  823. CHECK_FALSE(node_i->mouse_over_self);
  824. CHECK(node_j->mouse_over);
  825. CHECK(node_j->mouse_over_self);
  826. SIGNAL_CHECK_FALSE(SceneStringName(mouse_entered));
  827. SIGNAL_CHECK_FALSE(SceneStringName(mouse_exited));
  828. CHECK_FALSE(node_h->invalid_order);
  829. CHECK_FALSE(node_i->invalid_order);
  830. CHECK_FALSE(node_j->invalid_order);
  831. node_i->set_mouse_filter(Control::MOUSE_FILTER_STOP);
  832. node_j->set_mouse_filter(Control::MOUSE_FILTER_STOP);
  833. SIGNAL_UNWATCH(node_i, SceneStringName(mouse_entered));
  834. SIGNAL_UNWATCH(node_i, SceneStringName(mouse_exited));
  835. }
  836. SUBCASE("[Viewport][GuiInputEvent] Mouse Enter/Exit notification when removing the hovered Control.") {
  837. SIGNAL_WATCH(node_h, SceneStringName(mouse_entered));
  838. SIGNAL_WATCH(node_h, SceneStringName(mouse_exited));
  839. Array signal_args;
  840. signal_args.push_back(Array());
  841. node_i->set_mouse_filter(Control::MOUSE_FILTER_PASS);
  842. node_j->set_mouse_filter(Control::MOUSE_FILTER_PASS);
  843. // Move to Control node_j.
  844. SEND_GUI_MOUSE_MOTION_EVENT(on_j, MouseButtonMask::NONE, Key::NONE);
  845. CHECK(node_h->mouse_over);
  846. CHECK_FALSE(node_h->mouse_over_self);
  847. CHECK(node_i->mouse_over);
  848. CHECK_FALSE(node_i->mouse_over_self);
  849. CHECK(node_j->mouse_over);
  850. CHECK(node_j->mouse_over_self);
  851. SIGNAL_CHECK(SceneStringName(mouse_entered), signal_args);
  852. SIGNAL_CHECK_FALSE(SceneStringName(mouse_exited));
  853. // Remove node_i from the tree. node_i and node_j should receive Mouse Exit. node_h should not receive any new signals.
  854. node_h->remove_child(node_i);
  855. CHECK(node_h->mouse_over);
  856. CHECK_FALSE(node_h->mouse_over_self);
  857. CHECK_FALSE(node_i->mouse_over);
  858. CHECK_FALSE(node_i->mouse_over_self);
  859. CHECK_FALSE(node_j->mouse_over);
  860. CHECK_FALSE(node_j->mouse_over_self);
  861. SIGNAL_CHECK_FALSE(SceneStringName(mouse_entered));
  862. SIGNAL_CHECK_FALSE(SceneStringName(mouse_exited));
  863. // Add node_i to the tree and update the mouse. node_i and node_j should receive Mouse Enter. node_h should not receive any new signals.
  864. node_h->add_child(node_i);
  865. SEND_GUI_MOUSE_MOTION_EVENT(on_j, MouseButtonMask::NONE, Key::NONE);
  866. CHECK(node_h->mouse_over);
  867. CHECK_FALSE(node_h->mouse_over_self);
  868. CHECK(node_i->mouse_over);
  869. CHECK_FALSE(node_i->mouse_over_self);
  870. CHECK(node_j->mouse_over);
  871. CHECK(node_j->mouse_over_self);
  872. SIGNAL_CHECK_FALSE(SceneStringName(mouse_entered));
  873. SIGNAL_CHECK_FALSE(SceneStringName(mouse_exited));
  874. CHECK_FALSE(node_h->invalid_order);
  875. CHECK_FALSE(node_i->invalid_order);
  876. CHECK_FALSE(node_j->invalid_order);
  877. node_i->set_mouse_filter(Control::MOUSE_FILTER_STOP);
  878. node_j->set_mouse_filter(Control::MOUSE_FILTER_STOP);
  879. SIGNAL_UNWATCH(node_h, SceneStringName(mouse_entered));
  880. SIGNAL_UNWATCH(node_h, SceneStringName(mouse_exited));
  881. }
  882. SUBCASE("[Viewport][GuiInputEvent] Mouse Enter/Exit notification when hiding the hovered Control.") {
  883. SIGNAL_WATCH(node_h, SceneStringName(mouse_entered));
  884. SIGNAL_WATCH(node_h, SceneStringName(mouse_exited));
  885. Array signal_args;
  886. signal_args.push_back(Array());
  887. node_i->set_mouse_filter(Control::MOUSE_FILTER_PASS);
  888. node_j->set_mouse_filter(Control::MOUSE_FILTER_PASS);
  889. // Move to Control node_j.
  890. SEND_GUI_MOUSE_MOTION_EVENT(on_j, MouseButtonMask::NONE, Key::NONE);
  891. CHECK(node_h->mouse_over);
  892. CHECK_FALSE(node_h->mouse_over_self);
  893. CHECK(node_i->mouse_over);
  894. CHECK_FALSE(node_i->mouse_over_self);
  895. CHECK(node_j->mouse_over);
  896. CHECK(node_j->mouse_over_self);
  897. SIGNAL_CHECK(SceneStringName(mouse_entered), signal_args);
  898. SIGNAL_CHECK_FALSE(SceneStringName(mouse_exited));
  899. // Hide node_i. node_i and node_j should receive Mouse Exit. node_h should not receive any new signals.
  900. node_i->hide();
  901. CHECK(node_h->mouse_over);
  902. CHECK_FALSE(node_h->mouse_over_self);
  903. CHECK_FALSE(node_i->mouse_over);
  904. CHECK_FALSE(node_i->mouse_over_self);
  905. CHECK_FALSE(node_j->mouse_over);
  906. CHECK_FALSE(node_j->mouse_over_self);
  907. SIGNAL_CHECK_FALSE(SceneStringName(mouse_entered));
  908. SIGNAL_CHECK_FALSE(SceneStringName(mouse_exited));
  909. // Show node_i and update the mouse. node_i and node_j should receive Mouse Enter. node_h should not receive any new signals.
  910. node_i->show();
  911. SEND_GUI_MOUSE_MOTION_EVENT(on_j, MouseButtonMask::NONE, Key::NONE);
  912. CHECK(node_h->mouse_over);
  913. CHECK_FALSE(node_h->mouse_over_self);
  914. CHECK(node_i->mouse_over);
  915. CHECK_FALSE(node_i->mouse_over_self);
  916. CHECK(node_j->mouse_over);
  917. CHECK(node_j->mouse_over_self);
  918. SIGNAL_CHECK_FALSE(SceneStringName(mouse_entered));
  919. SIGNAL_CHECK_FALSE(SceneStringName(mouse_exited));
  920. CHECK_FALSE(node_h->invalid_order);
  921. CHECK_FALSE(node_i->invalid_order);
  922. CHECK_FALSE(node_j->invalid_order);
  923. node_i->set_mouse_filter(Control::MOUSE_FILTER_STOP);
  924. node_j->set_mouse_filter(Control::MOUSE_FILTER_STOP);
  925. SIGNAL_UNWATCH(node_h, SceneStringName(mouse_entered));
  926. SIGNAL_UNWATCH(node_h, SceneStringName(mouse_exited));
  927. }
  928. SUBCASE("[Viewport][GuiInputEvent] Window Mouse Enter/Exit signals.") {
  929. SIGNAL_WATCH(root, SceneStringName(mouse_entered));
  930. SIGNAL_WATCH(root, SceneStringName(mouse_exited));
  931. Array signal_args;
  932. signal_args.push_back(Array());
  933. SEND_GUI_MOUSE_MOTION_EVENT(on_outside, MouseButtonMask::NONE, Key::NONE);
  934. SIGNAL_CHECK_FALSE(SceneStringName(mouse_entered));
  935. SIGNAL_CHECK(SceneStringName(mouse_exited), signal_args);
  936. SEND_GUI_MOUSE_MOTION_EVENT(on_a, MouseButtonMask::NONE, Key::NONE);
  937. SIGNAL_CHECK(SceneStringName(mouse_entered), signal_args);
  938. SIGNAL_CHECK_FALSE(SceneStringName(mouse_exited));
  939. SIGNAL_UNWATCH(root, SceneStringName(mouse_entered));
  940. SIGNAL_UNWATCH(root, SceneStringName(mouse_exited));
  941. }
  942. SUBCASE("[Viewport][GuiInputEvent] Process-Mode affects, if GUI Mouse Motion Events are processed.") {
  943. node_a->last_mouse_move_position = on_outside;
  944. node_a->set_process_mode(Node::PROCESS_MODE_DISABLED);
  945. SEND_GUI_MOUSE_MOTION_EVENT(on_a, MouseButtonMask::NONE, Key::NONE);
  946. CHECK(node_a->last_mouse_move_position == on_outside);
  947. // Now verify that with allowed processing the event is processed.
  948. node_a->set_process_mode(Node::PROCESS_MODE_ALWAYS);
  949. SEND_GUI_MOUSE_MOTION_EVENT(on_a, MouseButtonMask::NONE, Key::NONE);
  950. CHECK(node_a->last_mouse_move_position == on_a);
  951. }
  952. }
  953. // Unit tests for Viewport::_gui_input_event (Drag and Drop)
  954. SUBCASE("[Viewport][GuiInputEvent] Drag and Drop") {
  955. // FIXME: Drag-Preview will likely change. Tests for this part would have to be rewritten anyway.
  956. // See https://github.com/godotengine/godot/pull/67531#issuecomment-1385353430 for details.
  957. // Note: Testing Drag and Drop with non-embedded windows would require DisplayServerMock additions.
  958. int min_grab_movement = 11;
  959. SUBCASE("[Viewport][GuiInputEvent][DnD] Drag from one Control to another in the same viewport.") {
  960. SUBCASE("[Viewport][GuiInputEvent][DnD] Perform successful Drag and Drop on a different Control.") {
  961. SEND_GUI_MOUSE_BUTTON_EVENT(on_a, MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
  962. CHECK_FALSE(root->gui_is_dragging());
  963. SEND_GUI_MOUSE_MOTION_EVENT(on_a + Point2i(min_grab_movement, 0), MouseButtonMask::LEFT, Key::NONE);
  964. CHECK(root->gui_is_dragging());
  965. // Move above a Control, that is a Drop target and allows dropping at this point.
  966. SEND_GUI_MOUSE_MOTION_EVENT(on_d, MouseButtonMask::LEFT, Key::NONE);
  967. CHECK(DS->get_cursor_shape() == DisplayServer::CURSOR_CAN_DROP);
  968. CHECK(root->gui_is_dragging());
  969. CHECK_FALSE(root->gui_is_drag_successful());
  970. SEND_GUI_MOUSE_BUTTON_RELEASED_EVENT(on_d, MouseButton::LEFT, MouseButtonMask::NONE, Key::NONE);
  971. CHECK_FALSE(root->gui_is_dragging());
  972. CHECK(root->gui_is_drag_successful());
  973. CHECK((StringName)node_d->drag_data == SNAME("Drag Data"));
  974. }
  975. SUBCASE("[Viewport][GuiInputEvent][DnD] Perform unsuccessful drop on Control.") {
  976. SEND_GUI_MOUSE_BUTTON_EVENT(on_a, MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
  977. CHECK_FALSE(root->gui_is_dragging());
  978. // Move, but don't trigger DnD yet.
  979. SEND_GUI_MOUSE_MOTION_EVENT(on_a + Point2i(0, min_grab_movement - 1), MouseButtonMask::LEFT, Key::NONE);
  980. CHECK_FALSE(root->gui_is_dragging());
  981. // Move and trigger DnD.
  982. SEND_GUI_MOUSE_MOTION_EVENT(on_a + Point2i(0, min_grab_movement), MouseButtonMask::LEFT, Key::NONE);
  983. CHECK(root->gui_is_dragging());
  984. // Move above a Control, that is not a Drop target.
  985. SEND_GUI_MOUSE_MOTION_EVENT(on_a, MouseButtonMask::LEFT, Key::NONE);
  986. CHECK(DS->get_cursor_shape() == DisplayServer::CURSOR_FORBIDDEN);
  987. // Move above a Control, that is a Drop target, but has disallowed this point.
  988. SEND_GUI_MOUSE_MOTION_EVENT(on_d + Point2i(20, 0), MouseButtonMask::LEFT, Key::NONE);
  989. CHECK(DS->get_cursor_shape() == DisplayServer::CURSOR_FORBIDDEN);
  990. CHECK(root->gui_is_dragging());
  991. SEND_GUI_MOUSE_BUTTON_RELEASED_EVENT(on_d + Point2i(20, 0), MouseButton::LEFT, MouseButtonMask::NONE, Key::NONE);
  992. CHECK_FALSE(root->gui_is_dragging());
  993. CHECK_FALSE(root->gui_is_drag_successful());
  994. }
  995. SUBCASE("[Viewport][GuiInputEvent][DnD] Perform unsuccessful drop on No-Control.") {
  996. SEND_GUI_MOUSE_BUTTON_EVENT(on_a, MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
  997. CHECK_FALSE(root->gui_is_dragging());
  998. // Move, but don't trigger DnD yet.
  999. SEND_GUI_MOUSE_MOTION_EVENT(on_a + Point2i(min_grab_movement - 1, 0), MouseButtonMask::LEFT, Key::NONE);
  1000. CHECK_FALSE(root->gui_is_dragging());
  1001. // Move and trigger DnD.
  1002. SEND_GUI_MOUSE_MOTION_EVENT(on_a + Point2i(min_grab_movement, 0), MouseButtonMask::LEFT, Key::NONE);
  1003. CHECK(root->gui_is_dragging());
  1004. // Move away from Controls.
  1005. SEND_GUI_MOUSE_MOTION_EVENT(on_background, MouseButtonMask::LEFT, Key::NONE);
  1006. CHECK(DS->get_cursor_shape() == DisplayServer::CURSOR_ARROW);
  1007. CHECK(root->gui_is_dragging());
  1008. SEND_GUI_MOUSE_BUTTON_RELEASED_EVENT(on_background, MouseButton::LEFT, MouseButtonMask::NONE, Key::NONE);
  1009. CHECK_FALSE(root->gui_is_dragging());
  1010. CHECK_FALSE(root->gui_is_drag_successful());
  1011. }
  1012. SUBCASE("[Viewport][GuiInputEvent][DnD] Perform unsuccessful drop outside of window.") {
  1013. SEND_GUI_MOUSE_BUTTON_EVENT(on_a, MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
  1014. CHECK_FALSE(root->gui_is_dragging());
  1015. // Move and trigger DnD.
  1016. SEND_GUI_MOUSE_MOTION_EVENT(on_a + Point2i(min_grab_movement, 0), MouseButtonMask::LEFT, Key::NONE);
  1017. CHECK(root->gui_is_dragging());
  1018. SEND_GUI_MOUSE_MOTION_EVENT(on_d, MouseButtonMask::LEFT, Key::NONE);
  1019. CHECK(DS->get_cursor_shape() == DisplayServer::CURSOR_CAN_DROP);
  1020. // Move outside of window.
  1021. SEND_GUI_MOUSE_MOTION_EVENT(on_outside, MouseButtonMask::LEFT, Key::NONE);
  1022. CHECK(root->gui_is_dragging());
  1023. SEND_GUI_MOUSE_BUTTON_RELEASED_EVENT(on_outside, MouseButton::LEFT, MouseButtonMask::NONE, Key::NONE);
  1024. CHECK_FALSE(root->gui_is_dragging());
  1025. CHECK_FALSE(root->gui_is_drag_successful());
  1026. }
  1027. SUBCASE("[Viewport][GuiInputEvent][DnD] Drag and Drop doesn't work with other Mouse Buttons than LMB.") {
  1028. SEND_GUI_MOUSE_BUTTON_EVENT(on_a, MouseButton::MIDDLE, MouseButtonMask::MIDDLE, Key::NONE);
  1029. CHECK_FALSE(root->gui_is_dragging());
  1030. SEND_GUI_MOUSE_MOTION_EVENT(on_a + Point2i(min_grab_movement, 0), MouseButtonMask::MIDDLE, Key::NONE);
  1031. CHECK_FALSE(root->gui_is_dragging());
  1032. SEND_GUI_MOUSE_BUTTON_RELEASED_EVENT(on_a, MouseButton::MIDDLE, MouseButtonMask::NONE, Key::NONE);
  1033. }
  1034. SUBCASE("[Viewport][GuiInputEvent][DnD] Drag and Drop parent propagation.") {
  1035. Node2D *node_aa = memnew(Node2D);
  1036. Control *node_aaa = memnew(Control);
  1037. Node2D *node_dd = memnew(Node2D);
  1038. Control *node_ddd = memnew(Control);
  1039. node_aaa->set_size(Size2i(10, 10));
  1040. node_aaa->set_position(Point2i(0, 5));
  1041. node_ddd->set_size(Size2i(10, 10));
  1042. node_ddd->set_position(Point2i(0, 5));
  1043. node_a->add_child(node_aa);
  1044. node_aa->add_child(node_aaa);
  1045. node_d->add_child(node_dd);
  1046. node_dd->add_child(node_ddd);
  1047. Point2i on_aaa = on_a + Point2i(-2, 2);
  1048. Point2i on_ddd = on_d + Point2i(-2, 2);
  1049. SUBCASE("[Viewport][GuiInputEvent] Drag and Drop propagation to parent Controls.") {
  1050. node_aaa->set_mouse_filter(Control::MOUSE_FILTER_PASS);
  1051. node_ddd->set_mouse_filter(Control::MOUSE_FILTER_PASS);
  1052. SEND_GUI_MOUSE_BUTTON_EVENT(on_aaa, MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
  1053. CHECK_FALSE(root->gui_is_dragging());
  1054. SEND_GUI_MOUSE_MOTION_EVENT(on_aaa + Point2i(0, min_grab_movement), MouseButtonMask::LEFT, Key::NONE);
  1055. CHECK(root->gui_is_dragging());
  1056. SEND_GUI_MOUSE_MOTION_EVENT(on_ddd, MouseButtonMask::LEFT, Key::NONE);
  1057. CHECK(root->gui_is_dragging());
  1058. CHECK_FALSE(root->gui_is_drag_successful());
  1059. SEND_GUI_MOUSE_BUTTON_RELEASED_EVENT(on_ddd, MouseButton::LEFT, MouseButtonMask::NONE, Key::NONE);
  1060. CHECK_FALSE(root->gui_is_dragging());
  1061. CHECK(root->gui_is_drag_successful());
  1062. node_aaa->set_mouse_filter(Control::MOUSE_FILTER_STOP);
  1063. node_ddd->set_mouse_filter(Control::MOUSE_FILTER_STOP);
  1064. }
  1065. SUBCASE("[Viewport][GuiInputEvent] Drag and Drop grab-propagation stopped by Top Level.") {
  1066. node_aaa->set_mouse_filter(Control::MOUSE_FILTER_PASS);
  1067. node_aaa->set_as_top_level(true);
  1068. SEND_GUI_MOUSE_BUTTON_EVENT(on_aaa, MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
  1069. CHECK_FALSE(root->gui_is_dragging());
  1070. SEND_GUI_MOUSE_MOTION_EVENT(on_aaa + Point2i(0, min_grab_movement), MouseButtonMask::LEFT, Key::NONE);
  1071. CHECK_FALSE(root->gui_is_dragging());
  1072. SEND_GUI_MOUSE_BUTTON_RELEASED_EVENT(on_background, MouseButton::LEFT, MouseButtonMask::NONE, Key::NONE);
  1073. node_aaa->set_as_top_level(false);
  1074. node_aaa->set_mouse_filter(Control::MOUSE_FILTER_STOP);
  1075. }
  1076. SUBCASE("[Viewport][GuiInputEvent] Drag and Drop target-propagation stopped by Top Level.") {
  1077. node_aaa->set_mouse_filter(Control::MOUSE_FILTER_PASS);
  1078. node_ddd->set_mouse_filter(Control::MOUSE_FILTER_PASS);
  1079. node_ddd->set_as_top_level(true);
  1080. node_ddd->set_position(Point2i(30, 100));
  1081. SEND_GUI_MOUSE_BUTTON_EVENT(on_aaa, MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
  1082. CHECK_FALSE(root->gui_is_dragging());
  1083. SEND_GUI_MOUSE_MOTION_EVENT(on_aaa + Point2i(0, min_grab_movement), MouseButtonMask::LEFT, Key::NONE);
  1084. CHECK(root->gui_is_dragging());
  1085. SEND_GUI_MOUSE_MOTION_EVENT(Point2i(35, 105), MouseButtonMask::LEFT, Key::NONE);
  1086. CHECK(root->gui_is_dragging());
  1087. SEND_GUI_MOUSE_BUTTON_RELEASED_EVENT(Point2i(35, 105), MouseButton::LEFT, MouseButtonMask::NONE, Key::NONE);
  1088. CHECK_FALSE(root->gui_is_dragging());
  1089. CHECK_FALSE(root->gui_is_drag_successful());
  1090. node_ddd->set_position(Point2i(0, 5));
  1091. node_ddd->set_as_top_level(false);
  1092. node_aaa->set_mouse_filter(Control::MOUSE_FILTER_STOP);
  1093. node_ddd->set_mouse_filter(Control::MOUSE_FILTER_STOP);
  1094. }
  1095. SUBCASE("[Viewport][GuiInputEvent] Drag and Drop grab-propagation stopped by non-CanvasItem.") {
  1096. node_g->set_mouse_filter(Control::MOUSE_FILTER_PASS);
  1097. SEND_GUI_MOUSE_BUTTON_EVENT(on_g, MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
  1098. SEND_GUI_MOUSE_MOTION_EVENT(on_g + Point2i(0, min_grab_movement), MouseButtonMask::LEFT, Key::NONE);
  1099. CHECK_FALSE(root->gui_is_dragging());
  1100. SEND_GUI_MOUSE_BUTTON_RELEASED_EVENT(on_background, MouseButton::LEFT, MouseButtonMask::NONE, Key::NONE);
  1101. node_g->set_mouse_filter(Control::MOUSE_FILTER_STOP);
  1102. }
  1103. SUBCASE("[Viewport][GuiInputEvent] Drag and Drop target-propagation stopped by non-CanvasItem.") {
  1104. node_g->set_mouse_filter(Control::MOUSE_FILTER_PASS);
  1105. SEND_GUI_MOUSE_BUTTON_EVENT(on_a - Point2i(1, 1), MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE); // Offset for node_aaa.
  1106. SEND_GUI_MOUSE_MOTION_EVENT(on_a + Point2i(0, min_grab_movement), MouseButtonMask::LEFT, Key::NONE);
  1107. CHECK(root->gui_is_dragging());
  1108. SEND_GUI_MOUSE_MOTION_EVENT(on_g, MouseButtonMask::LEFT, Key::NONE);
  1109. SEND_GUI_MOUSE_BUTTON_RELEASED_EVENT(on_g, MouseButton::LEFT, MouseButtonMask::NONE, Key::NONE);
  1110. CHECK_FALSE(root->gui_is_dragging());
  1111. node_g->set_mouse_filter(Control::MOUSE_FILTER_STOP);
  1112. }
  1113. memdelete(node_ddd);
  1114. memdelete(node_dd);
  1115. memdelete(node_aaa);
  1116. memdelete(node_aa);
  1117. }
  1118. SUBCASE("[Viewport][GuiInputEvent][DnD] Force Drag and Drop.") {
  1119. SEND_GUI_MOUSE_MOTION_EVENT(on_background, MouseButtonMask::NONE, Key::NONE);
  1120. CHECK_FALSE(root->gui_is_dragging());
  1121. node_a->force_drag(SNAME("Drag Data"), nullptr);
  1122. CHECK(root->gui_is_dragging());
  1123. SEND_GUI_MOUSE_MOTION_EVENT(on_d, MouseButtonMask::NONE, Key::NONE);
  1124. // Force Drop doesn't get triggered by mouse Buttons other than LMB.
  1125. SEND_GUI_MOUSE_BUTTON_EVENT(on_d, MouseButton::RIGHT, MouseButtonMask::RIGHT, Key::NONE);
  1126. SEND_GUI_MOUSE_BUTTON_RELEASED_EVENT(on_a, MouseButton::RIGHT, MouseButtonMask::NONE, Key::NONE);
  1127. CHECK(root->gui_is_dragging());
  1128. // Force Drop with LMB-Down.
  1129. SEND_GUI_MOUSE_BUTTON_EVENT(on_d, MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
  1130. CHECK_FALSE(root->gui_is_dragging());
  1131. CHECK(root->gui_is_drag_successful());
  1132. SEND_GUI_MOUSE_BUTTON_RELEASED_EVENT(on_d, MouseButton::LEFT, MouseButtonMask::NONE, Key::NONE);
  1133. }
  1134. }
  1135. SUBCASE("[Viewport][GuiInputEvent][DnD] Drag to a different Viewport.") {
  1136. SubViewportContainer *svc = memnew(SubViewportContainer);
  1137. svc->set_size(Size2(100, 100));
  1138. svc->set_position(Point2(200, 50));
  1139. root->add_child(svc);
  1140. SubViewport *sv = memnew(SubViewport);
  1141. sv->set_embedding_subwindows(true);
  1142. sv->set_size(Size2i(100, 100));
  1143. svc->add_child(sv);
  1144. DragStart *sv_a = memnew(DragStart);
  1145. sv_a->set_position(Point2(10, 10));
  1146. sv_a->set_size(Size2(10, 10));
  1147. sv->add_child(sv_a);
  1148. Point2i on_sva = Point2i(215, 65);
  1149. DragTarget *sv_b = memnew(DragTarget);
  1150. sv_b->set_position(Point2(30, 30));
  1151. sv_b->set_size(Size2(20, 20));
  1152. sv->add_child(sv_b);
  1153. Point2i on_svb = Point2i(235, 85);
  1154. Window *ew = memnew(Window);
  1155. ew->set_position(Point2(50, 200));
  1156. ew->set_size(Size2(100, 100));
  1157. root->add_child(ew);
  1158. DragStart *ew_a = memnew(DragStart);
  1159. ew_a->set_position(Point2(10, 10));
  1160. ew_a->set_size(Size2(10, 10));
  1161. ew->add_child(ew_a);
  1162. Point2i on_ewa = Point2i(65, 215);
  1163. DragTarget *ew_b = memnew(DragTarget);
  1164. ew_b->set_position(Point2(30, 30));
  1165. ew_b->set_size(Size2(20, 20));
  1166. ew->add_child(ew_b);
  1167. Point2i on_ewb = Point2i(85, 235);
  1168. SUBCASE("[Viewport][GuiInputEvent][DnD] Drag to SubViewport") {
  1169. sv_b->valid_drop = false;
  1170. SEND_GUI_MOUSE_BUTTON_EVENT(on_a, MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
  1171. SEND_GUI_MOUSE_MOTION_EVENT(on_a + Point2i(min_grab_movement, 0), MouseButtonMask::LEFT, Key::NONE);
  1172. CHECK(root->gui_is_dragging());
  1173. CHECK(sv_b->during_drag);
  1174. SEND_GUI_MOUSE_MOTION_EVENT(on_svb, MouseButtonMask::LEFT, Key::NONE);
  1175. CHECK(DS->get_cursor_shape() == DisplayServer::CURSOR_CAN_DROP);
  1176. SEND_GUI_MOUSE_BUTTON_RELEASED_EVENT(on_svb, MouseButton::LEFT, MouseButtonMask::NONE, Key::NONE);
  1177. CHECK(sv_b->valid_drop);
  1178. CHECK(!sv_b->during_drag);
  1179. }
  1180. SUBCASE("[Viewport][GuiInputEvent][DnD] Drag from SubViewport") {
  1181. node_d->valid_drop = false;
  1182. SEND_GUI_MOUSE_BUTTON_EVENT(on_sva, MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
  1183. SEND_GUI_MOUSE_MOTION_EVENT(on_sva + Point2i(min_grab_movement, 0), MouseButtonMask::LEFT, Key::NONE);
  1184. CHECK(sv->gui_is_dragging());
  1185. CHECK(node_d->during_drag);
  1186. SEND_GUI_MOUSE_MOTION_EVENT(on_d, MouseButtonMask::LEFT, Key::NONE);
  1187. CHECK(DS->get_cursor_shape() == DisplayServer::CURSOR_CAN_DROP);
  1188. SEND_GUI_MOUSE_BUTTON_RELEASED_EVENT(on_d, MouseButton::LEFT, MouseButtonMask::NONE, Key::NONE);
  1189. CHECK(node_d->valid_drop);
  1190. CHECK(!node_d->during_drag);
  1191. }
  1192. SUBCASE("[Viewport][GuiInputEvent][DnD] Drag to embedded Window") {
  1193. ew_b->valid_drop = false;
  1194. SEND_GUI_MOUSE_BUTTON_EVENT(on_a, MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
  1195. SEND_GUI_MOUSE_MOTION_EVENT(on_a + Point2i(min_grab_movement, 0), MouseButtonMask::LEFT, Key::NONE);
  1196. CHECK(root->gui_is_dragging());
  1197. CHECK(ew_b->during_drag);
  1198. SEND_GUI_MOUSE_MOTION_EVENT(on_ewb, MouseButtonMask::LEFT, Key::NONE);
  1199. CHECK(DS->get_cursor_shape() == DisplayServer::CURSOR_CAN_DROP);
  1200. SEND_GUI_MOUSE_BUTTON_RELEASED_EVENT(on_ewb, MouseButton::LEFT, MouseButtonMask::NONE, Key::NONE);
  1201. CHECK(ew_b->valid_drop);
  1202. CHECK(!ew_b->during_drag);
  1203. }
  1204. SUBCASE("[Viewport][GuiInputEvent][DnD] Drag from embedded Window") {
  1205. node_d->valid_drop = false;
  1206. SEND_GUI_MOUSE_BUTTON_EVENT(on_ewa, MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
  1207. SEND_GUI_MOUSE_MOTION_EVENT(on_ewa + Point2i(min_grab_movement, 0), MouseButtonMask::LEFT, Key::NONE);
  1208. CHECK(ew->gui_is_dragging());
  1209. CHECK(node_d->during_drag);
  1210. SEND_GUI_MOUSE_MOTION_EVENT(on_d, MouseButtonMask::LEFT, Key::NONE);
  1211. CHECK(DS->get_cursor_shape() == DisplayServer::CURSOR_CAN_DROP);
  1212. SEND_GUI_MOUSE_BUTTON_RELEASED_EVENT(on_d, MouseButton::LEFT, MouseButtonMask::NONE, Key::NONE);
  1213. CHECK(node_d->valid_drop);
  1214. CHECK(!node_d->during_drag);
  1215. }
  1216. memdelete(ew_a);
  1217. memdelete(ew_b);
  1218. memdelete(ew);
  1219. memdelete(sv_a);
  1220. memdelete(sv_b);
  1221. memdelete(sv);
  1222. memdelete(svc);
  1223. }
  1224. }
  1225. memdelete(node_j);
  1226. memdelete(node_i);
  1227. memdelete(node_h);
  1228. memdelete(node_g);
  1229. memdelete(node_f);
  1230. memdelete(node_e);
  1231. memdelete(node_d);
  1232. memdelete(node_c);
  1233. memdelete(node_b);
  1234. memdelete(node_a);
  1235. }
  1236. TEST_CASE("[SceneTree][Viewport] Control mouse cursor shape") {
  1237. SUBCASE("[Viewport][CursorShape] Mouse cursor is not overridden by SubViewportContainer") {
  1238. SubViewportContainer *node_a = memnew(SubViewportContainer);
  1239. SubViewport *node_b = memnew(SubViewport);
  1240. Control *node_c = memnew(Control);
  1241. node_a->set_name("SubViewportContainer");
  1242. node_b->set_name("SubViewport");
  1243. node_c->set_name("Control");
  1244. node_a->set_position(Point2i(0, 0));
  1245. node_c->set_position(Point2i(0, 0));
  1246. node_a->set_size(Point2i(100, 100));
  1247. node_b->set_size(Point2i(100, 100));
  1248. node_c->set_size(Point2i(100, 100));
  1249. node_a->set_default_cursor_shape(Control::CURSOR_ARROW);
  1250. node_c->set_default_cursor_shape(Control::CURSOR_FORBIDDEN);
  1251. Window *root = SceneTree::get_singleton()->get_root();
  1252. DisplayServerMock *DS = (DisplayServerMock *)(DisplayServer::get_singleton());
  1253. // Scene tree:
  1254. // - root
  1255. // - node_a (SubViewportContainer)
  1256. // - node_b (SubViewport)
  1257. // - node_c (Control)
  1258. root->add_child(node_a);
  1259. node_a->add_child(node_b);
  1260. node_b->add_child(node_c);
  1261. Point2i on_c = Point2i(5, 5);
  1262. SEND_GUI_MOUSE_MOTION_EVENT(on_c, MouseButtonMask::NONE, Key::NONE);
  1263. CHECK(DS->get_cursor_shape() == DisplayServer::CURSOR_FORBIDDEN); // GH-74805
  1264. memdelete(node_c);
  1265. memdelete(node_b);
  1266. memdelete(node_a);
  1267. }
  1268. }
  1269. class TestArea2D : public Area2D {
  1270. GDCLASS(TestArea2D, Area2D);
  1271. void _on_mouse_entered() {
  1272. enter_id = ++TestArea2D::counter; // > 0, if activated.
  1273. }
  1274. void _on_mouse_exited() {
  1275. exit_id = ++TestArea2D::counter; // > 0, if activated.
  1276. }
  1277. void _on_input_event(Node *p_vp, Ref<InputEvent> p_ev, int p_shape) {
  1278. last_input_event = p_ev;
  1279. }
  1280. public:
  1281. static int counter;
  1282. int enter_id = 0;
  1283. int exit_id = 0;
  1284. Ref<InputEvent> last_input_event;
  1285. void init_signals() {
  1286. connect(SceneStringName(mouse_entered), callable_mp(this, &TestArea2D::_on_mouse_entered));
  1287. connect(SceneStringName(mouse_exited), callable_mp(this, &TestArea2D::_on_mouse_exited));
  1288. connect(SceneStringName(input_event), callable_mp(this, &TestArea2D::_on_input_event));
  1289. }
  1290. void test_reset() {
  1291. enter_id = 0;
  1292. exit_id = 0;
  1293. last_input_event.unref();
  1294. }
  1295. };
  1296. int TestArea2D::counter = 0;
  1297. TEST_CASE("[SceneTree][Viewport] Physics Picking 2D") {
  1298. // FIXME: MOUSE_MODE_CAPTURED if-conditions are not testable, because DisplayServerMock doesn't support it.
  1299. // NOTE: This test requires a real physics server.
  1300. PhysicsServer2DDummy *physics_server_2d_dummy = Object::cast_to<PhysicsServer2DDummy>(PhysicsServer2D::get_singleton());
  1301. if (physics_server_2d_dummy) {
  1302. return;
  1303. }
  1304. struct PickingCollider {
  1305. TestArea2D *a;
  1306. CollisionShape2D *c;
  1307. Ref<RectangleShape2D> r;
  1308. };
  1309. SceneTree *tree = SceneTree::get_singleton();
  1310. Window *root = tree->get_root();
  1311. root->set_physics_object_picking(true);
  1312. Point2i on_background = Point2i(800, 800);
  1313. Point2i on_outside = Point2i(-1, -1);
  1314. SEND_GUI_MOUSE_MOTION_EVENT(on_background, MouseButtonMask::NONE, Key::NONE);
  1315. tree->physics_process(1);
  1316. Vector<PickingCollider> v;
  1317. for (int i = 0; i < 4; i++) {
  1318. PickingCollider pc;
  1319. pc.a = memnew(TestArea2D);
  1320. pc.c = memnew(CollisionShape2D);
  1321. pc.r.instantiate();
  1322. pc.r->set_size(Size2(150, 150));
  1323. pc.c->set_shape(pc.r);
  1324. pc.a->add_child(pc.c);
  1325. pc.a->set_name("A" + itos(i));
  1326. pc.c->set_name("C" + itos(i));
  1327. v.push_back(pc);
  1328. SIGNAL_WATCH(pc.a, SceneStringName(mouse_entered));
  1329. SIGNAL_WATCH(pc.a, SceneStringName(mouse_exited));
  1330. }
  1331. Node2D *node_a = memnew(Node2D);
  1332. node_a->set_position(Point2i(0, 0));
  1333. v[0].a->set_position(Point2i(0, 0));
  1334. v[1].a->set_position(Point2i(0, 100));
  1335. node_a->add_child(v[0].a);
  1336. node_a->add_child(v[1].a);
  1337. Node2D *node_b = memnew(Node2D);
  1338. node_b->set_position(Point2i(100, 0));
  1339. v[2].a->set_position(Point2i(0, 0));
  1340. v[3].a->set_position(Point2i(0, 100));
  1341. node_b->add_child(v[2].a);
  1342. node_b->add_child(v[3].a);
  1343. root->add_child(node_a);
  1344. root->add_child(node_b);
  1345. Point2i on_all = Point2i(50, 50);
  1346. Point2i on_0 = Point2i(10, 10);
  1347. Point2i on_01 = Point2i(10, 50);
  1348. Point2i on_02 = Point2i(50, 10);
  1349. Array empty_signal_args_2;
  1350. empty_signal_args_2.push_back(Array());
  1351. empty_signal_args_2.push_back(Array());
  1352. Array empty_signal_args_4;
  1353. empty_signal_args_4.push_back(Array());
  1354. empty_signal_args_4.push_back(Array());
  1355. empty_signal_args_4.push_back(Array());
  1356. empty_signal_args_4.push_back(Array());
  1357. for (PickingCollider E : v) {
  1358. E.a->init_signals();
  1359. }
  1360. SUBCASE("[Viewport][Picking2D] Mouse Motion") {
  1361. SEND_GUI_MOUSE_MOTION_EVENT(on_all, MouseButtonMask::NONE, Key::NONE);
  1362. tree->physics_process(1);
  1363. SIGNAL_CHECK(SceneStringName(mouse_entered), empty_signal_args_4);
  1364. SIGNAL_CHECK_FALSE(SceneStringName(mouse_exited));
  1365. for (PickingCollider E : v) {
  1366. CHECK(E.a->enter_id);
  1367. CHECK_FALSE(E.a->exit_id);
  1368. E.a->test_reset();
  1369. }
  1370. SEND_GUI_MOUSE_MOTION_EVENT(on_01, MouseButtonMask::NONE, Key::NONE);
  1371. tree->physics_process(1);
  1372. SIGNAL_CHECK_FALSE(SceneStringName(mouse_entered));
  1373. SIGNAL_CHECK(SceneStringName(mouse_exited), empty_signal_args_2);
  1374. for (int i = 0; i < v.size(); i++) {
  1375. CHECK_FALSE(v[i].a->enter_id);
  1376. if (i < 2) {
  1377. CHECK_FALSE(v[i].a->exit_id);
  1378. } else {
  1379. CHECK(v[i].a->exit_id);
  1380. }
  1381. v[i].a->test_reset();
  1382. }
  1383. SEND_GUI_MOUSE_MOTION_EVENT(on_outside, MouseButtonMask::NONE, Key::NONE);
  1384. tree->physics_process(1);
  1385. SIGNAL_CHECK_FALSE(SceneStringName(mouse_entered));
  1386. SIGNAL_CHECK(SceneStringName(mouse_exited), empty_signal_args_2);
  1387. for (int i = 0; i < v.size(); i++) {
  1388. CHECK_FALSE(v[i].a->enter_id);
  1389. if (i < 2) {
  1390. CHECK(v[i].a->exit_id);
  1391. } else {
  1392. CHECK_FALSE(v[i].a->exit_id);
  1393. }
  1394. v[i].a->test_reset();
  1395. }
  1396. }
  1397. SUBCASE("[Viewport][Picking2D] Object moved / passive hovering") {
  1398. SEND_GUI_MOUSE_MOTION_EVENT(on_all, MouseButtonMask::NONE, Key::NONE);
  1399. tree->physics_process(1);
  1400. for (int i = 0; i < v.size(); i++) {
  1401. CHECK(v[i].a->enter_id);
  1402. CHECK_FALSE(v[i].a->exit_id);
  1403. v[i].a->test_reset();
  1404. }
  1405. node_b->set_position(Point2i(200, 0));
  1406. tree->physics_process(1);
  1407. for (int i = 0; i < v.size(); i++) {
  1408. CHECK_FALSE(v[i].a->enter_id);
  1409. if (i < 2) {
  1410. CHECK_FALSE(v[i].a->exit_id);
  1411. } else {
  1412. CHECK(v[i].a->exit_id);
  1413. }
  1414. v[i].a->test_reset();
  1415. }
  1416. node_b->set_position(Point2i(100, 0));
  1417. tree->physics_process(1);
  1418. for (int i = 0; i < v.size(); i++) {
  1419. if (i < 2) {
  1420. CHECK_FALSE(v[i].a->enter_id);
  1421. } else {
  1422. CHECK(v[i].a->enter_id);
  1423. }
  1424. CHECK_FALSE(v[i].a->exit_id);
  1425. v[i].a->test_reset();
  1426. }
  1427. }
  1428. SUBCASE("[Viewport][Picking2D] No Processing") {
  1429. SEND_GUI_MOUSE_MOTION_EVENT(on_background, MouseButtonMask::NONE, Key::NONE);
  1430. tree->physics_process(1);
  1431. for (PickingCollider E : v) {
  1432. E.a->test_reset();
  1433. }
  1434. v[0].a->set_process_mode(Node::PROCESS_MODE_DISABLED);
  1435. v[0].c->set_process_mode(Node::PROCESS_MODE_DISABLED);
  1436. SEND_GUI_MOUSE_MOTION_EVENT(on_02, MouseButtonMask::NONE, Key::NONE);
  1437. tree->physics_process(1);
  1438. CHECK_FALSE(v[0].a->enter_id);
  1439. CHECK_FALSE(v[0].a->exit_id);
  1440. CHECK(v[2].a->enter_id);
  1441. CHECK_FALSE(v[2].a->exit_id);
  1442. for (PickingCollider E : v) {
  1443. E.a->test_reset();
  1444. }
  1445. SEND_GUI_MOUSE_MOTION_EVENT(on_background, MouseButtonMask::NONE, Key::NONE);
  1446. tree->physics_process(1);
  1447. CHECK_FALSE(v[0].a->enter_id);
  1448. CHECK_FALSE(v[0].a->exit_id);
  1449. CHECK_FALSE(v[2].a->enter_id);
  1450. CHECK(v[2].a->exit_id);
  1451. for (PickingCollider E : v) {
  1452. E.a->test_reset();
  1453. }
  1454. v[0].a->set_process_mode(Node::PROCESS_MODE_ALWAYS);
  1455. v[0].c->set_process_mode(Node::PROCESS_MODE_ALWAYS);
  1456. }
  1457. SUBCASE("[Viewport][Picking2D] Multiple events in series") {
  1458. SEND_GUI_MOUSE_MOTION_EVENT(on_0, MouseButtonMask::NONE, Key::NONE);
  1459. SEND_GUI_MOUSE_MOTION_EVENT(on_0 + Point2i(10, 0), MouseButtonMask::NONE, Key::NONE);
  1460. tree->physics_process(1);
  1461. for (int i = 0; i < v.size(); i++) {
  1462. if (i < 1) {
  1463. CHECK(v[i].a->enter_id);
  1464. } else {
  1465. CHECK_FALSE(v[i].a->enter_id);
  1466. }
  1467. CHECK_FALSE(v[i].a->exit_id);
  1468. v[i].a->test_reset();
  1469. }
  1470. SEND_GUI_MOUSE_MOTION_EVENT(on_background, MouseButtonMask::NONE, Key::NONE);
  1471. SEND_GUI_MOUSE_MOTION_EVENT(on_background + Point2i(10, 10), MouseButtonMask::NONE, Key::NONE);
  1472. tree->physics_process(1);
  1473. for (int i = 0; i < v.size(); i++) {
  1474. CHECK_FALSE(v[i].a->enter_id);
  1475. if (i < 1) {
  1476. CHECK(v[i].a->exit_id);
  1477. } else {
  1478. CHECK_FALSE(v[i].a->exit_id);
  1479. }
  1480. v[i].a->test_reset();
  1481. }
  1482. }
  1483. SUBCASE("[Viewport][Picking2D] Disable Picking") {
  1484. SEND_GUI_MOUSE_MOTION_EVENT(on_02, MouseButtonMask::NONE, Key::NONE);
  1485. root->set_physics_object_picking(false);
  1486. CHECK_FALSE(root->get_physics_object_picking());
  1487. tree->physics_process(1);
  1488. for (int i = 0; i < v.size(); i++) {
  1489. CHECK_FALSE(v[i].a->enter_id);
  1490. v[i].a->test_reset();
  1491. }
  1492. root->set_physics_object_picking(true);
  1493. CHECK(root->get_physics_object_picking());
  1494. }
  1495. SUBCASE("[Viewport][Picking2D] CollisionObject in CanvasLayer") {
  1496. CanvasLayer *node_c = memnew(CanvasLayer);
  1497. node_c->set_rotation(Math_PI);
  1498. node_c->set_offset(Point2i(100, 100));
  1499. root->add_child(node_c);
  1500. v[2].a->reparent(node_c, false);
  1501. v[3].a->reparent(node_c, false);
  1502. SEND_GUI_MOUSE_MOTION_EVENT(on_02, MouseButtonMask::NONE, Key::NONE);
  1503. tree->physics_process(1);
  1504. for (int i = 0; i < v.size(); i++) {
  1505. if (i == 0 || i == 3) {
  1506. CHECK(v[i].a->enter_id);
  1507. } else {
  1508. CHECK_FALSE(v[i].a->enter_id);
  1509. }
  1510. v[i].a->test_reset();
  1511. }
  1512. v[2].a->reparent(node_b, false);
  1513. v[3].a->reparent(node_b, false);
  1514. root->remove_child(node_c);
  1515. memdelete(node_c);
  1516. }
  1517. SUBCASE("[Viewport][Picking2D] Picking Sort") {
  1518. root->set_physics_object_picking_sort(true);
  1519. CHECK(root->get_physics_object_picking_sort());
  1520. SUBCASE("[Viewport][Picking2D] Picking Sort Z-Index") {
  1521. node_a->set_z_index(10);
  1522. v[0].a->set_z_index(0);
  1523. v[1].a->set_z_index(2);
  1524. node_b->set_z_index(5);
  1525. v[2].a->set_z_index(8);
  1526. v[3].a->set_z_index(11);
  1527. v[3].a->set_z_as_relative(false);
  1528. TestArea2D::counter = 0;
  1529. SEND_GUI_MOUSE_MOTION_EVENT(on_all, MouseButtonMask::NONE, Key::NONE);
  1530. tree->physics_process(1);
  1531. CHECK(v[0].a->enter_id == 4);
  1532. CHECK(v[1].a->enter_id == 2);
  1533. CHECK(v[2].a->enter_id == 1);
  1534. CHECK(v[3].a->enter_id == 3);
  1535. for (int i = 0; i < v.size(); i++) {
  1536. CHECK_FALSE(v[i].a->exit_id);
  1537. v[i].a->test_reset();
  1538. }
  1539. TestArea2D::counter = 0;
  1540. SEND_GUI_MOUSE_MOTION_EVENT(on_background, MouseButtonMask::NONE, Key::NONE);
  1541. tree->physics_process(1);
  1542. CHECK(v[0].a->exit_id == 4);
  1543. CHECK(v[1].a->exit_id == 2);
  1544. CHECK(v[2].a->exit_id == 1);
  1545. CHECK(v[3].a->exit_id == 3);
  1546. for (int i = 0; i < v.size(); i++) {
  1547. CHECK_FALSE(v[i].a->enter_id);
  1548. v[i].a->set_z_as_relative(true);
  1549. v[i].a->set_z_index(0);
  1550. v[i].a->test_reset();
  1551. }
  1552. node_a->set_z_index(0);
  1553. node_b->set_z_index(0);
  1554. }
  1555. SUBCASE("[Viewport][Picking2D] Picking Sort Scene Tree Location") {
  1556. TestArea2D::counter = 0;
  1557. SEND_GUI_MOUSE_MOTION_EVENT(on_all, MouseButtonMask::NONE, Key::NONE);
  1558. tree->physics_process(1);
  1559. for (int i = 0; i < v.size(); i++) {
  1560. CHECK(v[i].a->enter_id == 4 - i);
  1561. CHECK_FALSE(v[i].a->exit_id);
  1562. v[i].a->test_reset();
  1563. }
  1564. TestArea2D::counter = 0;
  1565. SEND_GUI_MOUSE_MOTION_EVENT(on_background, MouseButtonMask::NONE, Key::NONE);
  1566. tree->physics_process(1);
  1567. for (int i = 0; i < v.size(); i++) {
  1568. CHECK_FALSE(v[i].a->enter_id);
  1569. CHECK(v[i].a->exit_id == 4 - i);
  1570. v[i].a->test_reset();
  1571. }
  1572. }
  1573. root->set_physics_object_picking_sort(false);
  1574. CHECK_FALSE(root->get_physics_object_picking_sort());
  1575. }
  1576. SUBCASE("[Viewport][Picking2D] Mouse Button") {
  1577. SEND_GUI_MOUSE_BUTTON_EVENT(on_0, MouseButton::LEFT, MouseButtonMask::LEFT, Key::NONE);
  1578. tree->physics_process(1);
  1579. for (int i = 0; i < v.size(); i++) {
  1580. if (i == 0) {
  1581. CHECK(v[i].a->enter_id);
  1582. } else {
  1583. CHECK_FALSE(v[i].a->enter_id);
  1584. }
  1585. CHECK_FALSE(v[i].a->exit_id);
  1586. v[i].a->test_reset();
  1587. }
  1588. SEND_GUI_MOUSE_BUTTON_RELEASED_EVENT(on_0, MouseButton::LEFT, MouseButtonMask::NONE, Key::NONE);
  1589. tree->physics_process(1);
  1590. for (int i = 0; i < v.size(); i++) {
  1591. CHECK_FALSE(v[i].a->enter_id);
  1592. CHECK_FALSE(v[i].a->exit_id);
  1593. v[i].a->test_reset();
  1594. }
  1595. }
  1596. SUBCASE("[Viewport][Picking2D] Screen Touch") {
  1597. SEND_GUI_TOUCH_EVENT(on_01, true, false);
  1598. tree->physics_process(1);
  1599. for (int i = 0; i < v.size(); i++) {
  1600. if (i < 2) {
  1601. Ref<InputEventScreenTouch> st = v[i].a->last_input_event;
  1602. CHECK(st.is_valid());
  1603. } else {
  1604. CHECK(v[i].a->last_input_event.is_null());
  1605. }
  1606. v[i].a->test_reset();
  1607. }
  1608. }
  1609. for (PickingCollider E : v) {
  1610. SIGNAL_UNWATCH(E.a, SceneStringName(mouse_entered));
  1611. SIGNAL_UNWATCH(E.a, SceneStringName(mouse_exited));
  1612. memdelete(E.c);
  1613. memdelete(E.a);
  1614. }
  1615. }
  1616. TEST_CASE("[SceneTree][Viewport] Embedded Windows") {
  1617. Window *root = SceneTree::get_singleton()->get_root();
  1618. Window *w = memnew(Window);
  1619. SUBCASE("[Viewport] Safe-rect of embedded Window") {
  1620. root->add_child(w);
  1621. root->subwindow_set_popup_safe_rect(w, Rect2i(10, 10, 10, 10));
  1622. CHECK_EQ(root->subwindow_get_popup_safe_rect(w), Rect2i(10, 10, 10, 10));
  1623. root->remove_child(w);
  1624. CHECK_EQ(root->subwindow_get_popup_safe_rect(w), Rect2i());
  1625. }
  1626. memdelete(w);
  1627. }
  1628. } // namespace TestViewport
  1629. #endif // TEST_VIEWPORT_H