[3.0] Resource ready signal for Controls (for ImageLoading)
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / control / control-data-impl.cpp
1 /*
2  * Copyright (c) 2017 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 // CLASS HEADER
19 #include "control-data-impl.h"
20
21 // EXTERNAL INCLUDES
22 #include <dali/public-api/common/dali-common.h>
23 #include <dali/integration-api/debug.h>
24
25 #include <dali/devel-api/scripting/enum-helper.h>
26 #include <dali/devel-api/scripting/scripting.h>
27 #include <dali/integration-api/debug.h>
28 #include <dali/public-api/object/type-registry-helper.h>
29 #include <cstring>
30
31 // INTERNAL INCLUDES
32 #include <dali-toolkit/internal/visuals/visual-base-impl.h>
33 #include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
34 #include <dali-toolkit/internal/styling/style-manager-impl.h>
35 #include <dali-toolkit/public-api/visuals/image-visual-properties.h>
36 #include <dali-toolkit/devel-api/visuals/visual-properties-devel.h>
37 #include <dali-toolkit/internal/visuals/visual-string-constants.h>
38 #include <dali-toolkit/devel-api/controls/control-devel.h>
39
40 namespace Dali
41 {
42
43 namespace Toolkit
44 {
45
46 namespace Internal
47 {
48
49 namespace
50 {
51
52 #if defined(DEBUG_ENABLED)
53 Debug::Filter* gLogFilter = Debug::Filter::New( Debug::NoLogging, false, "LOG_CONTROL_VISUALS");
54 #endif
55
56 /**
57  *  Finds visual in given array, returning true if found along with the iterator for that visual as a out parameter
58  */
59 bool FindVisual( Property::Index targetIndex, const RegisteredVisualContainer& visuals, RegisteredVisualContainer::Iterator& iter )
60 {
61   for ( iter = visuals.Begin(); iter != visuals.End(); iter++ )
62   {
63     if ( (*iter)->index ==  targetIndex )
64     {
65       return true;
66     }
67   }
68   return false;
69 }
70
71
72
73
74 /**
75  * Performs actions as requested using the action name.
76  * @param[in] object The object on which to perform the action.
77  * @param[in] actionName The action to perform.
78  * @param[in] attributes The attributes with which to perfrom this action.
79  * @return true if action has been accepted by this control
80  */
81 const char* ACTION_ACCESSIBILITY_ACTIVATED = "accessibilityActivated";
82 static bool DoAction( BaseObject* object, const std::string& actionName, const Property::Map& attributes )
83 {
84   bool ret = false;
85
86   if( object && ( 0 == strcmp( actionName.c_str(), ACTION_ACCESSIBILITY_ACTIVATED ) ) )
87   {
88     Toolkit::Control control = Toolkit::Control::DownCast( BaseHandle( object ) );
89     if( control )
90     {
91       // if cast succeeds there is an implementation so no need to check
92       ret = Internal::GetImplementation( control ).OnAccessibilityActivated();
93     }
94   }
95
96   return ret;
97 }
98
99 /**
100  * Connects a callback function with the object's signals.
101  * @param[in] object The object providing the signal.
102  * @param[in] tracker Used to disconnect the signal.
103  * @param[in] signalName The signal to connect to.
104  * @param[in] functor A newly allocated FunctorDelegate.
105  * @return True if the signal was connected.
106  * @post If a signal was connected, ownership of functor was passed to CallbackBase. Otherwise the caller is responsible for deleting the unused functor.
107  */
108 const char* SIGNAL_KEY_EVENT = "keyEvent";
109 const char* SIGNAL_KEY_INPUT_FOCUS_GAINED = "keyInputFocusGained";
110 const char* SIGNAL_KEY_INPUT_FOCUS_LOST = "keyInputFocusLost";
111 const char* SIGNAL_TAPPED = "tapped";
112 const char* SIGNAL_PANNED = "panned";
113 const char* SIGNAL_PINCHED = "pinched";
114 const char* SIGNAL_LONG_PRESSED = "longPressed";
115 static bool DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
116 {
117   Dali::BaseHandle handle( object );
118
119   bool connected( false );
120   Toolkit::Control control = Toolkit::Control::DownCast( handle );
121   if ( control )
122   {
123     Internal::Control& controlImpl( Internal::GetImplementation( control ) );
124     connected = true;
125
126     if ( 0 == strcmp( signalName.c_str(), SIGNAL_KEY_EVENT ) )
127     {
128       controlImpl.KeyEventSignal().Connect( tracker, functor );
129     }
130     else if( 0 == strcmp( signalName.c_str(), SIGNAL_KEY_INPUT_FOCUS_GAINED ) )
131     {
132       controlImpl.KeyInputFocusGainedSignal().Connect( tracker, functor );
133     }
134     else if( 0 == strcmp( signalName.c_str(), SIGNAL_KEY_INPUT_FOCUS_LOST ) )
135     {
136       controlImpl.KeyInputFocusLostSignal().Connect( tracker, functor );
137     }
138     else if( 0 == strcmp( signalName.c_str(), SIGNAL_TAPPED ) )
139     {
140       controlImpl.EnableGestureDetection( Gesture::Tap );
141       controlImpl.GetTapGestureDetector().DetectedSignal().Connect( tracker, functor );
142     }
143     else if( 0 == strcmp( signalName.c_str(), SIGNAL_PANNED ) )
144     {
145       controlImpl.EnableGestureDetection( Gesture::Pan );
146       controlImpl.GetPanGestureDetector().DetectedSignal().Connect( tracker, functor );
147     }
148     else if( 0 == strcmp( signalName.c_str(), SIGNAL_PINCHED ) )
149     {
150       controlImpl.EnableGestureDetection( Gesture::Pinch );
151       controlImpl.GetPinchGestureDetector().DetectedSignal().Connect( tracker, functor );
152     }
153     else if( 0 == strcmp( signalName.c_str(), SIGNAL_LONG_PRESSED ) )
154     {
155       controlImpl.EnableGestureDetection( Gesture::LongPress );
156       controlImpl.GetLongPressGestureDetector().DetectedSignal().Connect( tracker, functor );
157     }
158   }
159   return connected;
160 }
161
162 /**
163  * Creates control through type registry
164  */
165 BaseHandle Create()
166 {
167   return Internal::Control::New();
168 }
169 // Setup signals and actions using the type-registry.
170 DALI_TYPE_REGISTRATION_BEGIN( Control, CustomActor, Create );
171
172 // Note: Properties are registered separately below.
173
174 SignalConnectorType registerSignal1( typeRegistration, SIGNAL_KEY_EVENT, &DoConnectSignal );
175 SignalConnectorType registerSignal2( typeRegistration, SIGNAL_KEY_INPUT_FOCUS_GAINED, &DoConnectSignal );
176 SignalConnectorType registerSignal3( typeRegistration, SIGNAL_KEY_INPUT_FOCUS_LOST, &DoConnectSignal );
177 SignalConnectorType registerSignal4( typeRegistration, SIGNAL_TAPPED, &DoConnectSignal );
178 SignalConnectorType registerSignal5( typeRegistration, SIGNAL_PANNED, &DoConnectSignal );
179 SignalConnectorType registerSignal6( typeRegistration, SIGNAL_PINCHED, &DoConnectSignal );
180 SignalConnectorType registerSignal7( typeRegistration, SIGNAL_LONG_PRESSED, &DoConnectSignal );
181
182 TypeAction registerAction( typeRegistration, ACTION_ACCESSIBILITY_ACTIVATED, &DoAction );
183
184 DALI_TYPE_REGISTRATION_END()
185
186 } // unnamed namespace
187
188
189 // Properties registered without macro to use specific member variables.
190 const PropertyRegistration Control::Impl::PROPERTY_1( typeRegistration, "styleName",              Toolkit::Control::Property::STYLE_NAME,                   Property::STRING,  &Control::Impl::SetProperty, &Control::Impl::GetProperty );
191 const PropertyRegistration Control::Impl::PROPERTY_2( typeRegistration, "backgroundColor",        Toolkit::Control::Property::BACKGROUND_COLOR,             Property::VECTOR4, &Control::Impl::SetProperty, &Control::Impl::GetProperty );
192 const PropertyRegistration Control::Impl::PROPERTY_3( typeRegistration, "backgroundImage",        Toolkit::Control::Property::BACKGROUND_IMAGE,             Property::MAP,     &Control::Impl::SetProperty, &Control::Impl::GetProperty );
193 const PropertyRegistration Control::Impl::PROPERTY_4( typeRegistration, "keyInputFocus",          Toolkit::Control::Property::KEY_INPUT_FOCUS,              Property::BOOLEAN, &Control::Impl::SetProperty, &Control::Impl::GetProperty );
194 const PropertyRegistration Control::Impl::PROPERTY_5( typeRegistration, "background",             Toolkit::Control::Property::BACKGROUND,                   Property::MAP,     &Control::Impl::SetProperty, &Control::Impl::GetProperty );
195
196
197
198 Control::Impl::Impl( Control& controlImpl )
199 : mControlImpl( controlImpl ),
200   mStyleName(""),
201   mBackgroundColor(Color::TRANSPARENT),
202   mStartingPinchScale( NULL ),
203   mKeyEventSignal(),
204   mPinchGestureDetector(),
205   mPanGestureDetector(),
206   mTapGestureDetector(),
207   mLongPressGestureDetector(),
208   mFlags( Control::ControlBehaviour( CONTROL_BEHAVIOUR_DEFAULT ) ),
209   mIsKeyboardNavigationSupported( false ),
210   mIsKeyboardFocusGroup( false )
211 {
212
213 }
214
215 Control::Impl::~Impl()
216 {
217   // All gesture detectors will be destroyed so no need to disconnect.
218   delete mStartingPinchScale;
219 }
220
221 Control::Impl& Control::Impl::Get( Internal::Control& internalControl )
222 {
223   return *internalControl.mImpl;
224 }
225
226 const Control::Impl& Control::Impl::Get( const Internal::Control& internalControl )
227 {
228   return *internalControl.mImpl;
229 }
230
231 // Gesture Detection Methods
232 void Control::Impl::PinchDetected(Actor actor, const PinchGesture& pinch)
233 {
234   mControlImpl.OnPinch(pinch);
235 }
236
237 void Control::Impl::PanDetected(Actor actor, const PanGesture& pan)
238 {
239   mControlImpl.OnPan(pan);
240 }
241
242 void Control::Impl::TapDetected(Actor actor, const TapGesture& tap)
243 {
244   mControlImpl.OnTap(tap);
245 }
246
247 void Control::Impl::LongPressDetected(Actor actor, const LongPressGesture& longPress)
248 {
249   mControlImpl.OnLongPress(longPress);
250 }
251
252 // Called by a Visual when it's resource is ready
253 void Control::Impl::ResourceReady( Visual::Base& object)
254 {
255
256   // go through and check if all the visuals are ready, if they are emit a signal
257   for ( RegisteredVisualContainer::ConstIterator visualIter = mVisuals.Begin();
258         visualIter != mVisuals.End(); ++visualIter )
259   {
260     const Toolkit::Visual::Base visual = (*visualIter)->visual;
261     const Internal::Visual::Base& visualImpl = Toolkit::GetImplementation( visual );
262
263     // one of the visuals is not ready
264     if( !visualImpl.IsResourceReady() )
265     {
266       return;
267     }
268   }
269
270   // all the visuals are ready
271   Dali::Toolkit::Control handle( mControlImpl.GetOwner() );
272   mResourceReadySignal.Emit( handle );
273
274 }
275
276 bool Control::Impl::IsResourceReady() const
277 {
278   // go through and check all the visuals are ready
279   for ( RegisteredVisualContainer::ConstIterator visualIter = mVisuals.Begin();
280          visualIter != mVisuals.End(); ++visualIter )
281    {
282      const Toolkit::Visual::Base visual = (*visualIter)->visual;
283      const Internal::Visual::Base& visualImpl = Toolkit::GetImplementation( visual );
284
285      // one of the visuals is not ready
286      if( !visualImpl.IsResourceReady()  )
287      {
288        return false;
289      }
290    }
291   return true;
292 }
293
294 void Control::Impl::RegisterVisual( Property::Index index, Toolkit::Visual::Base& visual )
295 {
296   RegisterVisual( index, visual, true );
297 }
298
299 void Control::Impl::RegisterVisual( Property::Index index, Toolkit::Visual::Base& visual, bool enabled )
300 {
301   bool visualReplaced ( false );
302   Actor self = mControlImpl.Self();
303
304   if( !mVisuals.Empty() )
305   {
306     RegisteredVisualContainer::Iterator iter;
307     // Check if visual (index) is already registered.  Replace if so.
308     if ( FindVisual( index, mVisuals, iter ) )
309     {
310       if( (*iter)->visual && self.OnStage() )
311       {
312         Toolkit::GetImplementation((*iter)->visual).SetOffStage( self );
313       }
314
315       StopObservingVisual( (*iter)->visual );
316       StartObservingVisual( visual );
317
318       (*iter)->visual = visual;
319       visualReplaced = true;
320     }
321   }
322
323   if( !visualReplaced ) // New registration entry
324   {
325     mVisuals.PushBack( new RegisteredVisual( index, visual, enabled ) );
326
327     // monitor when the visuals resources are ready
328     StartObservingVisual( visual );
329
330   }
331
332   if( visual && self.OnStage() && enabled )
333   {
334     Toolkit::GetImplementation(visual).SetOnStage( self );
335   }
336
337   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Control::RegisterVisual() Registered %s(%d), enabled:%s\n",  visual.GetName().c_str(), index, enabled?"T":"F" );
338 }
339
340 void Control::Impl::UnregisterVisual( Property::Index index )
341 {
342    RegisteredVisualContainer::Iterator iter;
343    if ( FindVisual( index, mVisuals, iter ) )
344    {
345      // stop observing visual
346      StopObservingVisual( (*iter)->visual );
347
348      Actor self( mControlImpl.Self() );
349      Toolkit::GetImplementation((*iter)->visual).SetOffStage( self );
350      (*iter)->visual.Reset();
351      mVisuals.Erase( iter );
352    }
353 }
354
355 Toolkit::Visual::Base Control::Impl::GetVisual( Property::Index index ) const
356 {
357   RegisteredVisualContainer::Iterator iter;
358   if ( FindVisual( index, mVisuals, iter ) )
359   {
360     return (*iter)->visual;
361   }
362
363   return Toolkit::Visual::Base();
364 }
365
366 void Control::Impl::EnableVisual( Property::Index index, bool enable )
367 {
368   RegisteredVisualContainer::Iterator iter;
369   if ( FindVisual( index, mVisuals, iter ) )
370   {
371     if (  (*iter)->enabled == enable )
372     {
373       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Control::EnableVisual Visual %s(%d) already %s\n", (*iter)->visual.GetName().c_str(), index, enable?"enabled":"disabled");
374       return;
375     }
376
377     (*iter)->enabled = enable;
378     Actor parentActor = mControlImpl.Self();
379     if ( mControlImpl.Self().OnStage() ) // If control not on Stage then Visual will be added when StageConnection is called.
380     {
381       if ( enable )
382       {
383         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Control::EnableVisual Setting %s(%d) on stage \n", (*iter)->visual.GetName().c_str(), index );
384         Toolkit::GetImplementation((*iter)->visual).SetOnStage( parentActor );
385       }
386       else
387       {
388         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Control::EnableVisual Setting %s(%d) off stage \n", (*iter)->visual.GetName().c_str(), index );
389         Toolkit::GetImplementation((*iter)->visual).SetOffStage( parentActor );  // No need to call if control not staged.
390       }
391     }
392   }
393 }
394
395 bool Control::Impl::IsVisualEnabled( Property::Index index ) const
396 {
397   RegisteredVisualContainer::Iterator iter;
398   if ( FindVisual( index, mVisuals, iter ) )
399   {
400     return (*iter)->enabled;
401   }
402   return false;
403 }
404
405 void Control::Impl::StopObservingVisual( Toolkit::Visual::Base& visual )
406 {
407   Internal::Visual::Base& visualImpl = Toolkit::GetImplementation( visual );
408
409   // Stop observing the visual
410   visualImpl.RemoveResourceObserver( *this );
411 }
412
413 void Control::Impl::StartObservingVisual( Toolkit::Visual::Base& visual)
414 {
415   Internal::Visual::Base& visualImpl = Toolkit::GetImplementation( visual );
416
417   // start observing the visual for resource ready
418   visualImpl.AddResourceObserver( *this );
419 }
420
421 void Control::Impl::SetProperty( BaseObject* object, Property::Index index, const Property::Value& value )
422 {
423   Toolkit::Control control = Toolkit::Control::DownCast( BaseHandle( object ) );
424
425   if ( control )
426   {
427     Control& controlImpl( GetImplementation( control ) );
428
429     switch ( index )
430     {
431       case Toolkit::Control::Property::STYLE_NAME:
432       {
433         controlImpl.SetStyleName( value.Get< std::string >() );
434         break;
435       }
436
437       case Toolkit::Control::Property::BACKGROUND_COLOR:
438       {
439         DALI_LOG_WARNING( "BACKGROUND_COLOR property is deprecated. Use BACKGROUND property instead\n" );
440         controlImpl.SetBackgroundColor( value.Get< Vector4 >() );
441         break;
442       }
443
444       case Toolkit::Control::Property::BACKGROUND_IMAGE:
445       {
446         DALI_LOG_WARNING( "BACKGROUND_IMAGE property is deprecated. Use BACKGROUND property instead\n" );
447         Image image = Scripting::NewImage( value );
448         if ( image )
449         {
450           controlImpl.SetBackgroundImage( image );
451         }
452         else
453         {
454           // An empty image means the background is no longer required
455           controlImpl.ClearBackground();
456         }
457         break;
458       }
459
460       case Toolkit::Control::Property::KEY_INPUT_FOCUS:
461       {
462         if ( value.Get< bool >() )
463         {
464           controlImpl.SetKeyInputFocus();
465         }
466         else
467         {
468           controlImpl.ClearKeyInputFocus();
469         }
470         break;
471       }
472
473       case Toolkit::Control::Property::BACKGROUND:
474       {
475         std::string url;
476         Vector4 color;
477         const Property::Map* map = value.GetMap();
478         if( map && !map->Empty() )
479         {
480           controlImpl.SetBackground( *map );
481         }
482         else if( value.Get( url ) )
483         {
484           // don't know the size to load
485           Toolkit::Visual::Base visual = Toolkit::VisualFactory::Get().CreateVisual( url, ImageDimensions() );
486           if( visual )
487           {
488             controlImpl.mImpl->RegisterVisual( Toolkit::Control::Property::BACKGROUND, visual );
489             visual.SetDepthIndex( DepthIndex::BACKGROUND );
490           }
491         }
492         else if( value.Get( color ) )
493         {
494           controlImpl.SetBackgroundColor(color);
495         }
496         else
497         {
498           // The background is an empty property map, so we should clear the background
499           controlImpl.ClearBackground();
500         }
501         break;
502       }
503     }
504   }
505 }
506
507 Property::Value Control::Impl::GetProperty( BaseObject* object, Property::Index index )
508 {
509   Property::Value value;
510
511   Toolkit::Control control = Toolkit::Control::DownCast( BaseHandle( object ) );
512
513   if ( control )
514   {
515     Control& controlImpl( GetImplementation( control ) );
516
517     switch ( index )
518     {
519       case Toolkit::Control::Property::STYLE_NAME:
520       {
521         value = controlImpl.GetStyleName();
522         break;
523       }
524       case Toolkit::Control::Property::BACKGROUND_COLOR:
525       {
526         DALI_LOG_WARNING( "BACKGROUND_COLOR property is deprecated. Use BACKGROUND property instead\n" );
527         value = controlImpl.GetBackgroundColor();
528         break;
529       }
530
531       case Toolkit::Control::Property::BACKGROUND_IMAGE:
532       {
533         DALI_LOG_WARNING( "BACKGROUND_IMAGE property is deprecated. Use BACKGROUND property instead\n" );
534         Property::Map map;
535         Toolkit::Visual::Base visual = controlImpl.mImpl->GetVisual( Toolkit::Control::Property::BACKGROUND );
536         if( visual )
537         {
538           visual.CreatePropertyMap( map );
539         }
540         value = map;
541         break;
542       }
543
544       case Toolkit::Control::Property::KEY_INPUT_FOCUS:
545       {
546         value = controlImpl.HasKeyInputFocus();
547         break;
548       }
549
550       case Toolkit::Control::Property::BACKGROUND:
551       {
552         Property::Map map;
553         Toolkit::Visual::Base visual = controlImpl.mImpl->GetVisual( Toolkit::Control::Property::BACKGROUND );
554         if( visual )
555         {
556           visual.CreatePropertyMap( map );
557         }
558
559         value = map;
560         break;
561       }
562
563     }
564   }
565
566   return value;
567 }
568
569 void Control::Impl::RemoveVisual( RegisteredVisualContainer& visuals, const std::string& visualName )
570 {
571   Actor self( mControlImpl.Self() );
572
573   for ( RegisteredVisualContainer::Iterator visualIter = visuals.Begin();
574         visualIter != visuals.End(); ++visualIter )
575   {
576     Toolkit::Visual::Base visual = (*visualIter)->visual;
577     if( visual && visual.GetName() == visualName )
578     {
579       Toolkit::GetImplementation(visual).SetOffStage( self );
580       (*visualIter)->visual.Reset();
581       visuals.Erase( visualIter );
582       break;
583     }
584   }
585 }
586
587 } // namespace Internal
588
589 } // namespace Toolkit
590
591 } // namespace Dali