2 * Copyright (c) 2020 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 #include <dali-test-suite-utils.h>
19 #include <dali/devel-api/events/hit-test-algorithm.h>
20 #include <dali/integration-api/events/touch-event-integ.h>
21 #include <dali/public-api/dali-core.h>
31 * The functor to be used in the hit-test algorithm to check whether the actor is hittable.
33 bool IsActorHittableFunction(Actor actor, Dali::HitTestAlgorithm::TraverseType type)
35 bool hittable = false;
39 case Dali::HitTestAlgorithm::CHECK_ACTOR:
41 // Check whether the actor is visible and not fully transparent.
42 if(actor.GetCurrentProperty<bool>(Actor::Property::VISIBLE) && actor.GetCurrentProperty<Vector4>(Actor::Property::WORLD_COLOR).a > 0.01f) // not FULLY_TRANSPARENT
44 // Check whether the actor has the specific name "HittableActor"
45 if(actor.GetProperty<std::string>(Actor::Property::NAME) == "HittableActor")
52 case Dali::HitTestAlgorithm::DESCEND_ACTOR_TREE:
54 if(actor.GetCurrentProperty<bool>(Actor::Property::VISIBLE)) // Actor is visible, if not visible then none of its children are visible.
69 bool DefaultIsActorTouchableFunction(Dali::Actor actor, Dali::HitTestAlgorithm::TraverseType type)
71 bool hittable = false;
75 case Dali::HitTestAlgorithm::CHECK_ACTOR:
77 if(actor.GetCurrentProperty<bool>(Actor::Property::VISIBLE) &&
78 actor.GetProperty<bool>(Actor::Property::SENSITIVE) &&
79 actor.GetCurrentProperty<Vector4>(Actor::Property::WORLD_COLOR).a > 0.01f)
85 case Dali::HitTestAlgorithm::DESCEND_ACTOR_TREE:
87 if(actor.GetCurrentProperty<bool>(Actor::Property::VISIBLE) && // Actor is visible, if not visible then none of its children are visible.
88 actor.GetProperty<bool>(Actor::Property::SENSITIVE)) // Actor is sensitive, if insensitive none of its children should be hittable either.
103 } // anonymous namespace
105 // Positive test case for a method
106 int UtcDaliHitTestAlgorithmWithFunctor(void)
108 TestApplication application;
109 tet_infoline("Testing Dali::HitTestAlgorithm functor");
111 Stage stage = Stage::GetCurrent();
113 Actor actor = Actor::New();
114 actor.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f));
115 actor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
116 actor.SetProperty(Actor::Property::NAME, "NonHittableActor");
120 application.SendNotification();
121 application.Render();
123 Vector2 screenCoordinates(10.0f, 10.0f);
124 Vector2 localCoordinates;
125 actor.ScreenToLocal(localCoordinates.x, localCoordinates.y, screenCoordinates.x, screenCoordinates.y);
127 // Perform a hit-test at the given screen coordinates
128 Dali::HitTestAlgorithm::Results results;
129 Dali::HitTestAlgorithm::HitTest(stage, screenCoordinates, results, IsActorHittableFunction);
130 DALI_TEST_CHECK(results.actor != actor);
132 actor.SetProperty(Actor::Property::NAME, "HittableActor");
134 results.actor = Actor();
135 results.actorCoordinates = Vector2::ZERO;
137 // Perform a hit-test at the given screen coordinates
138 Dali::HitTestAlgorithm::HitTest(stage, screenCoordinates, results, IsActorHittableFunction);
139 DALI_TEST_CHECK(results.actor == actor);
140 DALI_TEST_EQUALS(localCoordinates, results.actorCoordinates, 0.1f, TEST_LOCATION);
144 int UtcDaliHitTestAlgorithmOrtho01(void)
146 TestApplication application;
147 tet_infoline("Testing Dali::HitTestAlgorithm with parallel Ortho camera()");
149 Stage stage = Stage::GetCurrent();
150 RenderTaskList renderTaskList = stage.GetRenderTaskList();
151 RenderTask defaultRenderTask = renderTaskList.GetTask(0u);
152 Dali::CameraActor cameraActor = defaultRenderTask.GetCameraActor();
154 Vector2 stageSize(stage.GetSize());
155 cameraActor.SetOrthographicProjection(stageSize);
156 cameraActor.SetProperty(Actor::Property::POSITION, Vector3(0.0f, 0.0f, 1600.0f));
158 Vector2 actorSize(stageSize * 0.5f);
159 // Create two actors with half the size of the stage and set them to be partially overlapping
160 Actor blue = Actor::New();
161 blue.SetProperty(Actor::Property::NAME, "Blue");
162 blue.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
163 blue.SetProperty(Actor::Property::PARENT_ORIGIN, Vector3(1.0f / 3.0f, 1.0f / 3.0f, 0.5f));
164 blue.SetProperty(Actor::Property::SIZE, actorSize);
165 blue.SetProperty(Actor::Property::POSITION_Z, 30.0f);
167 Actor green = Actor::New();
168 green.SetProperty(Actor::Property::NAME, "Green");
169 green.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
170 green.SetProperty(Actor::Property::PARENT_ORIGIN, Vector3(2.0f / 3.0f, 2.0f / 3.0f, 0.5f));
171 green.SetProperty(Actor::Property::SIZE, actorSize);
173 // Add the actors to the view
178 application.SendNotification();
179 application.Render(0);
180 application.Render(10);
182 HitTestAlgorithm::Results results;
183 HitTest(stage, stageSize / 2.0f, results, &DefaultIsActorTouchableFunction);
184 DALI_TEST_CHECK(results.actor == green);
185 DALI_TEST_EQUALS(results.actorCoordinates, actorSize * 1.0f / 6.0f, TEST_LOCATION);
187 HitTest(stage, stageSize / 3.0f, results, &DefaultIsActorTouchableFunction);
188 DALI_TEST_CHECK(results.actor == blue);
189 DALI_TEST_EQUALS(results.actorCoordinates, actorSize * 0.5f, TEST_LOCATION);
191 HitTest(stage, stageSize * 2.0f / 3.0f, results, &DefaultIsActorTouchableFunction);
192 DALI_TEST_CHECK(results.actor == green);
193 DALI_TEST_EQUALS(results.actorCoordinates, actorSize * 0.5f, TEST_LOCATION);
197 int UtcDaliHitTestAlgorithmOrtho02(void)
199 TestApplication application;
200 tet_infoline("Testing Dali::HitTestAlgorithm with offset Ortho camera()");
202 Stage stage = Stage::GetCurrent();
203 RenderTaskList renderTaskList = stage.GetRenderTaskList();
204 RenderTask defaultRenderTask = renderTaskList.GetTask(0u);
205 Dali::CameraActor cameraActor = defaultRenderTask.GetCameraActor();
207 Vector2 stageSize(stage.GetSize());
208 cameraActor.SetOrthographicProjection(-stageSize.x * 0.3f, stageSize.x * 0.7f, stageSize.y * 0.3f, -stageSize.y * 0.7f, 800.0f, 4895.0f);
209 cameraActor.SetProperty(Actor::Property::POSITION, Vector3(0.0f, 0.0f, 1600.0f));
211 Vector2 actorSize(stageSize * 0.5f);
212 // Create two actors with half the size of the stage and set them to be partially overlapping
213 Actor blue = Actor::New();
214 blue.SetProperty(Actor::Property::NAME, "Blue");
215 blue.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
216 blue.SetProperty(Actor::Property::PARENT_ORIGIN, Vector3(0.2f, 0.2f, 0.5f));
217 blue.SetProperty(Actor::Property::SIZE, actorSize);
218 blue.SetProperty(Actor::Property::POSITION_Z, 30.0f);
220 Actor green = Actor::New();
221 green.SetProperty(Actor::Property::NAME, "Green");
222 green.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
223 green.SetProperty(Actor::Property::PARENT_ORIGIN, Vector3(0.4f, 0.4f, 0.5f));
224 green.SetProperty(Actor::Property::SIZE, actorSize);
226 // Add the actors to the view
231 application.SendNotification();
232 application.Render(0);
233 application.Render(10);
236 HitTestAlgorithm::Results results;
237 HitTest(stage, Vector2(240.0f, 400.0f), results, &DefaultIsActorTouchableFunction);
238 DALI_TEST_CHECK(results.actor == green);
239 DALI_TEST_EQUALS(results.actorCoordinates, actorSize * 0.6f, 0.01f, TEST_LOCATION);
243 HitTestAlgorithm::Results results;
244 HitTest(stage, Vector2(0.001f, 0.001f), results, &DefaultIsActorTouchableFunction);
245 DALI_TEST_CHECK(results.actor == blue);
246 DALI_TEST_EQUALS(results.actorCoordinates, Vector2(0.001f, 0.001f), 0.001f, TEST_LOCATION);
250 HitTestAlgorithm::Results results;
251 HitTest(stage, stageSize, results, &DefaultIsActorTouchableFunction);
252 DALI_TEST_CHECK(!results.actor);
253 DALI_TEST_EQUALS(results.actorCoordinates, Vector2::ZERO, TEST_LOCATION);
258 HitTestAlgorithm::Results results;
259 HitTest(stage, stageSize * 0.69f, results, &DefaultIsActorTouchableFunction);
260 DALI_TEST_CHECK(results.actor == green);
261 DALI_TEST_EQUALS(results.actorCoordinates, actorSize * 0.98f, 0.01f, TEST_LOCATION);
267 int UtcDaliHitTestAlgorithmClippingActor(void)
269 TestApplication application;
270 tet_infoline("Testing Dali::HitTestAlgorithm with a stencil");
272 Stage stage = Stage::GetCurrent();
273 Actor rootLayer = stage.GetRootLayer();
274 rootLayer.SetProperty(Actor::Property::NAME, "RootLayer");
277 Layer layer = Layer::New();
278 layer.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
279 layer.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
280 layer.SetProperty(Actor::Property::NAME, "layer");
283 // Create a clipping actor and add it to the layer.
284 Actor clippingActor = CreateRenderableActor();
285 clippingActor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
286 clippingActor.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
287 clippingActor.SetProperty(Actor::Property::SIZE, Vector2(50.0f, 50.0f));
288 clippingActor.SetProperty(Actor::Property::CLIPPING_MODE, ClippingMode::CLIP_CHILDREN);
289 clippingActor.SetProperty(Actor::Property::NAME, "clippingActor");
290 layer.Add(clippingActor);
292 // Create a renderable actor and add it to the clipping actor.
293 Actor childActor = CreateRenderableActor();
294 childActor.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f));
295 childActor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
296 childActor.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
297 childActor.SetProperty(Actor::Property::NAME, "childActor");
298 clippingActor.Add(childActor);
301 application.SendNotification();
302 application.Render();
304 // Hit within clippingActor and childActor.
305 HitTestAlgorithm::Results results;
306 HitTest(stage, Vector2(10.0f, 10.0f), results, &DefaultIsActorTouchableFunction);
307 DALI_TEST_CHECK(results.actor == childActor);
308 tet_printf("Hit: %s\n", (results.actor ? results.actor.GetProperty<std::string>(Actor::Property::NAME).c_str() : "NULL"));
310 // Hit within childActor but outside of clippingActor, should hit the root-layer instead.
311 HitTest(stage, Vector2(60.0f, 60.0f), results, &DefaultIsActorTouchableFunction);
312 DALI_TEST_CHECK(results.actor == rootLayer);
313 tet_printf("Hit: %s\n", (results.actor ? results.actor.GetProperty<std::string>(Actor::Property::NAME).c_str() : "NULL"));
318 int UtcDaliHitTestAlgorithmOverlay(void)
320 TestApplication application;
321 tet_infoline("Testing Dali::HitTestAlgorithm with overlay actors");
323 Stage stage = Stage::GetCurrent();
324 RenderTaskList renderTaskList = stage.GetRenderTaskList();
325 RenderTask defaultRenderTask = renderTaskList.GetTask(0u);
326 Dali::CameraActor cameraActor = defaultRenderTask.GetCameraActor();
328 Vector2 stageSize(stage.GetSize());
329 cameraActor.SetOrthographicProjection(stageSize);
330 cameraActor.SetProperty(Actor::Property::POSITION, Vector3(0.0f, 0.0f, 1600.0f));
332 Vector2 actorSize(stageSize * 0.5f);
333 // Create two actors with half the size of the stage and set them to be partially overlapping
334 Actor blue = Actor::New();
335 blue.SetProperty(Actor::Property::DRAW_MODE, DrawMode::OVERLAY_2D);
336 blue.SetProperty(Actor::Property::NAME, "Blue");
337 blue.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
338 blue.SetProperty(Actor::Property::PARENT_ORIGIN, Vector3(1.0f / 3.0f, 1.0f / 3.0f, 0.5f));
339 blue.SetProperty(Actor::Property::SIZE, actorSize);
340 blue.SetProperty(Actor::Property::POSITION_Z, 30.0f);
342 Actor green = Actor::New();
343 green.SetProperty(Actor::Property::NAME, "Green");
344 green.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
345 green.SetProperty(Actor::Property::PARENT_ORIGIN, Vector3(2.0f / 3.0f, 2.0f / 3.0f, 0.5f));
346 green.SetProperty(Actor::Property::SIZE, actorSize);
348 // Add the actors to the view
353 application.SendNotification();
354 application.Render(0);
355 application.Render(10);
357 HitTestAlgorithm::Results results;
359 //Hit in the intersection. Should pick the blue actor since it is an overlay.
360 HitTest(stage, stageSize / 2.0f, results, &DefaultIsActorTouchableFunction);
361 DALI_TEST_CHECK(results.actor == blue);
362 DALI_TEST_EQUALS(results.actorCoordinates, actorSize * 5.0f / 6.0f, TEST_LOCATION);
364 //Hit in the blue actor
365 HitTest(stage, stageSize / 3.0f, results, &DefaultIsActorTouchableFunction);
366 DALI_TEST_CHECK(results.actor == blue);
367 DALI_TEST_EQUALS(results.actorCoordinates, actorSize * 0.5f, TEST_LOCATION);
369 //Hit in the green actor
370 HitTest(stage, stageSize * 2.0f / 3.0f, results, &DefaultIsActorTouchableFunction);
371 DALI_TEST_CHECK(results.actor == green);
372 DALI_TEST_EQUALS(results.actorCoordinates, actorSize * 0.5f, TEST_LOCATION);