Merge branch 'devel/master' into tizen
[platform/core/uifw/dali-core.git] / automated-tests / src / dali / utc-Dali-HitTestAlgorithm.cpp
1 /*
2  * Copyright (c) 2016 Samsung Electronics Co., Ltd.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  *
16  */
17
18 #include <iostream>
19
20 #include <stdlib.h>
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>
25
26 using namespace Dali;
27
28 namespace
29 {
30
31 /**
32  * The functor to be used in the hit-test algorithm to check whether the actor is hittable.
33  */
34 bool IsActorHittableFunction(Actor actor, Dali::HitTestAlgorithm::TraverseType type)
35 {
36   bool hittable = false;
37
38   switch (type)
39   {
40     case Dali::HitTestAlgorithm::CHECK_ACTOR:
41     {
42       // Check whether the actor is visible and not fully transparent.
43       if( actor.GetCurrentProperty< bool >( Actor::Property::VISIBLE )
44        && actor.GetCurrentProperty< Vector4 >( Actor::Property::WORLD_COLOR ).a > 0.01f) // not FULLY_TRANSPARENT
45       {
46         // Check whether the actor has the specific name "HittableActor"
47         if(actor.GetProperty< std::string >( Actor::Property::NAME ) == "HittableActor")
48         {
49           hittable = true;
50         }
51       }
52       break;
53     }
54     case Dali::HitTestAlgorithm::DESCEND_ACTOR_TREE:
55     {
56       if( actor.GetCurrentProperty< bool >( Actor::Property::VISIBLE ) ) // Actor is visible, if not visible then none of its children are visible.
57       {
58         hittable = true;
59       }
60       break;
61     }
62     default:
63     {
64       break;
65     }
66   }
67
68   return hittable;
69 };
70
71
72 bool DefaultIsActorTouchableFunction(Dali::Actor actor, Dali::HitTestAlgorithm::TraverseType type)
73 {
74   bool hittable = false;
75
76   switch (type)
77   {
78     case Dali::HitTestAlgorithm::CHECK_ACTOR:
79     {
80       if( actor.GetCurrentProperty< bool >( Actor::Property::VISIBLE ) &&
81           actor.GetProperty< bool >( Actor::Property::SENSITIVE ) &&
82           actor.GetCurrentProperty< Vector4 >( Actor::Property::WORLD_COLOR ).a > 0.01f)
83       {
84         hittable = true;
85       }
86       break;
87     }
88     case Dali::HitTestAlgorithm::DESCEND_ACTOR_TREE:
89     {
90       if( actor.GetCurrentProperty< bool >( Actor::Property::VISIBLE ) && // Actor is visible, if not visible then none of its children are visible.
91           actor.GetProperty< bool >( Actor::Property::SENSITIVE )) // Actor is sensitive, if insensitive none of its children should be hittable either.
92       {
93         hittable = true;
94       }
95       break;
96     }
97     default:
98     {
99       break;
100     }
101   }
102
103   return hittable;
104 };
105
106 } // anonymous namespace
107
108
109 // Positive test case for a method
110 int UtcDaliHitTestAlgorithmWithFunctor(void)
111 {
112   TestApplication application;
113   tet_infoline("Testing Dali::HitTestAlgorithm functor");
114
115   Stage stage = Stage::GetCurrent();
116
117   Actor actor = Actor::New();
118   actor.SetSize(100.0f, 100.0f);
119   actor.SetProperty( Actor::Property::ANCHOR_POINT,AnchorPoint::TOP_LEFT);
120   actor.SetProperty( Actor::Property::NAME,"NonHittableActor");
121   stage.Add(actor);
122
123   // Render and notify
124   application.SendNotification();
125   application.Render();
126
127   Vector2 screenCoordinates( 10.0f, 10.0f );
128   Vector2 localCoordinates;
129   actor.ScreenToLocal( localCoordinates.x, localCoordinates.y, screenCoordinates.x, screenCoordinates.y );
130
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 );
135
136   actor.SetProperty( Actor::Property::NAME,"HittableActor");
137
138   results.actor = Actor();
139   results.actorCoordinates = Vector2::ZERO;
140
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 );
145   END_TEST;
146 }
147
148 int UtcDaliHitTestAlgorithmOrtho01(void)
149 {
150   TestApplication application;
151   tet_infoline("Testing Dali::HitTestAlgorithm with parallel Ortho camera()");
152
153   Stage stage = Stage::GetCurrent();
154   RenderTaskList renderTaskList = stage.GetRenderTaskList();
155   RenderTask defaultRenderTask = renderTaskList.GetTask(0u);
156   Dali::CameraActor cameraActor = defaultRenderTask.GetCameraActor();
157
158   Vector2 stageSize ( stage.GetSize() );
159   cameraActor.SetOrthographicProjection( stageSize );
160   cameraActor.SetPosition(0.0f, 0.0f, 1600.0f);
161
162   Vector2 actorSize( stageSize * 0.5f );
163   // Create two actors with half the size of the stage and set them to be partially overlapping
164   Actor blue = Actor::New();
165   blue.SetProperty( Actor::Property::NAME, "Blue" );
166   blue.SetProperty( Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER );
167   blue.SetProperty( Actor::Property::PARENT_ORIGIN, Vector3(1.0f/3.0f, 1.0f/3.0f, 0.5f) );
168   blue.SetSize( actorSize );
169   blue.SetZ(30.0f);
170
171   Actor green = Actor::New( );
172   green.SetProperty( Actor::Property::NAME, "Green" );
173   green.SetProperty( Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER );
174   green.SetProperty( Actor::Property::PARENT_ORIGIN, Vector3(2.0f/3.0f, 2.0f/3.0f, 0.5f) );
175   green.SetSize( actorSize );
176
177   // Add the actors to the view
178   stage.Add( blue );
179   stage.Add( green );
180
181   // Render and notify
182   application.SendNotification();
183   application.Render(0);
184   application.Render(10);
185
186   HitTestAlgorithm::Results results;
187   HitTest(stage, stageSize / 2.0f, results, &DefaultIsActorTouchableFunction);
188   DALI_TEST_CHECK( results.actor == green );
189   DALI_TEST_EQUALS( results.actorCoordinates, actorSize * 1.0f/6.0f, TEST_LOCATION );
190
191   HitTest(stage, stageSize / 3.0f, results, &DefaultIsActorTouchableFunction);
192   DALI_TEST_CHECK( results.actor == blue );
193   DALI_TEST_EQUALS( results.actorCoordinates, actorSize * 0.5f, TEST_LOCATION );
194
195   HitTest(stage, stageSize * 2.0f / 3.0f, results, &DefaultIsActorTouchableFunction);
196   DALI_TEST_CHECK( results.actor == green );
197   DALI_TEST_EQUALS( results.actorCoordinates, actorSize * 0.5f, TEST_LOCATION );
198   END_TEST;
199 }
200
201
202 int UtcDaliHitTestAlgorithmOrtho02(void)
203 {
204   TestApplication application;
205   tet_infoline("Testing Dali::HitTestAlgorithm with offset Ortho camera()");
206
207   Stage stage = Stage::GetCurrent();
208   RenderTaskList renderTaskList = stage.GetRenderTaskList();
209   RenderTask defaultRenderTask = renderTaskList.GetTask(0u);
210   Dali::CameraActor cameraActor = defaultRenderTask.GetCameraActor();
211
212   Vector2 stageSize ( stage.GetSize() );
213   cameraActor.SetOrthographicProjection(-stageSize.x * 0.3f,  stageSize.x * 0.7f,
214                                          stageSize.y * 0.3f, -stageSize.y * 0.7f,
215                                          800.0f, 4895.0f);
216   cameraActor.SetPosition(0.0f, 0.0f, 1600.0f);
217
218   Vector2 actorSize( stageSize * 0.5f );
219   // Create two actors with half the size of the stage and set them to be partially overlapping
220   Actor blue = Actor::New();
221   blue.SetProperty( Actor::Property::NAME, "Blue" );
222   blue.SetProperty( Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT );
223   blue.SetProperty( Actor::Property::PARENT_ORIGIN, Vector3(0.2f, 0.2f, 0.5f) );
224   blue.SetSize( actorSize );
225   blue.SetZ(30.0f);
226
227   Actor green = Actor::New( );
228   green.SetProperty( Actor::Property::NAME, "Green" );
229   green.SetProperty( Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT );
230   green.SetProperty( Actor::Property::PARENT_ORIGIN, Vector3(0.4f, 0.4f, 0.5f) );
231   green.SetSize( actorSize );
232
233   // Add the actors to the view
234   stage.Add( blue );
235   stage.Add( green );
236
237   // Render and notify
238   application.SendNotification();
239   application.Render(0);
240   application.Render(10);
241
242   {
243     HitTestAlgorithm::Results results;
244     HitTest(stage, Vector2( 240.0f, 400.0f ), results, &DefaultIsActorTouchableFunction);
245     DALI_TEST_CHECK( results.actor == green );
246     DALI_TEST_EQUALS( results.actorCoordinates, actorSize * 0.6f, 0.01f, TEST_LOCATION );
247   }
248
249   {
250     HitTestAlgorithm::Results results;
251     HitTest(stage, Vector2( 0.001f, 0.001f ), results, &DefaultIsActorTouchableFunction);
252     DALI_TEST_CHECK( results.actor == blue );
253     DALI_TEST_EQUALS( results.actorCoordinates, Vector2( 0.001f, 0.001f ), 0.001f, TEST_LOCATION );
254   }
255
256   {
257     HitTestAlgorithm::Results results;
258     HitTest(stage, stageSize, results, &DefaultIsActorTouchableFunction);
259     DALI_TEST_CHECK( ! results.actor );
260     DALI_TEST_EQUALS( results.actorCoordinates, Vector2::ZERO, TEST_LOCATION );
261   }
262
263   // Just inside green
264   {
265     HitTestAlgorithm::Results results;
266     HitTest(stage, stageSize*0.69f, results, &DefaultIsActorTouchableFunction);
267     DALI_TEST_CHECK( results.actor == green );
268     DALI_TEST_EQUALS( results.actorCoordinates, actorSize * 0.98f, 0.01f, TEST_LOCATION );
269   }
270
271   END_TEST;
272 }
273
274 int UtcDaliHitTestAlgorithmClippingActor(void)
275 {
276   TestApplication application;
277   tet_infoline("Testing Dali::HitTestAlgorithm with a stencil");
278
279   Stage stage = Stage::GetCurrent();
280   Actor rootLayer = stage.GetRootLayer();
281   rootLayer.SetProperty( Actor::Property::NAME, "RootLayer" );
282
283   // Create a layer
284   Layer layer = Layer::New();
285   layer.SetProperty( Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT );
286   layer.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT );
287   layer.SetProperty( Actor::Property::NAME, "layer" );
288   stage.Add( layer );
289
290   // Create a clipping actor and add it to the layer.
291   Actor clippingActor = CreateRenderableActor( Dali::BufferImage::WHITE() );
292   clippingActor.SetProperty( Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT );
293   clippingActor.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT );
294   clippingActor.SetSize( 50.0f, 50.0f );
295   clippingActor.SetProperty( Actor::Property::CLIPPING_MODE, ClippingMode::CLIP_CHILDREN );
296   clippingActor.SetProperty( Actor::Property::NAME, "clippingActor" );
297   layer.Add( clippingActor );
298
299   // Create a renderable actor and add it to the clipping actor.
300   Actor childActor = CreateRenderableActor( Dali::BufferImage::WHITE() );
301   childActor.SetSize( 100.0f, 100.0f );
302   childActor.SetProperty( Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT );
303   childActor.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT );
304   childActor.SetProperty( Actor::Property::NAME, "childActor" );
305   clippingActor.Add( childActor );
306
307   // Render and notify
308   application.SendNotification();
309   application.Render();
310
311   // Hit within clippingActor and childActor.
312   HitTestAlgorithm::Results results;
313   HitTest( stage, Vector2( 10.0f, 10.0f ), results, &DefaultIsActorTouchableFunction );
314   DALI_TEST_CHECK( results.actor == childActor );
315   tet_printf( "Hit: %s\n", ( results.actor ? results.actor.GetProperty< std::string >( Actor::Property::NAME ).c_str() : "NULL" ) );
316
317   // Hit within childActor but outside of clippingActor, should hit the root-layer instead.
318   HitTest( stage, Vector2( 60.0f, 60.0f ), results, &DefaultIsActorTouchableFunction);
319   DALI_TEST_CHECK( results.actor == rootLayer );
320   tet_printf( "Hit: %s\n", ( results.actor ? results.actor.GetProperty< std::string >( Actor::Property::NAME ).c_str() : "NULL" ) );
321
322   END_TEST;
323 }
324
325 int UtcDaliHitTestAlgorithmOverlay(void)
326 {
327   TestApplication application;
328   tet_infoline("Testing Dali::HitTestAlgorithm with overlay actors");
329
330   Stage stage = Stage::GetCurrent();
331   RenderTaskList renderTaskList = stage.GetRenderTaskList();
332   RenderTask defaultRenderTask = renderTaskList.GetTask(0u);
333   Dali::CameraActor cameraActor = defaultRenderTask.GetCameraActor();
334
335   Vector2 stageSize ( stage.GetSize() );
336   cameraActor.SetOrthographicProjection( stageSize );
337   cameraActor.SetPosition(0.0f, 0.0f, 1600.0f);
338
339   Vector2 actorSize( stageSize * 0.5f );
340   // Create two actors with half the size of the stage and set them to be partially overlapping
341   Actor blue = Actor::New();
342   blue.SetProperty( Actor::Property::DRAW_MODE, DrawMode::OVERLAY_2D );
343   blue.SetProperty( Actor::Property::NAME, "Blue" );
344   blue.SetProperty( Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER );
345   blue.SetProperty( Actor::Property::PARENT_ORIGIN, Vector3(1.0f/3.0f, 1.0f/3.0f, 0.5f) );
346   blue.SetSize( actorSize );
347   blue.SetZ(30.0f);
348
349   Actor green = Actor::New( );
350   green.SetProperty( Actor::Property::NAME, "Green" );
351   green.SetProperty( Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER );
352   green.SetProperty( Actor::Property::PARENT_ORIGIN, Vector3(2.0f/3.0f, 2.0f/3.0f, 0.5f) );
353   green.SetSize( actorSize );
354
355   // Add the actors to the view
356   stage.Add( blue );
357   stage.Add( green );
358
359   // Render and notify
360   application.SendNotification();
361   application.Render(0);
362   application.Render(10);
363
364   HitTestAlgorithm::Results results;
365
366   //Hit in the intersection. Should pick the blue actor since it is an overlay.
367   HitTest(stage, stageSize / 2.0f, results, &DefaultIsActorTouchableFunction);
368   DALI_TEST_CHECK( results.actor == blue );
369   DALI_TEST_EQUALS( results.actorCoordinates, actorSize * 5.0f/6.0f, TEST_LOCATION );
370
371   //Hit in the blue actor
372   HitTest(stage, stageSize / 3.0f, results, &DefaultIsActorTouchableFunction);
373   DALI_TEST_CHECK( results.actor == blue );
374   DALI_TEST_EQUALS( results.actorCoordinates, actorSize * 0.5f, TEST_LOCATION );
375
376   //Hit in the green actor
377   HitTest(stage, stageSize * 2.0f / 3.0f, results, &DefaultIsActorTouchableFunction);
378   DALI_TEST_CHECK( results.actor == green );
379   DALI_TEST_EQUALS( results.actorCoordinates, actorSize * 0.5f, TEST_LOCATION );
380   END_TEST;
381 }