[Tizen] Stop observing visuals when a control is destroyed
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / control / control-data-impl.cpp
1 /*
2  * Copyright (c) 2019 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-toolkit/public-api/dali-toolkit-common.h>
23 #include <dali/integration-api/debug.h>
24 #include <dali/devel-api/object/handle-devel.h>
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 <dali/integration-api/adaptor-framework/adaptor.h>
30 #include <cstring>
31 #include <limits>
32
33 // INTERNAL INCLUDES
34 #include <dali-toolkit/internal/visuals/visual-base-impl.h>
35 #include <dali-toolkit/public-api/visuals/image-visual-properties.h>
36 #include <dali-toolkit/public-api/visuals/visual-properties.h>
37 #include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
38 #include <dali-toolkit/devel-api/controls/control-devel.h>
39 #include <dali-toolkit/devel-api/controls/control-wrapper-impl.h>
40 #include <dali-toolkit/internal/styling/style-manager-impl.h>
41 #include <dali-toolkit/internal/visuals/visual-string-constants.h>
42
43 namespace Dali
44 {
45
46 namespace Toolkit
47 {
48
49 namespace Internal
50 {
51
52 extern const Dali::Scripting::StringEnum ControlStateTable[];
53 extern const unsigned int ControlStateTableCount;
54
55
56 // Not static or anonymous - shared with other translation units
57 const Scripting::StringEnum ControlStateTable[] = {
58   { "NORMAL",   Toolkit::DevelControl::NORMAL   },
59   { "FOCUSED",  Toolkit::DevelControl::FOCUSED  },
60   { "DISABLED", Toolkit::DevelControl::DISABLED },
61 };
62 const unsigned int ControlStateTableCount = sizeof( ControlStateTable ) / sizeof( ControlStateTable[0] );
63
64
65
66 namespace
67 {
68
69 #if defined(DEBUG_ENABLED)
70 Debug::Filter* gLogFilter = Debug::Filter::New( Debug::NoLogging, false, "LOG_CONTROL_VISUALS");
71 #endif
72
73
74 template<typename T>
75 void Remove( Dictionary<T>& keyValues, const std::string& name )
76 {
77   keyValues.Remove(name);
78 }
79
80 void Remove( DictionaryKeys& keys, const std::string& name )
81 {
82   DictionaryKeys::iterator iter = std::find( keys.begin(), keys.end(), name );
83   if( iter != keys.end())
84   {
85     keys.erase(iter);
86   }
87 }
88
89 Toolkit::Visual::Type GetVisualTypeFromMap( const Property::Map& map )
90 {
91   Property::Value* typeValue = map.Find( Toolkit::Visual::Property::TYPE, VISUAL_TYPE  );
92   Toolkit::Visual::Type type = Toolkit::Visual::IMAGE;
93   if( typeValue )
94   {
95     Scripting::GetEnumerationProperty( *typeValue, VISUAL_TYPE_TABLE, VISUAL_TYPE_TABLE_COUNT, type );
96   }
97   return type;
98 }
99
100 /**
101  *  Finds visual in given array, returning true if found along with the iterator for that visual as a out parameter
102  */
103 bool FindVisual( Property::Index targetIndex, const RegisteredVisualContainer& visuals, RegisteredVisualContainer::Iterator& iter )
104 {
105   for ( iter = visuals.Begin(); iter != visuals.End(); iter++ )
106   {
107     if ( (*iter)->index ==  targetIndex )
108     {
109       return true;
110     }
111   }
112   return false;
113 }
114
115 void FindChangableVisuals( Dictionary<Property::Map>& stateVisualsToAdd,
116                            Dictionary<Property::Map>& stateVisualsToChange,
117                            DictionaryKeys& stateVisualsToRemove)
118 {
119   DictionaryKeys copyOfStateVisualsToRemove = stateVisualsToRemove;
120
121   for( DictionaryKeys::iterator iter = copyOfStateVisualsToRemove.begin();
122        iter != copyOfStateVisualsToRemove.end(); ++iter )
123   {
124     const std::string& visualName = (*iter);
125     Property::Map* toMap = stateVisualsToAdd.Find( visualName );
126     if( toMap )
127     {
128       stateVisualsToChange.Add( visualName, *toMap );
129       stateVisualsToAdd.Remove( visualName );
130       Remove( stateVisualsToRemove, visualName );
131     }
132   }
133 }
134
135 Toolkit::Visual::Base GetVisualByName(
136   const RegisteredVisualContainer& visuals,
137   const std::string& visualName )
138 {
139   Toolkit::Visual::Base visualHandle;
140
141   RegisteredVisualContainer::Iterator iter;
142   for ( iter = visuals.Begin(); iter != visuals.End(); iter++ )
143   {
144     Toolkit::Visual::Base visual = (*iter)->visual;
145     if( visual && visual.GetName() == visualName )
146     {
147       visualHandle = visual;
148       break;
149     }
150   }
151   return visualHandle;
152 }
153
154 /**
155  * Move visual from source to destination container
156  */
157 void MoveVisual( RegisteredVisualContainer::Iterator sourceIter, RegisteredVisualContainer& source, RegisteredVisualContainer& destination )
158 {
159    Toolkit::Visual::Base visual = (*sourceIter)->visual;
160    if( visual )
161    {
162      RegisteredVisual* rv = source.Release( sourceIter );
163      destination.PushBack( rv );
164    }
165 }
166
167 /**
168  * Performs actions as requested using the action name.
169  * @param[in] object The object on which to perform the action.
170  * @param[in] actionName The action to perform.
171  * @param[in] attributes The attributes with which to perfrom this action.
172  * @return true if action has been accepted by this control
173  */
174 const char* ACTION_ACCESSIBILITY_ACTIVATED = "accessibilityActivated";
175 static bool DoAction( BaseObject* object, const std::string& actionName, const Property::Map& attributes )
176 {
177   bool ret = false;
178
179   if( object && ( 0 == strcmp( actionName.c_str(), ACTION_ACCESSIBILITY_ACTIVATED ) ) )
180   {
181     Toolkit::Control control = Toolkit::Control::DownCast( BaseHandle( object ) );
182     if( control )
183     {
184       // if cast succeeds there is an implementation so no need to check
185       ret = Internal::GetImplementation( control ).OnAccessibilityActivated();
186     }
187   }
188
189   return ret;
190 }
191
192 /**
193  * Connects a callback function with the object's signals.
194  * @param[in] object The object providing the signal.
195  * @param[in] tracker Used to disconnect the signal.
196  * @param[in] signalName The signal to connect to.
197  * @param[in] functor A newly allocated FunctorDelegate.
198  * @return True if the signal was connected.
199  * @post If a signal was connected, ownership of functor was passed to CallbackBase. Otherwise the caller is responsible for deleting the unused functor.
200  */
201 const char* SIGNAL_KEY_EVENT = "keyEvent";
202 const char* SIGNAL_KEY_INPUT_FOCUS_GAINED = "keyInputFocusGained";
203 const char* SIGNAL_KEY_INPUT_FOCUS_LOST = "keyInputFocusLost";
204 const char* SIGNAL_TAPPED = "tapped";
205 const char* SIGNAL_PANNED = "panned";
206 const char* SIGNAL_PINCHED = "pinched";
207 const char* SIGNAL_LONG_PRESSED = "longPressed";
208 static bool DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
209 {
210   Dali::BaseHandle handle( object );
211
212   bool connected( false );
213   Toolkit::Control control = Toolkit::Control::DownCast( handle );
214   if ( control )
215   {
216     Internal::Control& controlImpl( Internal::GetImplementation( control ) );
217     connected = true;
218
219     if ( 0 == strcmp( signalName.c_str(), SIGNAL_KEY_EVENT ) )
220     {
221       controlImpl.KeyEventSignal().Connect( tracker, functor );
222     }
223     else if( 0 == strcmp( signalName.c_str(), SIGNAL_KEY_INPUT_FOCUS_GAINED ) )
224     {
225       controlImpl.KeyInputFocusGainedSignal().Connect( tracker, functor );
226     }
227     else if( 0 == strcmp( signalName.c_str(), SIGNAL_KEY_INPUT_FOCUS_LOST ) )
228     {
229       controlImpl.KeyInputFocusLostSignal().Connect( tracker, functor );
230     }
231     else if( 0 == strcmp( signalName.c_str(), SIGNAL_TAPPED ) )
232     {
233       controlImpl.EnableGestureDetection( GestureType::TAP );
234       controlImpl.GetTapGestureDetector().DetectedSignal().Connect( tracker, functor );
235     }
236     else if( 0 == strcmp( signalName.c_str(), SIGNAL_PANNED ) )
237     {
238       controlImpl.EnableGestureDetection( GestureType::PAN );
239       controlImpl.GetPanGestureDetector().DetectedSignal().Connect( tracker, functor );
240     }
241     else if( 0 == strcmp( signalName.c_str(), SIGNAL_PINCHED ) )
242     {
243       controlImpl.EnableGestureDetection( GestureType::PINCH );
244       controlImpl.GetPinchGestureDetector().DetectedSignal().Connect( tracker, functor );
245     }
246     else if( 0 == strcmp( signalName.c_str(), SIGNAL_LONG_PRESSED ) )
247     {
248       controlImpl.EnableGestureDetection( GestureType::LONG_PRESS );
249       controlImpl.GetLongPressGestureDetector().DetectedSignal().Connect( tracker, functor );
250     }
251   }
252   return connected;
253 }
254
255 /**
256  * Creates control through type registry
257  */
258 BaseHandle Create()
259 {
260   return Internal::Control::New();
261 }
262 // Setup signals and actions using the type-registry.
263 DALI_TYPE_REGISTRATION_BEGIN( Control, CustomActor, Create );
264
265 // Note: Properties are registered separately below.
266
267 SignalConnectorType registerSignal1( typeRegistration, SIGNAL_KEY_EVENT, &DoConnectSignal );
268 SignalConnectorType registerSignal2( typeRegistration, SIGNAL_KEY_INPUT_FOCUS_GAINED, &DoConnectSignal );
269 SignalConnectorType registerSignal3( typeRegistration, SIGNAL_KEY_INPUT_FOCUS_LOST, &DoConnectSignal );
270 SignalConnectorType registerSignal4( typeRegistration, SIGNAL_TAPPED, &DoConnectSignal );
271 SignalConnectorType registerSignal5( typeRegistration, SIGNAL_PANNED, &DoConnectSignal );
272 SignalConnectorType registerSignal6( typeRegistration, SIGNAL_PINCHED, &DoConnectSignal );
273 SignalConnectorType registerSignal7( typeRegistration, SIGNAL_LONG_PRESSED, &DoConnectSignal );
274
275 TypeAction registerAction( typeRegistration, ACTION_ACCESSIBILITY_ACTIVATED, &DoAction );
276
277 DALI_TYPE_REGISTRATION_END()
278
279 /**
280  * @brief Iterate through given container and setOffScene any visual found
281  *
282  * @param[in] container Container of visuals
283  * @param[in] parent Parent actor to remove visuals from
284  */
285 void SetVisualsOffScene( const RegisteredVisualContainer& container, Actor parent )
286 {
287   for( auto iter = container.Begin(), end = container.End() ; iter!= end; iter++)
288   {
289     if( (*iter)->visual )
290     {
291       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Control::SetOffScene Setting visual(%d) off stage\n", (*iter)->index );
292       Toolkit::GetImplementation((*iter)->visual).SetOffScene( parent );
293     }
294   }
295 }
296
297 } // unnamed namespace
298
299
300 // Properties registered without macro to use specific member variables.
301 const PropertyRegistration Control::Impl::PROPERTY_1( typeRegistration, "styleName",              Toolkit::Control::Property::STYLE_NAME,                   Property::STRING,  &Control::Impl::SetProperty, &Control::Impl::GetProperty );
302 const PropertyRegistration Control::Impl::PROPERTY_4( typeRegistration, "keyInputFocus",          Toolkit::Control::Property::KEY_INPUT_FOCUS,              Property::BOOLEAN, &Control::Impl::SetProperty, &Control::Impl::GetProperty );
303 const PropertyRegistration Control::Impl::PROPERTY_5( typeRegistration, "background",             Toolkit::Control::Property::BACKGROUND,                   Property::MAP,     &Control::Impl::SetProperty, &Control::Impl::GetProperty );
304 const PropertyRegistration Control::Impl::PROPERTY_6( typeRegistration, "margin",                 Toolkit::Control::Property::MARGIN,                       Property::EXTENTS, &Control::Impl::SetProperty, &Control::Impl::GetProperty );
305 const PropertyRegistration Control::Impl::PROPERTY_7( typeRegistration, "padding",                Toolkit::Control::Property::PADDING,                      Property::EXTENTS, &Control::Impl::SetProperty, &Control::Impl::GetProperty );
306 const PropertyRegistration Control::Impl::PROPERTY_8( typeRegistration, "tooltip",                Toolkit::DevelControl::Property::TOOLTIP,                 Property::MAP,     &Control::Impl::SetProperty, &Control::Impl::GetProperty );
307 const PropertyRegistration Control::Impl::PROPERTY_9( typeRegistration, "state",                  Toolkit::DevelControl::Property::STATE,                   Property::STRING,  &Control::Impl::SetProperty, &Control::Impl::GetProperty );
308 const PropertyRegistration Control::Impl::PROPERTY_10( typeRegistration, "subState",               Toolkit::DevelControl::Property::SUB_STATE,               Property::STRING,  &Control::Impl::SetProperty, &Control::Impl::GetProperty );
309 const PropertyRegistration Control::Impl::PROPERTY_11( typeRegistration, "leftFocusableActorId",   Toolkit::DevelControl::Property::LEFT_FOCUSABLE_ACTOR_ID, Property::INTEGER, &Control::Impl::SetProperty, &Control::Impl::GetProperty );
310 const PropertyRegistration Control::Impl::PROPERTY_12( typeRegistration, "rightFocusableActorId", Toolkit::DevelControl::Property::RIGHT_FOCUSABLE_ACTOR_ID,Property::INTEGER, &Control::Impl::SetProperty, &Control::Impl::GetProperty );
311 const PropertyRegistration Control::Impl::PROPERTY_13( typeRegistration, "upFocusableActorId",    Toolkit::DevelControl::Property::UP_FOCUSABLE_ACTOR_ID,   Property::INTEGER, &Control::Impl::SetProperty, &Control::Impl::GetProperty );
312 const PropertyRegistration Control::Impl::PROPERTY_14( typeRegistration, "downFocusableActorId",  Toolkit::DevelControl::Property::DOWN_FOCUSABLE_ACTOR_ID, Property::INTEGER, &Control::Impl::SetProperty, &Control::Impl::GetProperty );
313 const PropertyRegistration Control::Impl::PROPERTY_15( typeRegistration, "shadow",                Toolkit::DevelControl::Property::SHADOW,                  Property::MAP,     &Control::Impl::SetProperty, &Control::Impl::GetProperty );
314
315 Control::Impl::Impl( Control& controlImpl )
316 : mControlImpl( controlImpl ),
317   mState( Toolkit::DevelControl::NORMAL ),
318   mSubStateName(""),
319   mLeftFocusableActorId( -1 ),
320   mRightFocusableActorId( -1 ),
321   mUpFocusableActorId( -1 ),
322   mDownFocusableActorId( -1 ),
323   mStyleName(""),
324   mBackgroundColor(Color::TRANSPARENT),
325   mStartingPinchScale(nullptr),
326   mMargin( 0, 0, 0, 0 ),
327   mPadding( 0, 0, 0, 0 ),
328   mKeyEventSignal(),
329   mKeyInputFocusGainedSignal(),
330   mKeyInputFocusLostSignal(),
331   mResourceReadySignal(),
332   mVisualEventSignal(),
333   mPinchGestureDetector(),
334   mPanGestureDetector(),
335   mTapGestureDetector(),
336   mLongPressGestureDetector(),
337   mTooltip( NULL ),
338   mInputMethodContext(),
339   mIdleCallback(nullptr),
340   mAutofillItem(),
341   mAutofillContainer(),
342   mFlags( Control::ControlBehaviour( CONTROL_BEHAVIOUR_DEFAULT ) ),
343   mIsKeyboardNavigationSupported( false ),
344   mIsKeyboardFocusGroup( false ),
345   mIsEmittingResourceReadySignal(false),
346   mNeedToEmitResourceReady(false),
347   mIsAutofillEnabled( false )
348 {
349 }
350
351 Control::Impl::~Impl()
352 {
353   for( auto&& iter : mVisuals )
354   {
355     StopObservingVisual( iter->visual );
356   }
357
358   for( auto&& iter : mRemoveVisuals )
359   {
360     StopObservingVisual( iter->visual );
361   }
362
363   // All gesture detectors will be destroyed so no need to disconnect.
364   delete mStartingPinchScale;
365
366   if(mIdleCallback && Adaptor::IsAvailable())
367   {
368     // Removes the callback from the callback manager in case the control is destroyed before the callback is executed.
369     Adaptor::Get().RemoveIdle(mIdleCallback);
370   }
371 }
372
373 Control::Impl& Control::Impl::Get( Internal::Control& internalControl )
374 {
375   return *internalControl.mImpl;
376 }
377
378 const Control::Impl& Control::Impl::Get( const Internal::Control& internalControl )
379 {
380   return *internalControl.mImpl;
381 }
382
383 // Gesture Detection Methods
384 void Control::Impl::PinchDetected(Actor actor, const PinchGesture& pinch)
385 {
386   mControlImpl.OnPinch(pinch);
387 }
388
389 void Control::Impl::PanDetected(Actor actor, const PanGesture& pan)
390 {
391   mControlImpl.OnPan(pan);
392 }
393
394 void Control::Impl::TapDetected(Actor actor, const TapGesture& tap)
395 {
396   mControlImpl.OnTap(tap);
397 }
398
399 void Control::Impl::LongPressDetected(Actor actor, const LongPressGesture& longPress)
400 {
401   mControlImpl.OnLongPress(longPress);
402 }
403
404 void Control::Impl::RegisterVisual( Property::Index index, Toolkit::Visual::Base& visual )
405 {
406   RegisterVisual( index, visual, VisualState::ENABLED, DepthIndexValue::NOT_SET );
407 }
408
409 void Control::Impl::RegisterVisual( Property::Index index, Toolkit::Visual::Base& visual, int depthIndex )
410 {
411   RegisterVisual( index, visual, VisualState::ENABLED, DepthIndexValue::SET, depthIndex );
412 }
413
414 void Control::Impl::RegisterVisual( Property::Index index, Toolkit::Visual::Base& visual, bool enabled )
415 {
416   RegisterVisual( index, visual, ( enabled ? VisualState::ENABLED : VisualState::DISABLED ), DepthIndexValue::NOT_SET );
417 }
418
419 void Control::Impl::RegisterVisual( Property::Index index, Toolkit::Visual::Base& visual, bool enabled, int depthIndex )
420 {
421   RegisterVisual( index, visual, ( enabled ? VisualState::ENABLED : VisualState::DISABLED ), DepthIndexValue::SET, depthIndex );
422 }
423
424 void Control::Impl::RegisterVisual( Property::Index index, Toolkit::Visual::Base& visual, VisualState::Type enabled, DepthIndexValue::Type depthIndexValueSet, int depthIndex )
425 {
426   DALI_LOG_INFO( gLogFilter, Debug::Concise, "RegisterVisual:%d \n", index );
427
428   bool visualReplaced ( false );
429   Actor self = mControlImpl.Self();
430
431   // Set the depth index, if not set by caller this will be either the current visual depth, max depth of all visuals
432   // or zero.
433   int requiredDepthIndex = visual.GetDepthIndex();
434
435   if( depthIndexValueSet == DepthIndexValue::SET )
436   {
437     requiredDepthIndex = depthIndex;
438   }
439
440   // Visual replacement, existing visual should only be removed from stage when replacement ready.
441   if( !mVisuals.Empty() )
442   {
443     RegisteredVisualContainer::Iterator registeredVisualsiter;
444     // Check if visual (index) is already registered, this is the current visual.
445     if( FindVisual( index, mVisuals, registeredVisualsiter ) )
446     {
447       Toolkit::Visual::Base& currentRegisteredVisual = (*registeredVisualsiter)->visual;
448       if( currentRegisteredVisual )
449       {
450         // Store current visual depth index as may need to set the replacement visual to same depth
451         const int currentDepthIndex = (*registeredVisualsiter)->visual.GetDepthIndex();
452
453         // No longer required to know if the replaced visual's resources are ready
454         StopObservingVisual( currentRegisteredVisual );
455
456         // If control staged and visual enabled then visuals will be swapped once ready
457         if(  self.GetProperty< bool >( Actor::Property::CONNECTED_TO_SCENE ) && enabled )
458         {
459           // Check if visual is currently in the process of being replaced ( is in removal container )
460           RegisteredVisualContainer::Iterator visualQueuedForRemoval;
461           if ( FindVisual( index, mRemoveVisuals, visualQueuedForRemoval ) )
462           {
463             // Visual with same index is already in removal container so current visual pending
464             // Only the the last requested visual will be displayed so remove current visual which is staged but not ready.
465             Toolkit::GetImplementation( currentRegisteredVisual ).SetOffScene( self );
466             mVisuals.Erase( registeredVisualsiter );
467           }
468           else
469           {
470             // current visual not already in removal container so add now.
471             DALI_LOG_INFO( gLogFilter, Debug::Verbose, "RegisterVisual Move current registered visual to removal Queue: %d \n", index );
472             MoveVisual( registeredVisualsiter, mVisuals, mRemoveVisuals );
473           }
474         }
475         else
476         {
477           // Control not staged or visual disabled so can just erase from registered visuals and new visual will be added later.
478           mVisuals.Erase( registeredVisualsiter );
479         }
480
481         // If we've not set the depth-index value and the new visual does not have a depth index applied to it, then use the previously set depth-index for this index
482         if( ( depthIndexValueSet == DepthIndexValue::NOT_SET ) &&
483             ( visual.GetDepthIndex() == 0 ) )
484         {
485           requiredDepthIndex = currentDepthIndex;
486         }
487       }
488
489       visualReplaced = true;
490     }
491   }
492
493   // If not set, set the name of the visual to the same name as the control's property.
494   // ( If the control has been type registered )
495   if( visual.GetName().empty() )
496   {
497     // returns empty string if index is not found as long as index is not -1
498     std::string visualName = self.GetPropertyName( index );
499     if( !visualName.empty() )
500     {
501       DALI_LOG_INFO( gLogFilter, Debug::Concise, "Setting visual name for property %d to %s\n",
502                      index, visualName.c_str() );
503       visual.SetName( visualName );
504     }
505   }
506
507   if( !visualReplaced ) // New registration entry
508   {
509     // If we've not set the depth-index value, we have more than one visual and the visual does not have a depth index, then set it to be the highest
510     if( ( depthIndexValueSet == DepthIndexValue::NOT_SET ) &&
511         ( mVisuals.Size() > 0 ) &&
512         ( visual.GetDepthIndex() == 0 ) )
513     {
514       int maxDepthIndex = std::numeric_limits< int >::min();
515
516       RegisteredVisualContainer::ConstIterator iter;
517       const RegisteredVisualContainer::ConstIterator endIter = mVisuals.End();
518       for ( iter = mVisuals.Begin(); iter != endIter; iter++ )
519       {
520         const int visualDepthIndex = (*iter)->visual.GetDepthIndex();
521         if ( visualDepthIndex > maxDepthIndex )
522         {
523           maxDepthIndex = visualDepthIndex;
524         }
525       }
526       ++maxDepthIndex; // Add one to the current maximum depth index so that our added visual appears on top
527       requiredDepthIndex = std::max( 0, maxDepthIndex ); // Start at zero if maxDepth index belongs to a background
528     }
529   }
530
531   if( visual )
532   {
533     // Set determined depth index
534     visual.SetDepthIndex( requiredDepthIndex );
535
536     // Monitor when the visual resources are ready
537     StartObservingVisual( visual );
538
539     DALI_LOG_INFO( gLogFilter, Debug::Concise, "New Visual registration index[%d] depth[%d]\n", index, requiredDepthIndex );
540     RegisteredVisual* newRegisteredVisual  = new RegisteredVisual( index, visual,
541                                              ( enabled == VisualState::ENABLED ? true : false ),
542                                              ( visualReplaced && enabled ) ) ;
543     mVisuals.PushBack( newRegisteredVisual );
544
545     Internal::Visual::Base& visualImpl = Toolkit::GetImplementation( visual );
546     // Put on stage if enabled and the control is already on the stage
547     if( ( enabled == VisualState::ENABLED ) && self.GetProperty< bool >( Actor::Property::CONNECTED_TO_SCENE ) )
548     {
549       visualImpl.SetOnScene( self );
550     }
551     else if( visualImpl.IsResourceReady() ) // When not being staged, check if visual already 'ResourceReady' before it was Registered. ( Resource may have been loaded already )
552     {
553       ResourceReady( visualImpl );
554     }
555
556   }
557
558   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Control::RegisterVisual() Registered %s(%d), enabled:%s\n",  visual.GetName().c_str(), index, enabled?"true":"false" );
559 }
560
561 void Control::Impl::UnregisterVisual( Property::Index index )
562 {
563   RegisteredVisualContainer::Iterator iter;
564   if ( FindVisual( index, mVisuals, iter ) )
565   {
566     // stop observing visual
567     StopObservingVisual( (*iter)->visual );
568
569     Actor self( mControlImpl.Self() );
570     Toolkit::GetImplementation((*iter)->visual).SetOffScene( self );
571     (*iter)->visual.Reset();
572     mVisuals.Erase( iter );
573   }
574
575   if( FindVisual( index, mRemoveVisuals, iter ) )
576   {
577     Actor self( mControlImpl.Self() );
578     Toolkit::GetImplementation( (*iter)->visual ).SetOffScene( self );
579     (*iter)->pending = false;
580     (*iter)->visual.Reset();
581     mRemoveVisuals.Erase( iter );
582   }
583 }
584
585 Toolkit::Visual::Base Control::Impl::GetVisual( Property::Index index ) const
586 {
587   RegisteredVisualContainer::Iterator iter;
588   if ( FindVisual( index, mVisuals, iter ) )
589   {
590     return (*iter)->visual;
591   }
592
593   return Toolkit::Visual::Base();
594 }
595
596 void Control::Impl::EnableVisual( Property::Index index, bool enable )
597 {
598   DALI_LOG_INFO( gLogFilter, Debug::General, "Control::EnableVisual(%d, %s)\n", index, enable?"T":"F");
599
600   RegisteredVisualContainer::Iterator iter;
601   if ( FindVisual( index, mVisuals, iter ) )
602   {
603     if (  (*iter)->enabled == enable )
604     {
605       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Control::EnableVisual Visual %s(%d) already %s\n", (*iter)->visual.GetName().c_str(), index, enable?"enabled":"disabled");
606       return;
607     }
608
609     (*iter)->enabled = enable;
610     Actor parentActor = mControlImpl.Self();
611     if ( mControlImpl.Self().GetProperty< bool >( Actor::Property::CONNECTED_TO_SCENE ) ) // If control not on Scene then Visual will be added when SceneConnection is called.
612     {
613       if ( enable )
614       {
615         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Control::EnableVisual Setting %s(%d) on stage \n", (*iter)->visual.GetName().c_str(), index );
616         Toolkit::GetImplementation((*iter)->visual).SetOnScene( parentActor );
617       }
618       else
619       {
620         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Control::EnableVisual Setting %s(%d) off stage \n", (*iter)->visual.GetName().c_str(), index );
621         Toolkit::GetImplementation((*iter)->visual).SetOffScene( parentActor );  // No need to call if control not staged.
622       }
623     }
624   }
625   else
626   {
627     DALI_LOG_WARNING( "Control::EnableVisual(%d, %s) FAILED - NO SUCH VISUAL\n", index, enable?"T":"F" );
628   }
629 }
630
631 bool Control::Impl::IsVisualEnabled( Property::Index index ) const
632 {
633   RegisteredVisualContainer::Iterator iter;
634   if ( FindVisual( index, mVisuals, iter ) )
635   {
636     return (*iter)->enabled;
637   }
638   return false;
639 }
640
641 void Control::Impl::StopObservingVisual( Toolkit::Visual::Base& visual )
642 {
643   Internal::Visual::Base& visualImpl = Toolkit::GetImplementation( visual );
644
645   // Stop observing the visual
646   visualImpl.RemoveEventObserver( *this );
647 }
648
649 void Control::Impl::StartObservingVisual( Toolkit::Visual::Base& visual)
650 {
651   Internal::Visual::Base& visualImpl = Toolkit::GetImplementation( visual );
652
653   // start observing the visual for events
654   visualImpl.AddEventObserver( *this );
655 }
656
657 // Called by a Visual when it's resource is ready
658 void Control::Impl::ResourceReady( Visual::Base& object)
659 {
660   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Control::Impl::ResourceReady() replacements pending[%d]\n", mRemoveVisuals.Count() );
661
662   Actor self = mControlImpl.Self();
663
664   // A resource is ready, find resource in the registered visuals container and get its index
665   for( auto registeredIter = mVisuals.Begin(),  end = mVisuals.End(); registeredIter != end; ++registeredIter )
666   {
667     Internal::Visual::Base& registeredVisualImpl = Toolkit::GetImplementation( (*registeredIter)->visual );
668
669     if( &object == &registeredVisualImpl )
670     {
671       RegisteredVisualContainer::Iterator visualToRemoveIter;
672       // Find visual with the same index in the removal container
673       // Set if off stage as it's replacement is now ready.
674       // Remove if from removal list as now removed from stage.
675       // Set Pending flag on the ready visual to false as now ready.
676       if( FindVisual( (*registeredIter)->index, mRemoveVisuals, visualToRemoveIter ) )
677       {
678         (*registeredIter)->pending = false;
679         Toolkit::GetImplementation( (*visualToRemoveIter)->visual ).SetOffScene( self );
680         mRemoveVisuals.Erase( visualToRemoveIter );
681       }
682       break;
683     }
684   }
685
686   // A visual is ready so control may need relayouting if staged
687   if ( self.GetProperty< bool >( Actor::Property::CONNECTED_TO_SCENE ) )
688   {
689     mControlImpl.RelayoutRequest();
690   }
691
692   // Emit signal if all enabled visuals registered by the control are ready.
693   if( IsResourceReady() )
694   {
695     // Reset the flag
696     mNeedToEmitResourceReady = false;
697
698     EmitResourceReadySignal();
699   }
700 }
701
702 void Control::Impl::NotifyVisualEvent( Visual::Base& object, Property::Index signalId )
703 {
704   for( auto registeredIter = mVisuals.Begin(),  end = mVisuals.End(); registeredIter != end; ++registeredIter )
705   {
706     Internal::Visual::Base& registeredVisualImpl = Toolkit::GetImplementation( (*registeredIter)->visual );
707     if( &object == &registeredVisualImpl )
708     {
709       Dali::Toolkit::Control handle( mControlImpl.GetOwner() );
710       mVisualEventSignal.Emit( handle, (*registeredIter)->index, signalId );
711       break;
712     }
713   }
714 }
715
716 bool Control::Impl::IsResourceReady() const
717 {
718   // Iterate through and check all the enabled visuals are ready
719   for( auto visualIter = mVisuals.Begin();
720          visualIter != mVisuals.End(); ++visualIter )
721   {
722     const Toolkit::Visual::Base visual = (*visualIter)->visual;
723     const Internal::Visual::Base& visualImpl = Toolkit::GetImplementation( visual );
724
725     // one of the enabled visuals is not ready
726     if( !visualImpl.IsResourceReady() && (*visualIter)->enabled )
727     {
728       return false;
729     }
730   }
731   return true;
732 }
733
734 Toolkit::Visual::ResourceStatus Control::Impl::GetVisualResourceStatus( Property::Index index ) const
735 {
736   RegisteredVisualContainer::Iterator iter;
737   if ( FindVisual( index, mVisuals, iter ) )
738   {
739     const Toolkit::Visual::Base visual = (*iter)->visual;
740     const Internal::Visual::Base& visualImpl = Toolkit::GetImplementation( visual );
741     return visualImpl.GetResourceStatus( );
742   }
743
744   return Toolkit::Visual::ResourceStatus::PREPARING;
745 }
746
747
748
749 void Control::Impl::AddTransitions( Dali::Animation& animation,
750                                     const Toolkit::TransitionData& handle,
751                                     bool createAnimation )
752 {
753   // Setup a Transition from TransitionData.
754   const Internal::TransitionData& transitionData = Toolkit::GetImplementation( handle );
755   TransitionData::Iterator end = transitionData.End();
756   for( TransitionData::Iterator iter = transitionData.Begin() ;
757        iter != end; ++iter )
758   {
759     TransitionData::Animator* animator = (*iter);
760
761     Toolkit::Visual::Base visual = GetVisualByName( mVisuals, animator->objectName );
762
763     if( visual )
764     {
765 #if defined(DEBUG_ENABLED)
766       Dali::TypeInfo typeInfo;
767       ControlWrapper* controlWrapperImpl = dynamic_cast<ControlWrapper*>(&mControlImpl);
768       if( controlWrapperImpl )
769       {
770         typeInfo = controlWrapperImpl->GetTypeInfo();
771       }
772
773       DALI_LOG_INFO( gLogFilter, Debug::Concise, "CreateTransition: Found %s visual for %s\n",
774                      visual.GetName().c_str(), typeInfo?typeInfo.GetName().c_str():"Unknown" );
775 #endif
776       Internal::Visual::Base& visualImpl = Toolkit::GetImplementation( visual );
777       visualImpl.AnimateProperty( animation, *animator );
778     }
779     else
780     {
781       DALI_LOG_INFO( gLogFilter, Debug::Concise, "CreateTransition: Could not find visual. Trying actors");
782       // Otherwise, try any actor children of control (Including the control)
783       Actor child = mControlImpl.Self().FindChildByName( animator->objectName );
784       if( child )
785       {
786         Property::Index propertyIndex = child.GetPropertyIndex( animator->propertyKey );
787         if( propertyIndex != Property::INVALID_INDEX )
788         {
789           if( animator->animate == false )
790           {
791             if( animator->targetValue.GetType() != Property::NONE )
792             {
793               child.SetProperty( propertyIndex, animator->targetValue );
794             }
795           }
796           else // animate the property
797           {
798             if( animator->initialValue.GetType() != Property::NONE )
799             {
800               child.SetProperty( propertyIndex, animator->initialValue );
801             }
802
803             if( createAnimation && !animation )
804             {
805               animation = Dali::Animation::New( 0.1f );
806             }
807
808             animation.AnimateTo( Property( child, propertyIndex ),
809                                  animator->targetValue,
810                                  animator->alphaFunction,
811                                  TimePeriod( animator->timePeriodDelay,
812                                              animator->timePeriodDuration ) );
813           }
814         }
815       }
816     }
817   }
818 }
819
820 Dali::Animation Control::Impl::CreateTransition( const Toolkit::TransitionData& transitionData )
821 {
822   Dali::Animation transition;
823
824   if( transitionData.Count() > 0 )
825   {
826     AddTransitions( transition, transitionData, true );
827   }
828   return transition;
829 }
830
831
832
833 void Control::Impl::DoAction( Dali::Property::Index visualIndex, Dali::Property::Index actionId, const Dali::Property::Value attributes )
834 {
835   RegisteredVisualContainer::Iterator iter;
836   if ( FindVisual( visualIndex, mVisuals, iter ) )
837   {
838     Toolkit::GetImplementation((*iter)->visual).DoAction( actionId, attributes );
839   }
840 }
841
842 void Control::Impl::SetProperty( BaseObject* object, Property::Index index, const Property::Value& value )
843 {
844   Toolkit::Control control = Toolkit::Control::DownCast( BaseHandle( object ) );
845
846   if ( control )
847   {
848     Control& controlImpl( GetImplementation( control ) );
849
850     switch ( index )
851     {
852       case Toolkit::Control::Property::STYLE_NAME:
853       {
854         controlImpl.SetStyleName( value.Get< std::string >() );
855         break;
856       }
857
858       case Toolkit::DevelControl::Property::STATE:
859       {
860         bool withTransitions=true;
861         const Property::Value* valuePtr=&value;
862         const Property::Map* map = value.GetMap();
863         if(map)
864         {
865           Property::Value* value2 = map->Find("withTransitions");
866           if( value2 )
867           {
868             withTransitions = value2->Get<bool>();
869           }
870
871           valuePtr = map->Find("state");
872         }
873
874         if( valuePtr )
875         {
876           Toolkit::DevelControl::State state( controlImpl.mImpl->mState );
877           if( Scripting::GetEnumerationProperty< Toolkit::DevelControl::State >( *valuePtr, ControlStateTable, ControlStateTableCount, state ) )
878           {
879             controlImpl.mImpl->SetState( state, withTransitions );
880           }
881         }
882       }
883       break;
884
885       case Toolkit::DevelControl::Property::SUB_STATE:
886       {
887         std::string subState;
888         if( value.Get( subState ) )
889         {
890           controlImpl.mImpl->SetSubState( subState );
891         }
892       }
893       break;
894
895       case Toolkit::DevelControl::Property::LEFT_FOCUSABLE_ACTOR_ID:
896       {
897         int focusId;
898         if( value.Get( focusId ) )
899         {
900           controlImpl.mImpl->mLeftFocusableActorId = focusId;
901         }
902       }
903       break;
904
905       case Toolkit::DevelControl::Property::RIGHT_FOCUSABLE_ACTOR_ID:
906       {
907         int focusId;
908         if( value.Get( focusId ) )
909         {
910           controlImpl.mImpl->mRightFocusableActorId = focusId;
911         }
912       }
913       break;
914
915       case Toolkit::DevelControl::Property::UP_FOCUSABLE_ACTOR_ID:
916       {
917         int focusId;
918         if( value.Get( focusId ) )
919         {
920           controlImpl.mImpl->mUpFocusableActorId = focusId;
921         }
922       }
923       break;
924
925       case Toolkit::DevelControl::Property::DOWN_FOCUSABLE_ACTOR_ID:
926       {
927         int focusId;
928         if( value.Get( focusId ) )
929         {
930           controlImpl.mImpl->mDownFocusableActorId = focusId;
931         }
932       }
933       break;
934
935       case Toolkit::Control::Property::KEY_INPUT_FOCUS:
936       {
937         if ( value.Get< bool >() )
938         {
939           controlImpl.SetKeyInputFocus();
940         }
941         else
942         {
943           controlImpl.ClearKeyInputFocus();
944         }
945         break;
946       }
947
948       case Toolkit::Control::Property::BACKGROUND:
949       {
950         std::string url;
951         Vector4 color;
952         const Property::Map* map = value.GetMap();
953         if( map && !map->Empty() )
954         {
955           controlImpl.SetBackground( *map );
956         }
957         else if( value.Get( url ) )
958         {
959           // don't know the size to load
960           Toolkit::Visual::Base visual = Toolkit::VisualFactory::Get().CreateVisual( url, ImageDimensions() );
961           if( visual )
962           {
963             controlImpl.mImpl->RegisterVisual( Toolkit::Control::Property::BACKGROUND, visual, DepthIndex::BACKGROUND );
964           }
965         }
966         else if( value.Get( color ) )
967         {
968           controlImpl.SetBackgroundColor(color);
969         }
970         else
971         {
972           // The background is an empty property map, so we should clear the background
973           controlImpl.ClearBackground();
974         }
975         break;
976       }
977
978       case Toolkit::Control::Property::MARGIN:
979       {
980         Extents margin;
981         if( value.Get( margin ) )
982         {
983           controlImpl.mImpl->SetMargin( margin );
984         }
985         break;
986       }
987
988       case Toolkit::Control::Property::PADDING:
989       {
990         Extents padding;
991         if( value.Get( padding ) )
992         {
993           controlImpl.mImpl->SetPadding( padding );
994         }
995         break;
996       }
997
998       case Toolkit::DevelControl::Property::TOOLTIP:
999       {
1000         TooltipPtr& tooltipPtr = controlImpl.mImpl->mTooltip;
1001         if( ! tooltipPtr )
1002         {
1003           tooltipPtr = Tooltip::New( control );
1004         }
1005         tooltipPtr->SetProperties( value );
1006         break;
1007       }
1008
1009       case Toolkit::DevelControl::Property::SHADOW:
1010       {
1011         const Property::Map* map = value.GetMap();
1012         if( map && !map->Empty() )
1013         {
1014           controlImpl.mImpl->SetShadow( *map );
1015         }
1016         else
1017         {
1018           // The shadow is an empty property map, so we should clear the shadow
1019           controlImpl.mImpl->ClearShadow();
1020         }
1021         break;
1022       }
1023
1024     }
1025   }
1026 }
1027
1028 Property::Value Control::Impl::GetProperty( BaseObject* object, Property::Index index )
1029 {
1030   Property::Value value;
1031
1032   Toolkit::Control control = Toolkit::Control::DownCast( BaseHandle( object ) );
1033
1034   if ( control )
1035   {
1036     Control& controlImpl( GetImplementation( control ) );
1037
1038     switch ( index )
1039     {
1040       case Toolkit::Control::Property::STYLE_NAME:
1041       {
1042         value = controlImpl.GetStyleName();
1043         break;
1044       }
1045
1046       case Toolkit::DevelControl::Property::STATE:
1047       {
1048         value = controlImpl.mImpl->mState;
1049         break;
1050       }
1051
1052       case Toolkit::DevelControl::Property::SUB_STATE:
1053       {
1054         value = controlImpl.mImpl->mSubStateName;
1055         break;
1056       }
1057
1058       case Toolkit::DevelControl::Property::LEFT_FOCUSABLE_ACTOR_ID:
1059       {
1060         value = controlImpl.mImpl->mLeftFocusableActorId;
1061         break;
1062       }
1063
1064       case Toolkit::DevelControl::Property::RIGHT_FOCUSABLE_ACTOR_ID:
1065       {
1066         value = controlImpl.mImpl->mRightFocusableActorId;
1067         break;
1068       }
1069
1070       case Toolkit::DevelControl::Property::UP_FOCUSABLE_ACTOR_ID:
1071       {
1072         value = controlImpl.mImpl->mUpFocusableActorId;
1073         break;
1074       }
1075
1076       case Toolkit::DevelControl::Property::DOWN_FOCUSABLE_ACTOR_ID:
1077       {
1078         value = controlImpl.mImpl->mDownFocusableActorId;
1079         break;
1080       }
1081
1082       case Toolkit::Control::Property::KEY_INPUT_FOCUS:
1083       {
1084         value = controlImpl.HasKeyInputFocus();
1085         break;
1086       }
1087
1088       case Toolkit::Control::Property::BACKGROUND:
1089       {
1090         Property::Map map;
1091         Toolkit::Visual::Base visual = controlImpl.mImpl->GetVisual( Toolkit::Control::Property::BACKGROUND );
1092         if( visual )
1093         {
1094           visual.CreatePropertyMap( map );
1095         }
1096
1097         value = map;
1098         break;
1099       }
1100
1101       case Toolkit::Control::Property::MARGIN:
1102       {
1103         value = controlImpl.mImpl->GetMargin();
1104         break;
1105       }
1106
1107       case Toolkit::Control::Property::PADDING:
1108       {
1109         value = controlImpl.mImpl->GetPadding();
1110         break;
1111       }
1112
1113       case Toolkit::DevelControl::Property::TOOLTIP:
1114       {
1115         Property::Map map;
1116         if( controlImpl.mImpl->mTooltip )
1117         {
1118           controlImpl.mImpl->mTooltip->CreatePropertyMap( map );
1119         }
1120         value = map;
1121         break;
1122       }
1123
1124       case Toolkit::DevelControl::Property::SHADOW:
1125       {
1126         Property::Map map;
1127         Toolkit::Visual::Base visual = controlImpl.mImpl->GetVisual( Toolkit::DevelControl::Property::SHADOW );
1128         if( visual )
1129         {
1130           visual.CreatePropertyMap( map );
1131         }
1132
1133         value = map;
1134         break;
1135       }
1136     }
1137   }
1138
1139   return value;
1140 }
1141
1142
1143 void  Control::Impl::CopyInstancedProperties( RegisteredVisualContainer& visuals, Dictionary<Property::Map>& instancedProperties )
1144 {
1145   for(RegisteredVisualContainer::Iterator iter = visuals.Begin(); iter!= visuals.End(); iter++)
1146   {
1147     if( (*iter)->visual )
1148     {
1149       Property::Map instanceMap;
1150       Toolkit::GetImplementation((*iter)->visual).CreateInstancePropertyMap(instanceMap);
1151       instancedProperties.Add( (*iter)->visual.GetName(), instanceMap );
1152     }
1153   }
1154 }
1155
1156
1157 void Control::Impl::RemoveVisual( RegisteredVisualContainer& visuals, const std::string& visualName )
1158 {
1159   Actor self( mControlImpl.Self() );
1160
1161   for ( RegisteredVisualContainer::Iterator visualIter = visuals.Begin();
1162         visualIter != visuals.End(); ++visualIter )
1163   {
1164     Toolkit::Visual::Base visual = (*visualIter)->visual;
1165     if( visual && visual.GetName() == visualName )
1166     {
1167       Toolkit::GetImplementation(visual).SetOffScene( self );
1168       (*visualIter)->visual.Reset();
1169       visuals.Erase( visualIter );
1170       break;
1171     }
1172   }
1173 }
1174
1175 void Control::Impl::RemoveVisuals( RegisteredVisualContainer& visuals, DictionaryKeys& removeVisuals )
1176 {
1177   Actor self( mControlImpl.Self() );
1178   for( DictionaryKeys::iterator iter = removeVisuals.begin(); iter != removeVisuals.end(); ++iter )
1179   {
1180     const std::string visualName = *iter;
1181     RemoveVisual( visuals, visualName );
1182   }
1183 }
1184
1185 void Control::Impl::RecreateChangedVisuals( Dictionary<Property::Map>& stateVisualsToChange,
1186                              Dictionary<Property::Map>& instancedProperties )
1187 {
1188   Dali::CustomActor handle( mControlImpl.GetOwner() );
1189   for( Dictionary<Property::Map>::iterator iter = stateVisualsToChange.Begin();
1190        iter != stateVisualsToChange.End(); ++iter )
1191   {
1192     const std::string& visualName = (*iter).key;
1193     const Property::Map& toMap = (*iter).entry;
1194
1195     // is it a candidate for re-creation?
1196     bool recreate = false;
1197
1198     Toolkit::Visual::Base visual = GetVisualByName( mVisuals, visualName );
1199     if( visual )
1200     {
1201       Property::Map fromMap;
1202       visual.CreatePropertyMap( fromMap );
1203
1204       Toolkit::Visual::Type fromType = GetVisualTypeFromMap( fromMap );
1205       Toolkit::Visual::Type toType = GetVisualTypeFromMap( toMap );
1206
1207       if( fromType != toType )
1208       {
1209         recreate = true;
1210       }
1211       else
1212       {
1213         if( fromType == Toolkit::Visual::IMAGE || fromType == Toolkit::Visual::N_PATCH
1214             || fromType == Toolkit::Visual::SVG || fromType == Toolkit::Visual::ANIMATED_IMAGE )
1215         {
1216           Property::Value* fromUrl = fromMap.Find( Toolkit::ImageVisual::Property::URL, IMAGE_URL_NAME );
1217           Property::Value* toUrl = toMap.Find( Toolkit::ImageVisual::Property::URL, IMAGE_URL_NAME );
1218
1219           if( fromUrl && toUrl )
1220           {
1221             std::string fromUrlString;
1222             std::string toUrlString;
1223             fromUrl->Get(fromUrlString);
1224             toUrl->Get(toUrlString);
1225
1226             if( fromUrlString != toUrlString )
1227             {
1228               recreate = true;
1229             }
1230           }
1231         }
1232       }
1233
1234       const Property::Map* instancedMap = instancedProperties.FindConst( visualName );
1235       if( recreate || instancedMap )
1236       {
1237         RemoveVisual( mVisuals, visualName );
1238         Style::ApplyVisual( handle, visualName, toMap, instancedMap );
1239       }
1240       else
1241       {
1242         // @todo check to see if we can apply toMap without recreating the visual
1243         // e.g. by setting only animatable properties
1244         // For now, recreate all visuals, but merge in instance data.
1245         RemoveVisual( mVisuals, visualName );
1246         Style::ApplyVisual( handle, visualName, toMap, instancedMap );
1247       }
1248     }
1249   }
1250 }
1251
1252 void Control::Impl::ReplaceStateVisualsAndProperties( const StylePtr oldState, const StylePtr newState, const std::string& subState )
1253 {
1254   // Collect all old visual names
1255   DictionaryKeys stateVisualsToRemove;
1256   if( oldState )
1257   {
1258     oldState->visuals.GetKeys( stateVisualsToRemove );
1259     if( ! subState.empty() )
1260     {
1261       const StylePtr* oldSubState = oldState->subStates.FindConst(subState);
1262       if( oldSubState )
1263       {
1264         DictionaryKeys subStateVisualsToRemove;
1265         (*oldSubState)->visuals.GetKeys( subStateVisualsToRemove );
1266         Merge( stateVisualsToRemove, subStateVisualsToRemove );
1267       }
1268     }
1269   }
1270
1271   // Collect all new visual properties
1272   Dictionary<Property::Map> stateVisualsToAdd;
1273   if( newState )
1274   {
1275     stateVisualsToAdd = newState->visuals;
1276     if( ! subState.empty() )
1277     {
1278       const StylePtr* newSubState = newState->subStates.FindConst(subState);
1279       if( newSubState )
1280       {
1281         stateVisualsToAdd.Merge( (*newSubState)->visuals );
1282       }
1283     }
1284   }
1285
1286   // If a name is in both add/remove, move it to change list.
1287   Dictionary<Property::Map> stateVisualsToChange;
1288   FindChangableVisuals( stateVisualsToAdd, stateVisualsToChange, stateVisualsToRemove);
1289
1290   // Copy instanced properties (e.g. text label) of current visuals
1291   Dictionary<Property::Map> instancedProperties;
1292   CopyInstancedProperties( mVisuals, instancedProperties );
1293
1294   // For each visual in remove list, remove from mVisuals
1295   RemoveVisuals( mVisuals, stateVisualsToRemove );
1296
1297   // For each visual in add list, create and add to mVisuals
1298   Dali::CustomActor handle( mControlImpl.GetOwner() );
1299   Style::ApplyVisuals( handle, stateVisualsToAdd, instancedProperties );
1300
1301   // For each visual in change list, if it requires a new visual,
1302   // remove old visual, create and add to mVisuals
1303   RecreateChangedVisuals( stateVisualsToChange, instancedProperties );
1304 }
1305
1306 void Control::Impl::SetState( DevelControl::State newState, bool withTransitions )
1307 {
1308   DevelControl::State oldState = mState;
1309   Dali::CustomActor handle( mControlImpl.GetOwner() );
1310   DALI_LOG_INFO(gLogFilter, Debug::Concise, "Control::Impl::SetState: %s\n",
1311                 (mState == DevelControl::NORMAL ? "NORMAL" :(
1312                   mState == DevelControl::FOCUSED ?"FOCUSED" : (
1313                     mState == DevelControl::DISABLED?"DISABLED":"NONE" ))));
1314
1315   if( mState != newState )
1316   {
1317     // If mState was Disabled, and new state is Focused, should probably
1318     // store that fact, e.g. in another property that FocusManager can access.
1319     mState = newState;
1320
1321     // Trigger state change and transitions
1322     // Apply new style, if stylemanager is available
1323     Toolkit::StyleManager styleManager = Toolkit::StyleManager::Get();
1324     if( styleManager )
1325     {
1326       const StylePtr stylePtr = GetImpl( styleManager ).GetRecordedStyle( Toolkit::Control( mControlImpl.GetOwner() ) );
1327
1328       if( stylePtr )
1329       {
1330         std::string oldStateName = Scripting::GetEnumerationName< Toolkit::DevelControl::State >( oldState, ControlStateTable, ControlStateTableCount );
1331         std::string newStateName = Scripting::GetEnumerationName< Toolkit::DevelControl::State >( newState, ControlStateTable, ControlStateTableCount );
1332
1333         const StylePtr* newStateStyle = stylePtr->subStates.Find( newStateName );
1334         const StylePtr* oldStateStyle = stylePtr->subStates.Find( oldStateName );
1335         if( oldStateStyle && newStateStyle )
1336         {
1337           // Only change if both state styles exist
1338           ReplaceStateVisualsAndProperties( *oldStateStyle, *newStateStyle, mSubStateName );
1339         }
1340       }
1341     }
1342   }
1343 }
1344
1345 void Control::Impl::SetSubState( const std::string& subStateName, bool withTransitions )
1346 {
1347   if( mSubStateName != subStateName )
1348   {
1349     // Get existing sub-state visuals, and unregister them
1350     Dali::CustomActor handle( mControlImpl.GetOwner() );
1351
1352     Toolkit::StyleManager styleManager = Toolkit::StyleManager::Get();
1353     if( styleManager )
1354     {
1355       const StylePtr stylePtr = GetImpl( styleManager ).GetRecordedStyle( Toolkit::Control( mControlImpl.GetOwner() ) );
1356       if( stylePtr )
1357       {
1358         // Stringify state
1359         std::string stateName = Scripting::GetEnumerationName< Toolkit::DevelControl::State >( mState, ControlStateTable, ControlStateTableCount );
1360
1361         const StylePtr* state = stylePtr->subStates.Find( stateName );
1362         if( state )
1363         {
1364           StylePtr stateStyle(*state);
1365
1366           const StylePtr* newStateStyle = stateStyle->subStates.Find( subStateName );
1367           const StylePtr* oldStateStyle = stateStyle->subStates.Find( mSubStateName );
1368           if( oldStateStyle && newStateStyle )
1369           {
1370             std::string empty;
1371             ReplaceStateVisualsAndProperties( *oldStateStyle, *newStateStyle, empty );
1372           }
1373         }
1374       }
1375     }
1376
1377     mSubStateName = subStateName;
1378   }
1379 }
1380
1381 void Control::Impl::OnSceneDisconnection()
1382 {
1383   Actor self = mControlImpl.Self();
1384
1385   // Any visuals set for replacement but not yet ready should still be registered.
1386   // Reason: If a request was made to register a new visual but the control removed from scene before visual was ready
1387   // then when this control appears back on stage it should use that new visual.
1388
1389   // Iterate through all registered visuals and set off scene
1390   SetVisualsOffScene( mVisuals, self );
1391
1392   // Visuals pending replacement can now be taken out of the removal list and set off scene
1393   // Iterate through all replacement visuals and add to a move queue then set off scene
1394   for( auto removalIter = mRemoveVisuals.Begin(), end = mRemoveVisuals.End(); removalIter != end; removalIter++ )
1395   {
1396     Toolkit::GetImplementation((*removalIter)->visual).SetOffScene( self );
1397   }
1398
1399   for( auto replacedIter = mVisuals.Begin(), end = mVisuals.End(); replacedIter != end; replacedIter++ )
1400   {
1401     (*replacedIter)->pending = false;
1402   }
1403
1404   mRemoveVisuals.Clear();
1405 }
1406
1407 void Control::Impl::SetMargin( Extents margin )
1408 {
1409   mControlImpl.mImpl->mMargin = margin;
1410
1411   // Trigger a size negotiation request that may be needed when setting a margin.
1412   mControlImpl.RelayoutRequest();
1413 }
1414
1415 Extents Control::Impl::GetMargin() const
1416 {
1417   return mControlImpl.mImpl->mMargin;
1418 }
1419
1420 void Control::Impl::SetPadding( Extents padding )
1421 {
1422   mControlImpl.mImpl->mPadding = padding;
1423
1424   // Trigger a size negotiation request that may be needed when setting a padding.
1425   mControlImpl.RelayoutRequest();
1426 }
1427
1428 Extents Control::Impl::GetPadding() const
1429 {
1430   return mControlImpl.mImpl->mPadding;
1431 }
1432
1433 void Control::Impl::SetInputMethodContext( InputMethodContext& inputMethodContext )
1434 {
1435   mInputMethodContext = inputMethodContext;
1436 }
1437
1438 bool Control::Impl::FilterKeyEvent( const KeyEvent& event )
1439 {
1440   bool consumed ( false );
1441
1442   if ( mInputMethodContext )
1443   {
1444     consumed = mInputMethodContext.FilterEventKey( event );
1445   }
1446   return consumed;
1447 }
1448
1449 DevelControl::VisualEventSignalType& Control::Impl::VisualEventSignal()
1450 {
1451   return mVisualEventSignal;
1452 }
1453
1454 void Control::Impl::SetShadow( const Property::Map& map )
1455 {
1456   Toolkit::Visual::Base visual = Toolkit::VisualFactory::Get().CreateVisual( map );
1457   visual.SetName("shadow");
1458
1459   if( visual )
1460   {
1461     mControlImpl.mImpl->RegisterVisual( Toolkit::DevelControl::Property::SHADOW, visual, DepthIndex::BACKGROUND_EFFECT );
1462
1463     mControlImpl.RelayoutRequest();
1464   }
1465 }
1466
1467 void Control::Impl::ClearShadow()
1468 {
1469    mControlImpl.mImpl->UnregisterVisual( Toolkit::DevelControl::Property::SHADOW );
1470
1471    // Trigger a size negotiation request that may be needed when unregistering a visual.
1472    mControlImpl.RelayoutRequest();
1473 }
1474
1475 void Control::Impl::EmitResourceReadySignal()
1476 {
1477   if(!mIsEmittingResourceReadySignal)
1478   {
1479     // Guard against calls to emit the signal during the callback
1480     mIsEmittingResourceReadySignal = true;
1481
1482     // If the signal handler changes visual, it may become ready during this call & therefore this method will
1483     // get called again recursively. If so, mNeedToEmitResourceReady is set below, and we act on it after that secondary
1484     // invocation has completed by notifying in an Idle callback to prevent further recursion.
1485     Dali::Toolkit::Control handle(mControlImpl.GetOwner());
1486     mResourceReadySignal.Emit(handle);
1487
1488     if(mNeedToEmitResourceReady)
1489     {
1490       // Add idler to emit the signal again
1491       if(!mIdleCallback)
1492       {
1493         // The callback manager takes the ownership of the callback object.
1494         mIdleCallback = MakeCallback( this, &Control::Impl::OnIdleCallback);
1495         Adaptor::Get().AddIdle(mIdleCallback, false);
1496       }
1497     }
1498
1499     mIsEmittingResourceReadySignal = false;
1500   }
1501   else
1502   {
1503     mNeedToEmitResourceReady = true;
1504   }
1505 }
1506
1507 void Control::Impl::OnIdleCallback()
1508 {
1509   if(mNeedToEmitResourceReady)
1510   {
1511     // Reset the flag
1512     mNeedToEmitResourceReady = false;
1513
1514     // A visual is ready so control may need relayouting if staged
1515     if(mControlImpl.Self().GetProperty<bool>(Actor::Property::CONNECTED_TO_SCENE))
1516     {
1517       mControlImpl.RelayoutRequest();
1518     }
1519
1520     EmitResourceReadySignal();
1521   }
1522
1523   // Set the pointer to null as the callback manager deletes the callback after execute it.
1524   mIdleCallback = nullptr;
1525 }
1526
1527 void Control::Impl::SetAutofillEnabled( bool autofillEnabled )
1528 {
1529   mIsAutofillEnabled = autofillEnabled;
1530 }
1531
1532 bool Control::Impl::IsAutofillEnabled()
1533 {
1534   return mIsAutofillEnabled;
1535 }
1536
1537 void Control::Impl::SetAutofillItemHandle( Dali::AutofillItem item )
1538 {
1539   mAutofillItem = item;
1540 }
1541
1542 Dali::AutofillItem Control::Impl::GetAutofillItemHandle()
1543 {
1544   return mAutofillItem;
1545 }
1546
1547 void Control::Impl::SetAutofillContainer( Toolkit::AutofillContainer container )
1548 {
1549   mAutofillContainer = container;
1550 }
1551
1552 Toolkit::AutofillContainer Control::Impl::GetAutofillContainer()
1553 {
1554   return mAutofillContainer;
1555 }
1556
1557 } // namespace Internal
1558
1559 } // namespace Toolkit
1560
1561 } // namespace Dali