2 * Copyright (c) 2014 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.
21 #include <dali/public-api/dali-core.h>
22 #include <dali/devel-api/events/hit-test-algorithm.h>
23 #include <dali/integration-api/events/touch-event-integ.h>
24 #include <dali-test-suite-utils.h>
32 * The functor to be used in the hit-test algorithm to check whether the actor is hittable.
34 bool IsActorHittableFunction(Actor actor, Dali::HitTestAlgorithm::TraverseType type)
36 bool hittable = false;
40 case Dali::HitTestAlgorithm::CHECK_ACTOR:
42 // Check whether the actor is visible and not fully transparent.
44 && actor.GetCurrentWorldColor().a > 0.01f) // not FULLY_TRANSPARENT
46 // Check whether the actor has the specific name "HittableActor"
47 if(actor.GetName() == "HittableActor")
54 case Dali::HitTestAlgorithm::DESCEND_ACTOR_TREE:
56 if( actor.IsVisible() ) // Actor is visible, if not visible then none of its children are visible.
72 bool DefaultIsActorTouchableFunction(Dali::Actor actor, Dali::HitTestAlgorithm::TraverseType type)
74 bool hittable = false;
78 case Dali::HitTestAlgorithm::CHECK_ACTOR:
80 if( actor.IsVisible() &&
81 actor.IsSensitive() &&
82 actor.GetCurrentWorldColor().a > 0.01f)
88 case Dali::HitTestAlgorithm::DESCEND_ACTOR_TREE:
90 if( actor.IsVisible() && // Actor is visible, if not visible then none of its children are visible.
91 actor.IsSensitive()) // Actor is sensitive, if insensitive none of its children should be hittable either.
106 } // anonymous namespace
109 // Positive test case for a method
110 int UtcDaliHitTestAlgorithmWithFunctor(void)
112 TestApplication application;
113 tet_infoline("Testing Dali::HitTestAlgorithm functor");
115 Stage stage = Stage::GetCurrent();
117 Actor actor = Actor::New();
118 actor.SetSize(100.0f, 100.0f);
119 actor.SetAnchorPoint(AnchorPoint::TOP_LEFT);
120 actor.SetName("NonHittableActor");
124 application.SendNotification();
125 application.Render();
127 Vector2 screenCoordinates( 10.0f, 10.0f );
128 Vector2 localCoordinates;
129 actor.ScreenToLocal( localCoordinates.x, localCoordinates.y, screenCoordinates.x, screenCoordinates.y );
131 // Perform a hit-test at the given screen coordinates
132 Dali::HitTestAlgorithm::Results results;
133 Dali::HitTestAlgorithm::HitTest( stage, screenCoordinates, results, IsActorHittableFunction );
134 DALI_TEST_CHECK( results.actor != actor );
136 actor.SetName("HittableActor");
138 results.actor = Actor();
139 results.actorCoordinates = Vector2::ZERO;
141 // Perform a hit-test at the given screen coordinates
142 Dali::HitTestAlgorithm::HitTest( stage, screenCoordinates, results, IsActorHittableFunction );
143 DALI_TEST_CHECK( results.actor == actor );
144 DALI_TEST_EQUALS( localCoordinates, results.actorCoordinates, 0.1f, TEST_LOCATION );
148 int UtcDaliHitTestAlgorithmWithFunctorOnRenderTask(void)
150 TestApplication application;
151 tet_infoline("Testing Dali::HitTestAlgorithm functor, specific to a given render task");
153 Stage stage = Stage::GetCurrent();
154 Size stageSize = stage.GetSize();
155 RenderTaskList taskList = stage.GetRenderTaskList();
159 for( int i=0; i<2; i++ )
161 actor[i] = Actor::New();
162 actor[i].SetSize(100.f, 100.f);
163 actor[i].SetParentOrigin(ParentOrigin::TOP_LEFT);
164 actor[i].SetAnchorPoint(AnchorPoint::TOP_LEFT);
165 actor[i].SetName("HittableActor");
168 Vector2 position( 50.f, 40.f );
169 actor[1].SetPosition( position.x, position.y );
171 RenderTask renderTask[2];
172 renderTask[0] = taskList.GetTask( 0u );
174 FrameBufferImage frameBufferImage = FrameBufferImage::New(stageSize.width, stageSize.height, Pixel::A8, Image::NEVER);
175 renderTask[1] = taskList.CreateTask();
176 renderTask[1].SetSourceActor( actor[1] );
177 renderTask[1].SetExclusive( true );
178 renderTask[1].SetInputEnabled( true );
179 renderTask[1].SetTargetFrameBuffer( frameBufferImage );
180 renderTask[1].SetRefreshRate( RenderTask::REFRESH_ONCE );
181 renderTask[1].SetScreenToFrameBufferFunction( RenderTask::FULLSCREEN_FRAMEBUFFER_FUNCTION );
182 application.GetGlAbstraction().SetCheckFramebufferStatusResult( GL_FRAMEBUFFER_COMPLETE );
185 application.SendNotification();
186 application.Render();
187 application.Render();
188 application.SendNotification();
190 // Perform a hit-test at the given screen coordinates with different render tasks
192 Dali::HitTestAlgorithm::Results results;
193 Vector2 screenCoordinates( 25.f, 25.f );
195 Dali::HitTestAlgorithm::HitTest( renderTask[0], screenCoordinates, results, IsActorHittableFunction );
196 DALI_TEST_CHECK( results.actor == actor[0] );
197 DALI_TEST_EQUALS( screenCoordinates, results.actorCoordinates, 0.1f, TEST_LOCATION );
199 results.actor = Actor();
200 results.actorCoordinates = Vector2::ZERO;
201 Dali::HitTestAlgorithm::HitTest( renderTask[1], screenCoordinates, results, IsActorHittableFunction );
202 DALI_TEST_CHECK( !results.actor );
203 DALI_TEST_EQUALS( Vector2::ZERO, results.actorCoordinates, 0.1f, TEST_LOCATION );
205 screenCoordinates.x = 80.f;
206 screenCoordinates.y = 70.f;
208 results.actor = Actor();
209 results.actorCoordinates = Vector2::ZERO;
210 Dali::HitTestAlgorithm::HitTest( renderTask[0], screenCoordinates, results, IsActorHittableFunction );
211 DALI_TEST_CHECK( results.actor == actor[0] );
212 DALI_TEST_EQUALS( screenCoordinates, results.actorCoordinates, 0.1f, TEST_LOCATION );
214 results.actor = Actor();
215 results.actorCoordinates = Vector2::ZERO;
216 Dali::HitTestAlgorithm::HitTest( renderTask[1], screenCoordinates, results, IsActorHittableFunction );
217 DALI_TEST_CHECK( results.actor == actor[1]);
218 DALI_TEST_EQUALS( screenCoordinates - position, results.actorCoordinates, 0.1f, TEST_LOCATION );
221 screenCoordinates.x = 120.f;
222 screenCoordinates.y = 130.f;
224 results.actor = Actor();
225 results.actorCoordinates = Vector2::ZERO;
226 Dali::HitTestAlgorithm::HitTest( renderTask[0], screenCoordinates, results, IsActorHittableFunction );
227 DALI_TEST_CHECK( results.actor == actor[1] );
228 DALI_TEST_EQUALS( screenCoordinates - position, results.actorCoordinates, 0.1f, TEST_LOCATION );
230 results.actor = Actor();
231 results.actorCoordinates = Vector2::ZERO;
232 Dali::HitTestAlgorithm::HitTest( renderTask[1], screenCoordinates, results, IsActorHittableFunction );
233 DALI_TEST_CHECK( results.actor == actor[1]);
234 DALI_TEST_EQUALS( screenCoordinates - position, results.actorCoordinates, 0.1f, TEST_LOCATION );
239 int UtcDaliHitTestAlgorithmOrtho01(void)
241 TestApplication application;
242 tet_infoline("Testing Dali::HitTestAlgorithm with parallel Ortho camera()");
244 Stage stage = Stage::GetCurrent();
245 RenderTaskList renderTaskList = stage.GetRenderTaskList();
246 RenderTask defaultRenderTask = renderTaskList.GetTask(0u);
247 Dali::CameraActor cameraActor = defaultRenderTask.GetCameraActor();
249 Vector2 stageSize ( stage.GetSize() );
250 cameraActor.SetOrthographicProjection( stageSize );
251 cameraActor.SetPosition(0.0f, 0.0f, 1600.0f);
253 Vector2 actorSize( stageSize * 0.5f );
254 // Create two actors with half the size of the stage and set them to be partially overlapping
255 Actor blue = Actor::New();
256 blue.SetName( "Blue" );
257 blue.SetAnchorPoint( AnchorPoint::CENTER );
258 blue.SetParentOrigin( Vector3(1.0f/3.0f, 1.0f/3.0f, 0.5f) );
259 blue.SetSize( actorSize );
262 Actor green = Actor::New( );
263 green.SetName( "Green" );
264 green.SetAnchorPoint( AnchorPoint::CENTER );
265 green.SetParentOrigin( Vector3(2.0f/3.0f, 2.0f/3.0f, 0.5f) );
266 green.SetSize( actorSize );
268 // Add the actors to the view
273 application.SendNotification();
274 application.Render(0);
275 application.Render(10);
277 HitTestAlgorithm::Results results;
278 HitTest(stage, Vector2( 240.0f, 400.0f ), results, &DefaultIsActorTouchableFunction);
279 DALI_TEST_CHECK( results.actor == blue );
280 DALI_TEST_EQUALS( results.actorCoordinates, actorSize * 5.0f/6.0f, TEST_LOCATION );
282 HitTest(stage, stageSize / 3.0f, results, &DefaultIsActorTouchableFunction);
283 DALI_TEST_CHECK( results.actor == blue );
284 DALI_TEST_EQUALS( results.actorCoordinates, actorSize * 0.5f, TEST_LOCATION );
286 HitTest(stage, stageSize * 2.0f / 3.0f, results, &DefaultIsActorTouchableFunction);
287 DALI_TEST_CHECK( results.actor == green );
288 DALI_TEST_EQUALS( results.actorCoordinates, actorSize * 0.5f, TEST_LOCATION );
293 int UtcDaliHitTestAlgorithmOrtho02(void)
295 TestApplication application;
296 tet_infoline("Testing Dali::HitTestAlgorithm with offset Ortho camera()");
298 Stage stage = Stage::GetCurrent();
299 RenderTaskList renderTaskList = stage.GetRenderTaskList();
300 RenderTask defaultRenderTask = renderTaskList.GetTask(0u);
301 Dali::CameraActor cameraActor = defaultRenderTask.GetCameraActor();
303 Vector2 stageSize ( stage.GetSize() );
304 cameraActor.SetOrthographicProjection(-stageSize.x * 0.3f, stageSize.x * 0.7f,
305 stageSize.y * 0.3f, -stageSize.y * 0.7f,
307 cameraActor.SetPosition(0.0f, 0.0f, 1600.0f);
309 Vector2 actorSize( stageSize * 0.5f );
310 // Create two actors with half the size of the stage and set them to be partially overlapping
311 Actor blue = Actor::New();
312 blue.SetName( "Blue" );
313 blue.SetAnchorPoint( AnchorPoint::TOP_LEFT );
314 blue.SetParentOrigin( Vector3(0.2f, 0.2f, 0.5f) );
315 blue.SetSize( actorSize );
318 Actor green = Actor::New( );
319 green.SetName( "Green" );
320 green.SetAnchorPoint( AnchorPoint::TOP_LEFT );
321 green.SetParentOrigin( Vector3(0.4f, 0.4f, 0.5f) );
322 green.SetSize( actorSize );
324 // Add the actors to the view
329 application.SendNotification();
330 application.Render(0);
331 application.Render(10);
334 HitTestAlgorithm::Results results;
335 HitTest(stage, Vector2( 240.0f, 400.0f ), results, &DefaultIsActorTouchableFunction);
336 DALI_TEST_CHECK( results.actor == green );
337 DALI_TEST_EQUALS( results.actorCoordinates, actorSize * 0.6f, 0.01f, TEST_LOCATION );
341 HitTestAlgorithm::Results results;
342 HitTest(stage, Vector2( 0.001f, 0.001f ), results, &DefaultIsActorTouchableFunction);
343 DALI_TEST_CHECK( results.actor == blue );
344 DALI_TEST_EQUALS( results.actorCoordinates, Vector2( 0.001f, 0.001f ), 0.001f, TEST_LOCATION );
348 HitTestAlgorithm::Results results;
349 HitTest(stage, stageSize, results, &DefaultIsActorTouchableFunction);
350 DALI_TEST_CHECK( ! results.actor );
351 DALI_TEST_EQUALS( results.actorCoordinates, Vector2::ZERO, TEST_LOCATION );
356 HitTestAlgorithm::Results results;
357 HitTest(stage, stageSize*0.69f, results, &DefaultIsActorTouchableFunction);
358 DALI_TEST_CHECK( results.actor == green );
359 DALI_TEST_EQUALS( results.actorCoordinates, actorSize * 0.98f, 0.01f, TEST_LOCATION );
365 int UtcDaliHitTestAlgorithmStencil(void)
367 TestApplication application;
368 tet_infoline("Testing Dali::HitTestAlgorithm with a stencil");
370 Stage stage = Stage::GetCurrent();
371 Actor rootLayer = stage.GetRootLayer();
372 rootLayer.SetName( "RootLayer" );
375 Layer layer = Layer::New();
376 layer.SetAnchorPoint( AnchorPoint::TOP_LEFT );
377 layer.SetParentOrigin( ParentOrigin::TOP_LEFT );
378 layer.SetName( "layer" );
381 // Create a stencil and add that to the layer
382 Actor stencil = ImageActor::New(Dali::BufferImage::WHITE() );
383 stencil.SetAnchorPoint( AnchorPoint::TOP_LEFT );
384 stencil.SetParentOrigin( ParentOrigin::TOP_LEFT );
385 stencil.SetSize( 50.0f, 50.0f );
386 stencil.SetDrawMode( DrawMode::STENCIL );
387 stencil.SetName( "stencil" );
388 layer.Add( stencil );
390 // Create a renderable actor and add that to the layer
391 Actor layerHitActor = ImageActor::New();
392 layerHitActor.SetSize( 100.0f, 100.0f );
393 layerHitActor.SetAnchorPoint( AnchorPoint::TOP_LEFT );
394 layerHitActor.SetParentOrigin( ParentOrigin::TOP_LEFT );
395 layerHitActor.SetName( "layerHitActor" );
396 layer.Add( layerHitActor );
399 application.SendNotification();
400 application.Render();
402 // Hit within stencil and actor
404 HitTestAlgorithm::Results results;
405 HitTest(stage, Vector2( 10.0f, 10.0f ), results, &DefaultIsActorTouchableFunction);
406 DALI_TEST_CHECK( results.actor == layerHitActor );
407 tet_printf( "Hit: %s\n", ( results.actor ? results.actor.GetName().c_str() : "NULL" ) );
410 // Hit within actor but outside of stencil, should hit the root-layer
412 HitTestAlgorithm::Results results;
413 HitTest(stage, Vector2( 60.0f, 60.0f ), results, &DefaultIsActorTouchableFunction);
414 DALI_TEST_CHECK( results.actor == rootLayer );
415 tet_printf( "Hit: %s\n", ( results.actor ? results.actor.GetName().c_str() : "NULL" ) );