Revert "[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   // All gesture detectors will be destroyed so no need to disconnect.
354   delete mStartingPinchScale;
355
356   if(mIdleCallback && Adaptor::IsAvailable())
357   {
358     // Removes the callback from the callback manager in case the control is destroyed before the callback is executed.
359     Adaptor::Get().RemoveIdle(mIdleCallback);
360   }
361 }
362
363 Control::Impl& Control::Impl::Get( Internal::Control& internalControl )
364 {
365   return *internalControl.mImpl;
366 }
367
368 const Control::Impl& Control::Impl::Get( const Internal::Control& internalControl )
369 {
370   return *internalControl.mImpl;
371 }
372
373 // Gesture Detection Methods
374 void Control::Impl::PinchDetected(Actor actor, const PinchGesture& pinch)
375 {
376   mControlImpl.OnPinch(pinch);
377 }
378
379 void Control::Impl::PanDetected(Actor actor, const PanGesture& pan)
380 {
381   mControlImpl.OnPan(pan);
382 }
383
384 void Control::Impl::TapDetected(Actor actor, const TapGesture& tap)
385 {
386   mControlImpl.OnTap(tap);
387 }
388
389 void Control::Impl::LongPressDetected(Actor actor, const LongPressGesture& longPress)
390 {
391   mControlImpl.OnLongPress(longPress);
392 }
393
394 void Control::Impl::RegisterVisual( Property::Index index, Toolkit::Visual::Base& visual )
395 {
396   RegisterVisual( index, visual, VisualState::ENABLED, DepthIndexValue::NOT_SET );
397 }
398
399 void Control::Impl::RegisterVisual( Property::Index index, Toolkit::Visual::Base& visual, int depthIndex )
400 {
401   RegisterVisual( index, visual, VisualState::ENABLED, DepthIndexValue::SET, depthIndex );
402 }
403
404 void Control::Impl::RegisterVisual( Property::Index index, Toolkit::Visual::Base& visual, bool enabled )
405 {
406   RegisterVisual( index, visual, ( enabled ? VisualState::ENABLED : VisualState::DISABLED ), DepthIndexValue::NOT_SET );
407 }
408
409 void Control::Impl::RegisterVisual( Property::Index index, Toolkit::Visual::Base& visual, bool enabled, int depthIndex )
410 {
411   RegisterVisual( index, visual, ( enabled ? VisualState::ENABLED : VisualState::DISABLED ), DepthIndexValue::SET, depthIndex );
412 }
413
414 void Control::Impl::RegisterVisual( Property::Index index, Toolkit::Visual::Base& visual, VisualState::Type enabled, DepthIndexValue::Type depthIndexValueSet, int depthIndex )
415 {
416   DALI_LOG_INFO( gLogFilter, Debug::Concise, "RegisterVisual:%d \n", index );
417
418   bool visualReplaced ( false );
419   Actor self = mControlImpl.Self();
420
421   // Set the depth index, if not set by caller this will be either the current visual depth, max depth of all visuals
422   // or zero.
423   int requiredDepthIndex = visual.GetDepthIndex();
424
425   if( depthIndexValueSet == DepthIndexValue::SET )
426   {
427     requiredDepthIndex = depthIndex;
428   }
429
430   // Visual replacement, existing visual should only be removed from stage when replacement ready.
431   if( !mVisuals.Empty() )
432   {
433     RegisteredVisualContainer::Iterator registeredVisualsiter;
434     // Check if visual (index) is already registered, this is the current visual.
435     if( FindVisual( index, mVisuals, registeredVisualsiter ) )
436     {
437       Toolkit::Visual::Base& currentRegisteredVisual = (*registeredVisualsiter)->visual;
438       if( currentRegisteredVisual )
439       {
440         // Store current visual depth index as may need to set the replacement visual to same depth
441         const int currentDepthIndex = (*registeredVisualsiter)->visual.GetDepthIndex();
442
443         // No longer required to know if the replaced visual's resources are ready
444         StopObservingVisual( currentRegisteredVisual );
445
446         // If control staged and visual enabled then visuals will be swapped once ready
447         if(  self.GetProperty< bool >( Actor::Property::CONNECTED_TO_SCENE ) && enabled )
448         {
449           // Check if visual is currently in the process of being replaced ( is in removal container )
450           RegisteredVisualContainer::Iterator visualQueuedForRemoval;
451           if ( FindVisual( index, mRemoveVisuals, visualQueuedForRemoval ) )
452           {
453             // Visual with same index is already in removal container so current visual pending
454             // Only the the last requested visual will be displayed so remove current visual which is staged but not ready.
455             Toolkit::GetImplementation( currentRegisteredVisual ).SetOffScene( self );
456             mVisuals.Erase( registeredVisualsiter );
457           }
458           else
459           {
460             // current visual not already in removal container so add now.
461             DALI_LOG_INFO( gLogFilter, Debug::Verbose, "RegisterVisual Move current registered visual to removal Queue: %d \n", index );
462             MoveVisual( registeredVisualsiter, mVisuals, mRemoveVisuals );
463           }
464         }
465         else
466         {
467           // Control not staged or visual disabled so can just erase from registered visuals and new visual will be added later.
468           mVisuals.Erase( registeredVisualsiter );
469         }
470
471         // 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
472         if( ( depthIndexValueSet == DepthIndexValue::NOT_SET ) &&
473             ( visual.GetDepthIndex() == 0 ) )
474         {
475           requiredDepthIndex = currentDepthIndex;
476         }
477       }
478
479       visualReplaced = true;
480     }
481   }
482
483   // If not set, set the name of the visual to the same name as the control's property.
484   // ( If the control has been type registered )
485   if( visual.GetName().empty() )
486   {
487     // returns empty string if index is not found as long as index is not -1
488     std::string visualName = self.GetPropertyName( index );
489     if( !visualName.empty() )
490     {
491       DALI_LOG_INFO( gLogFilter, Debug::Concise, "Setting visual name for property %d to %s\n",
492                      index, visualName.c_str() );
493       visual.SetName( visualName );
494     }
495   }
496
497   if( !visualReplaced ) // New registration entry
498   {
499     // 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
500     if( ( depthIndexValueSet == DepthIndexValue::NOT_SET ) &&
501         ( mVisuals.Size() > 0 ) &&
502         ( visual.GetDepthIndex() == 0 ) )
503     {
504       int maxDepthIndex = std::numeric_limits< int >::min();
505
506       RegisteredVisualContainer::ConstIterator iter;
507       const RegisteredVisualContainer::ConstIterator endIter = mVisuals.End();
508       for ( iter = mVisuals.Begin(); iter != endIter; iter++ )
509       {
510         const int visualDepthIndex = (*iter)->visual.GetDepthIndex();
511         if ( visualDepthIndex > maxDepthIndex )
512         {
513           maxDepthIndex = visualDepthIndex;
514         }
515       }
516       ++maxDepthIndex; // Add one to the current maximum depth index so that our added visual appears on top
517       requiredDepthIndex = std::max( 0, maxDepthIndex ); // Start at zero if maxDepth index belongs to a background
518     }
519   }
520
521   if( visual )
522   {
523     // Set determined depth index
524     visual.SetDepthIndex( requiredDepthIndex );
525
526     // Monitor when the visual resources are ready
527     StartObservingVisual( visual );
528
529     DALI_LOG_INFO( gLogFilter, Debug::Concise, "New Visual registration index[%d] depth[%d]\n", index, requiredDepthIndex );
530     RegisteredVisual* newRegisteredVisual  = new RegisteredVisual( index, visual,
531                                              ( enabled == VisualState::ENABLED ? true : false ),
532                                              ( visualReplaced && enabled ) ) ;
533     mVisuals.PushBack( newRegisteredVisual );
534
535     Internal::Visual::Base& visualImpl = Toolkit::GetImplementation( visual );
536     // Put on stage if enabled and the control is already on the stage
537     if( ( enabled == VisualState::ENABLED ) && self.GetProperty< bool >( Actor::Property::CONNECTED_TO_SCENE ) )
538     {
539       visualImpl.SetOnScene( self );
540     }
541     else if( visualImpl.IsResourceReady() ) // When not being staged, check if visual already 'ResourceReady' before it was Registered. ( Resource may have been loaded already )
542     {
543       ResourceReady( visualImpl );
544     }
545
546   }
547
548   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Control::RegisterVisual() Registered %s(%d), enabled:%s\n",  visual.GetName().c_str(), index, enabled?"true":"false" );
549 }
550
551 void Control::Impl::UnregisterVisual( Property::Index index )
552 {
553   RegisteredVisualContainer::Iterator iter;
554   if ( FindVisual( index, mVisuals, iter ) )
555   {
556     // stop observing visual
557     StopObservingVisual( (*iter)->visual );
558
559     Actor self( mControlImpl.Self() );
560     Toolkit::GetImplementation((*iter)->visual).SetOffScene( self );
561     (*iter)->visual.Reset();
562     mVisuals.Erase( iter );
563   }
564
565   if( FindVisual( index, mRemoveVisuals, iter ) )
566   {
567     Actor self( mControlImpl.Self() );
568     Toolkit::GetImplementation( (*iter)->visual ).SetOffScene( self );
569     (*iter)->pending = false;
570     (*iter)->visual.Reset();
571     mRemoveVisuals.Erase( iter );
572   }
573 }
574
575 Toolkit::Visual::Base Control::Impl::GetVisual( Property::Index index ) const
576 {
577   RegisteredVisualContainer::Iterator iter;
578   if ( FindVisual( index, mVisuals, iter ) )
579   {
580     return (*iter)->visual;
581   }
582
583   return Toolkit::Visual::Base();
584 }
585
586 void Control::Impl::EnableVisual( Property::Index index, bool enable )
587 {
588   DALI_LOG_INFO( gLogFilter, Debug::General, "Control::EnableVisual(%d, %s)\n", index, enable?"T":"F");
589
590   RegisteredVisualContainer::Iterator iter;
591   if ( FindVisual( index, mVisuals, iter ) )
592   {
593     if (  (*iter)->enabled == enable )
594     {
595       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Control::EnableVisual Visual %s(%d) already %s\n", (*iter)->visual.GetName().c_str(), index, enable?"enabled":"disabled");
596       return;
597     }
598
599     (*iter)->enabled = enable;
600     Actor parentActor = mControlImpl.Self();
601     if ( mControlImpl.Self().GetProperty< bool >( Actor::Property::CONNECTED_TO_SCENE ) ) // If control not on Scene then Visual will be added when SceneConnection is called.
602     {
603       if ( enable )
604       {
605         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Control::EnableVisual Setting %s(%d) on stage \n", (*iter)->visual.GetName().c_str(), index );
606         Toolkit::GetImplementation((*iter)->visual).SetOnScene( parentActor );
607       }
608       else
609       {
610         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Control::EnableVisual Setting %s(%d) off stage \n", (*iter)->visual.GetName().c_str(), index );
611         Toolkit::GetImplementation((*iter)->visual).SetOffScene( parentActor );  // No need to call if control not staged.
612       }
613     }
614   }
615   else
616   {
617     DALI_LOG_WARNING( "Control::EnableVisual(%d, %s) FAILED - NO SUCH VISUAL\n", index, enable?"T":"F" );
618   }
619 }
620
621 bool Control::Impl::IsVisualEnabled( Property::Index index ) const
622 {
623   RegisteredVisualContainer::Iterator iter;
624   if ( FindVisual( index, mVisuals, iter ) )
625   {
626     return (*iter)->enabled;
627   }
628   return false;
629 }
630
631 void Control::Impl::StopObservingVisual( Toolkit::Visual::Base& visual )
632 {
633   Internal::Visual::Base& visualImpl = Toolkit::GetImplementation( visual );
634
635   // Stop observing the visual
636   visualImpl.RemoveEventObserver( *this );
637 }
638
639 void Control::Impl::StartObservingVisual( Toolkit::Visual::Base& visual)
640 {
641   Internal::Visual::Base& visualImpl = Toolkit::GetImplementation( visual );
642
643   // start observing the visual for events
644   visualImpl.AddEventObserver( *this );
645 }
646
647 // Called by a Visual when it's resource is ready
648 void Control::Impl::ResourceReady( Visual::Base& object)
649 {
650   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Control::Impl::ResourceReady() replacements pending[%d]\n", mRemoveVisuals.Count() );
651
652   Actor self = mControlImpl.Self();
653
654   // A resource is ready, find resource in the registered visuals container and get its index
655   for( auto registeredIter = mVisuals.Begin(),  end = mVisuals.End(); registeredIter != end; ++registeredIter )
656   {
657     Internal::Visual::Base& registeredVisualImpl = Toolkit::GetImplementation( (*registeredIter)->visual );
658
659     if( &object == &registeredVisualImpl )
660     {
661       RegisteredVisualContainer::Iterator visualToRemoveIter;
662       // Find visual with the same index in the removal container
663       // Set if off stage as it's replacement is now ready.
664       // Remove if from removal list as now removed from stage.
665       // Set Pending flag on the ready visual to false as now ready.
666       if( FindVisual( (*registeredIter)->index, mRemoveVisuals, visualToRemoveIter ) )
667       {
668         (*registeredIter)->pending = false;
669         Toolkit::GetImplementation( (*visualToRemoveIter)->visual ).SetOffScene( self );
670         mRemoveVisuals.Erase( visualToRemoveIter );
671       }
672       break;
673     }
674   }
675
676   // A visual is ready so control may need relayouting if staged
677   if ( self.GetProperty< bool >( Actor::Property::CONNECTED_TO_SCENE ) )
678   {
679     mControlImpl.RelayoutRequest();
680   }
681
682   // Emit signal if all enabled visuals registered by the control are ready.
683   if( IsResourceReady() )
684   {
685     // Reset the flag
686     mNeedToEmitResourceReady = false;
687
688     EmitResourceReadySignal();
689   }
690 }
691
692 void Control::Impl::NotifyVisualEvent( Visual::Base& object, Property::Index signalId )
693 {
694   for( auto registeredIter = mVisuals.Begin(),  end = mVisuals.End(); registeredIter != end; ++registeredIter )
695   {
696     Internal::Visual::Base& registeredVisualImpl = Toolkit::GetImplementation( (*registeredIter)->visual );
697     if( &object == &registeredVisualImpl )
698     {
699       Dali::Toolkit::Control handle( mControlImpl.GetOwner() );
700       mVisualEventSignal.Emit( handle, (*registeredIter)->index, signalId );
701       break;
702     }
703   }
704 }
705
706 bool Control::Impl::IsResourceReady() const
707 {
708   // Iterate through and check all the enabled visuals are ready
709   for( auto visualIter = mVisuals.Begin();
710          visualIter != mVisuals.End(); ++visualIter )
711   {
712     const Toolkit::Visual::Base visual = (*visualIter)->visual;
713     const Internal::Visual::Base& visualImpl = Toolkit::GetImplementation( visual );
714
715     // one of the enabled visuals is not ready
716     if( !visualImpl.IsResourceReady() && (*visualIter)->enabled )
717     {
718       return false;
719     }
720   }
721   return true;
722 }
723
724 Toolkit::Visual::ResourceStatus Control::Impl::GetVisualResourceStatus( Property::Index index ) const
725 {
726   RegisteredVisualContainer::Iterator iter;
727   if ( FindVisual( index, mVisuals, iter ) )
728   {
729     const Toolkit::Visual::Base visual = (*iter)->visual;
730     const Internal::Visual::Base& visualImpl = Toolkit::GetImplementation( visual );
731     return visualImpl.GetResourceStatus( );
732   }
733
734   return Toolkit::Visual::ResourceStatus::PREPARING;
735 }
736
737
738
739 void Control::Impl::AddTransitions( Dali::Animation& animation,
740                                     const Toolkit::TransitionData& handle,
741                                     bool createAnimation )
742 {
743   // Setup a Transition from TransitionData.
744   const Internal::TransitionData& transitionData = Toolkit::GetImplementation( handle );
745   TransitionData::Iterator end = transitionData.End();
746   for( TransitionData::Iterator iter = transitionData.Begin() ;
747        iter != end; ++iter )
748   {
749     TransitionData::Animator* animator = (*iter);
750
751     Toolkit::Visual::Base visual = GetVisualByName( mVisuals, animator->objectName );
752
753     if( visual )
754     {
755 #if defined(DEBUG_ENABLED)
756       Dali::TypeInfo typeInfo;
757       ControlWrapper* controlWrapperImpl = dynamic_cast<ControlWrapper*>(&mControlImpl);
758       if( controlWrapperImpl )
759       {
760         typeInfo = controlWrapperImpl->GetTypeInfo();
761       }
762
763       DALI_LOG_INFO( gLogFilter, Debug::Concise, "CreateTransition: Found %s visual for %s\n",
764                      visual.GetName().c_str(), typeInfo?typeInfo.GetName().c_str():"Unknown" );
765 #endif
766       Internal::Visual::Base& visualImpl = Toolkit::GetImplementation( visual );
767       visualImpl.AnimateProperty( animation, *animator );
768     }
769     else
770     {
771       DALI_LOG_INFO( gLogFilter, Debug::Concise, "CreateTransition: Could not find visual. Trying actors");
772       // Otherwise, try any actor children of control (Including the control)
773       Actor child = mControlImpl.Self().FindChildByName( animator->objectName );
774       if( child )
775       {
776         Property::Index propertyIndex = child.GetPropertyIndex( animator->propertyKey );
777         if( propertyIndex != Property::INVALID_INDEX )
778         {
779           if( animator->animate == false )
780           {
781             if( animator->targetValue.GetType() != Property::NONE )
782             {
783               child.SetProperty( propertyIndex, animator->targetValue );
784             }
785           }
786           else // animate the property
787           {
788             if( animator->initialValue.GetType() != Property::NONE )
789             {
790               child.SetProperty( propertyIndex, animator->initialValue );
791             }
792
793             if( createAnimation && !animation )
794             {
795               animation = Dali::Animation::New( 0.1f );
796             }
797
798             animation.AnimateTo( Property( child, propertyIndex ),
799                                  animator->targetValue,
800                                  animator->alphaFunction,
801                                  TimePeriod( animator->timePeriodDelay,
802                                              animator->timePeriodDuration ) );
803           }
804         }
805       }
806     }
807   }
808 }
809
810 Dali::Animation Control::Impl::CreateTransition( const Toolkit::TransitionData& transitionData )
811 {
812   Dali::Animation transition;
813
814   if( transitionData.Count() > 0 )
815   {
816     AddTransitions( transition, transitionData, true );
817   }
818   return transition;
819 }
820
821
822
823 void Control::Impl::DoAction( Dali::Property::Index visualIndex, Dali::Property::Index actionId, const Dali::Property::Value attributes )
824 {
825   RegisteredVisualContainer::Iterator iter;
826   if ( FindVisual( visualIndex, mVisuals, iter ) )
827   {
828     Toolkit::GetImplementation((*iter)->visual).DoAction( actionId, attributes );
829   }
830 }
831
832 void Control::Impl::SetProperty( BaseObject* object, Property::Index index, const Property::Value& value )
833 {
834   Toolkit::Control control = Toolkit::Control::DownCast( BaseHandle( object ) );
835
836   if ( control )
837   {
838     Control& controlImpl( GetImplementation( control ) );
839
840     switch ( index )
841     {
842       case Toolkit::Control::Property::STYLE_NAME:
843       {
844         controlImpl.SetStyleName( value.Get< std::string >() );
845         break;
846       }
847
848       case Toolkit::DevelControl::Property::STATE:
849       {
850         bool withTransitions=true;
851         const Property::Value* valuePtr=&value;
852         const Property::Map* map = value.GetMap();
853         if(map)
854         {
855           Property::Value* value2 = map->Find("withTransitions");
856           if( value2 )
857           {
858             withTransitions = value2->Get<bool>();
859           }
860
861           valuePtr = map->Find("state");
862         }
863
864         if( valuePtr )
865         {
866           Toolkit::DevelControl::State state( controlImpl.mImpl->mState );
867           if( Scripting::GetEnumerationProperty< Toolkit::DevelControl::State >( *valuePtr, ControlStateTable, ControlStateTableCount, state ) )
868           {
869             controlImpl.mImpl->SetState( state, withTransitions );
870           }
871         }
872       }
873       break;
874
875       case Toolkit::DevelControl::Property::SUB_STATE:
876       {
877         std::string subState;
878         if( value.Get( subState ) )
879         {
880           controlImpl.mImpl->SetSubState( subState );
881         }
882       }
883       break;
884
885       case Toolkit::DevelControl::Property::LEFT_FOCUSABLE_ACTOR_ID:
886       {
887         int focusId;
888         if( value.Get( focusId ) )
889         {
890           controlImpl.mImpl->mLeftFocusableActorId = focusId;
891         }
892       }
893       break;
894
895       case Toolkit::DevelControl::Property::RIGHT_FOCUSABLE_ACTOR_ID:
896       {
897         int focusId;
898         if( value.Get( focusId ) )
899         {
900           controlImpl.mImpl->mRightFocusableActorId = focusId;
901         }
902       }
903       break;
904
905       case Toolkit::DevelControl::Property::UP_FOCUSABLE_ACTOR_ID:
906       {
907         int focusId;
908         if( value.Get( focusId ) )
909         {
910           controlImpl.mImpl->mUpFocusableActorId = focusId;
911         }
912       }
913       break;
914
915       case Toolkit::DevelControl::Property::DOWN_FOCUSABLE_ACTOR_ID:
916       {
917         int focusId;
918         if( value.Get( focusId ) )
919         {
920           controlImpl.mImpl->mDownFocusableActorId = focusId;
921         }
922       }
923       break;
924
925       case Toolkit::Control::Property::KEY_INPUT_FOCUS:
926       {
927         if ( value.Get< bool >() )
928         {
929           controlImpl.SetKeyInputFocus();
930         }
931         else
932         {
933           controlImpl.ClearKeyInputFocus();
934         }
935         break;
936       }
937
938       case Toolkit::Control::Property::BACKGROUND:
939       {
940         std::string url;
941         Vector4 color;
942         const Property::Map* map = value.GetMap();
943         if( map && !map->Empty() )
944         {
945           controlImpl.SetBackground( *map );
946         }
947         else if( value.Get( url ) )
948         {
949           // don't know the size to load
950           Toolkit::Visual::Base visual = Toolkit::VisualFactory::Get().CreateVisual( url, ImageDimensions() );
951           if( visual )
952           {
953             controlImpl.mImpl->RegisterVisual( Toolkit::Control::Property::BACKGROUND, visual, DepthIndex::BACKGROUND );
954           }
955         }
956         else if( value.Get( color ) )
957         {
958           controlImpl.SetBackgroundColor(color);
959         }
960         else
961         {
962           // The background is an empty property map, so we should clear the background
963           controlImpl.ClearBackground();
964         }
965         break;
966       }
967
968       case Toolkit::Control::Property::MARGIN:
969       {
970         Extents margin;
971         if( value.Get( margin ) )
972         {
973           controlImpl.mImpl->SetMargin( margin );
974         }
975         break;
976       }
977
978       case Toolkit::Control::Property::PADDING:
979       {
980         Extents padding;
981         if( value.Get( padding ) )
982         {
983           controlImpl.mImpl->SetPadding( padding );
984         }
985         break;
986       }
987
988       case Toolkit::DevelControl::Property::TOOLTIP:
989       {
990         TooltipPtr& tooltipPtr = controlImpl.mImpl->mTooltip;
991         if( ! tooltipPtr )
992         {
993           tooltipPtr = Tooltip::New( control );
994         }
995         tooltipPtr->SetProperties( value );
996         break;
997       }
998
999       case Toolkit::DevelControl::Property::SHADOW:
1000       {
1001         const Property::Map* map = value.GetMap();
1002         if( map && !map->Empty() )
1003         {
1004           controlImpl.mImpl->SetShadow( *map );
1005         }
1006         else
1007         {
1008           // The shadow is an empty property map, so we should clear the shadow
1009           controlImpl.mImpl->ClearShadow();
1010         }
1011         break;
1012       }
1013
1014     }
1015   }
1016 }
1017
1018 Property::Value Control::Impl::GetProperty( BaseObject* object, Property::Index index )
1019 {
1020   Property::Value value;
1021
1022   Toolkit::Control control = Toolkit::Control::DownCast( BaseHandle( object ) );
1023
1024   if ( control )
1025   {
1026     Control& controlImpl( GetImplementation( control ) );
1027
1028     switch ( index )
1029     {
1030       case Toolkit::Control::Property::STYLE_NAME:
1031       {
1032         value = controlImpl.GetStyleName();
1033         break;
1034       }
1035
1036       case Toolkit::DevelControl::Property::STATE:
1037       {
1038         value = controlImpl.mImpl->mState;
1039         break;
1040       }
1041
1042       case Toolkit::DevelControl::Property::SUB_STATE:
1043       {
1044         value = controlImpl.mImpl->mSubStateName;
1045         break;
1046       }
1047
1048       case Toolkit::DevelControl::Property::LEFT_FOCUSABLE_ACTOR_ID:
1049       {
1050         value = controlImpl.mImpl->mLeftFocusableActorId;
1051         break;
1052       }
1053
1054       case Toolkit::DevelControl::Property::RIGHT_FOCUSABLE_ACTOR_ID:
1055       {
1056         value = controlImpl.mImpl->mRightFocusableActorId;
1057         break;
1058       }
1059
1060       case Toolkit::DevelControl::Property::UP_FOCUSABLE_ACTOR_ID:
1061       {
1062         value = controlImpl.mImpl->mUpFocusableActorId;
1063         break;
1064       }
1065
1066       case Toolkit::DevelControl::Property::DOWN_FOCUSABLE_ACTOR_ID:
1067       {
1068         value = controlImpl.mImpl->mDownFocusableActorId;
1069         break;
1070       }
1071
1072       case Toolkit::Control::Property::KEY_INPUT_FOCUS:
1073       {
1074         value = controlImpl.HasKeyInputFocus();
1075         break;
1076       }
1077
1078       case Toolkit::Control::Property::BACKGROUND:
1079       {
1080         Property::Map map;
1081         Toolkit::Visual::Base visual = controlImpl.mImpl->GetVisual( Toolkit::Control::Property::BACKGROUND );
1082         if( visual )
1083         {
1084           visual.CreatePropertyMap( map );
1085         }
1086
1087         value = map;
1088         break;
1089       }
1090
1091       case Toolkit::Control::Property::MARGIN:
1092       {
1093         value = controlImpl.mImpl->GetMargin();
1094         break;
1095       }
1096
1097       case Toolkit::Control::Property::PADDING:
1098       {
1099         value = controlImpl.mImpl->GetPadding();
1100         break;
1101       }
1102
1103       case Toolkit::DevelControl::Property::TOOLTIP:
1104       {
1105         Property::Map map;
1106         if( controlImpl.mImpl->mTooltip )
1107         {
1108           controlImpl.mImpl->mTooltip->CreatePropertyMap( map );
1109         }
1110         value = map;
1111         break;
1112       }
1113
1114       case Toolkit::DevelControl::Property::SHADOW:
1115       {
1116         Property::Map map;
1117         Toolkit::Visual::Base visual = controlImpl.mImpl->GetVisual( Toolkit::DevelControl::Property::SHADOW );
1118         if( visual )
1119         {
1120           visual.CreatePropertyMap( map );
1121         }
1122
1123         value = map;
1124         break;
1125       }
1126     }
1127   }
1128
1129   return value;
1130 }
1131
1132
1133 void  Control::Impl::CopyInstancedProperties( RegisteredVisualContainer& visuals, Dictionary<Property::Map>& instancedProperties )
1134 {
1135   for(RegisteredVisualContainer::Iterator iter = visuals.Begin(); iter!= visuals.End(); iter++)
1136   {
1137     if( (*iter)->visual )
1138     {
1139       Property::Map instanceMap;
1140       Toolkit::GetImplementation((*iter)->visual).CreateInstancePropertyMap(instanceMap);
1141       instancedProperties.Add( (*iter)->visual.GetName(), instanceMap );
1142     }
1143   }
1144 }
1145
1146
1147 void Control::Impl::RemoveVisual( RegisteredVisualContainer& visuals, const std::string& visualName )
1148 {
1149   Actor self( mControlImpl.Self() );
1150
1151   for ( RegisteredVisualContainer::Iterator visualIter = visuals.Begin();
1152         visualIter != visuals.End(); ++visualIter )
1153   {
1154     Toolkit::Visual::Base visual = (*visualIter)->visual;
1155     if( visual && visual.GetName() == visualName )
1156     {
1157       Toolkit::GetImplementation(visual).SetOffScene( self );
1158       (*visualIter)->visual.Reset();
1159       visuals.Erase( visualIter );
1160       break;
1161     }
1162   }
1163 }
1164
1165 void Control::Impl::RemoveVisuals( RegisteredVisualContainer& visuals, DictionaryKeys& removeVisuals )
1166 {
1167   Actor self( mControlImpl.Self() );
1168   for( DictionaryKeys::iterator iter = removeVisuals.begin(); iter != removeVisuals.end(); ++iter )
1169   {
1170     const std::string visualName = *iter;
1171     RemoveVisual( visuals, visualName );
1172   }
1173 }
1174
1175 void Control::Impl::RecreateChangedVisuals( Dictionary<Property::Map>& stateVisualsToChange,
1176                              Dictionary<Property::Map>& instancedProperties )
1177 {
1178   Dali::CustomActor handle( mControlImpl.GetOwner() );
1179   for( Dictionary<Property::Map>::iterator iter = stateVisualsToChange.Begin();
1180        iter != stateVisualsToChange.End(); ++iter )
1181   {
1182     const std::string& visualName = (*iter).key;
1183     const Property::Map& toMap = (*iter).entry;
1184
1185     // is it a candidate for re-creation?
1186     bool recreate = false;
1187
1188     Toolkit::Visual::Base visual = GetVisualByName( mVisuals, visualName );
1189     if( visual )
1190     {
1191       Property::Map fromMap;
1192       visual.CreatePropertyMap( fromMap );
1193
1194       Toolkit::Visual::Type fromType = GetVisualTypeFromMap( fromMap );
1195       Toolkit::Visual::Type toType = GetVisualTypeFromMap( toMap );
1196
1197       if( fromType != toType )
1198       {
1199         recreate = true;
1200       }
1201       else
1202       {
1203         if( fromType == Toolkit::Visual::IMAGE || fromType == Toolkit::Visual::N_PATCH
1204             || fromType == Toolkit::Visual::SVG || fromType == Toolkit::Visual::ANIMATED_IMAGE )
1205         {
1206           Property::Value* fromUrl = fromMap.Find( Toolkit::ImageVisual::Property::URL, IMAGE_URL_NAME );
1207           Property::Value* toUrl = toMap.Find( Toolkit::ImageVisual::Property::URL, IMAGE_URL_NAME );
1208
1209           if( fromUrl && toUrl )
1210           {
1211             std::string fromUrlString;
1212             std::string toUrlString;
1213             fromUrl->Get(fromUrlString);
1214             toUrl->Get(toUrlString);
1215
1216             if( fromUrlString != toUrlString )
1217             {
1218               recreate = true;
1219             }
1220           }
1221         }
1222       }
1223
1224       const Property::Map* instancedMap = instancedProperties.FindConst( visualName );
1225       if( recreate || instancedMap )
1226       {
1227         RemoveVisual( mVisuals, visualName );
1228         Style::ApplyVisual( handle, visualName, toMap, instancedMap );
1229       }
1230       else
1231       {
1232         // @todo check to see if we can apply toMap without recreating the visual
1233         // e.g. by setting only animatable properties
1234         // For now, recreate all visuals, but merge in instance data.
1235         RemoveVisual( mVisuals, visualName );
1236         Style::ApplyVisual( handle, visualName, toMap, instancedMap );
1237       }
1238     }
1239   }
1240 }
1241
1242 void Control::Impl::ReplaceStateVisualsAndProperties( const StylePtr oldState, const StylePtr newState, const std::string& subState )
1243 {
1244   // Collect all old visual names
1245   DictionaryKeys stateVisualsToRemove;
1246   if( oldState )
1247   {
1248     oldState->visuals.GetKeys( stateVisualsToRemove );
1249     if( ! subState.empty() )
1250     {
1251       const StylePtr* oldSubState = oldState->subStates.FindConst(subState);
1252       if( oldSubState )
1253       {
1254         DictionaryKeys subStateVisualsToRemove;
1255         (*oldSubState)->visuals.GetKeys( subStateVisualsToRemove );
1256         Merge( stateVisualsToRemove, subStateVisualsToRemove );
1257       }
1258     }
1259   }
1260
1261   // Collect all new visual properties
1262   Dictionary<Property::Map> stateVisualsToAdd;
1263   if( newState )
1264   {
1265     stateVisualsToAdd = newState->visuals;
1266     if( ! subState.empty() )
1267     {
1268       const StylePtr* newSubState = newState->subStates.FindConst(subState);
1269       if( newSubState )
1270       {
1271         stateVisualsToAdd.Merge( (*newSubState)->visuals );
1272       }
1273     }
1274   }
1275
1276   // If a name is in both add/remove, move it to change list.
1277   Dictionary<Property::Map> stateVisualsToChange;
1278   FindChangableVisuals( stateVisualsToAdd, stateVisualsToChange, stateVisualsToRemove);
1279
1280   // Copy instanced properties (e.g. text label) of current visuals
1281   Dictionary<Property::Map> instancedProperties;
1282   CopyInstancedProperties( mVisuals, instancedProperties );
1283
1284   // For each visual in remove list, remove from mVisuals
1285   RemoveVisuals( mVisuals, stateVisualsToRemove );
1286
1287   // For each visual in add list, create and add to mVisuals
1288   Dali::CustomActor handle( mControlImpl.GetOwner() );
1289   Style::ApplyVisuals( handle, stateVisualsToAdd, instancedProperties );
1290
1291   // For each visual in change list, if it requires a new visual,
1292   // remove old visual, create and add to mVisuals
1293   RecreateChangedVisuals( stateVisualsToChange, instancedProperties );
1294 }
1295
1296 void Control::Impl::SetState( DevelControl::State newState, bool withTransitions )
1297 {
1298   DevelControl::State oldState = mState;
1299   Dali::CustomActor handle( mControlImpl.GetOwner() );
1300   DALI_LOG_INFO(gLogFilter, Debug::Concise, "Control::Impl::SetState: %s\n",
1301                 (mState == DevelControl::NORMAL ? "NORMAL" :(
1302                   mState == DevelControl::FOCUSED ?"FOCUSED" : (
1303                     mState == DevelControl::DISABLED?"DISABLED":"NONE" ))));
1304
1305   if( mState != newState )
1306   {
1307     // If mState was Disabled, and new state is Focused, should probably
1308     // store that fact, e.g. in another property that FocusManager can access.
1309     mState = newState;
1310
1311     // Trigger state change and transitions
1312     // Apply new style, if stylemanager is available
1313     Toolkit::StyleManager styleManager = Toolkit::StyleManager::Get();
1314     if( styleManager )
1315     {
1316       const StylePtr stylePtr = GetImpl( styleManager ).GetRecordedStyle( Toolkit::Control( mControlImpl.GetOwner() ) );
1317
1318       if( stylePtr )
1319       {
1320         std::string oldStateName = Scripting::GetEnumerationName< Toolkit::DevelControl::State >( oldState, ControlStateTable, ControlStateTableCount );
1321         std::string newStateName = Scripting::GetEnumerationName< Toolkit::DevelControl::State >( newState, ControlStateTable, ControlStateTableCount );
1322
1323         const StylePtr* newStateStyle = stylePtr->subStates.Find( newStateName );
1324         const StylePtr* oldStateStyle = stylePtr->subStates.Find( oldStateName );
1325         if( oldStateStyle && newStateStyle )
1326         {
1327           // Only change if both state styles exist
1328           ReplaceStateVisualsAndProperties( *oldStateStyle, *newStateStyle, mSubStateName );
1329         }
1330       }
1331     }
1332   }
1333 }
1334
1335 void Control::Impl::SetSubState( const std::string& subStateName, bool withTransitions )
1336 {
1337   if( mSubStateName != subStateName )
1338   {
1339     // Get existing sub-state visuals, and unregister them
1340     Dali::CustomActor handle( mControlImpl.GetOwner() );
1341
1342     Toolkit::StyleManager styleManager = Toolkit::StyleManager::Get();
1343     if( styleManager )
1344     {
1345       const StylePtr stylePtr = GetImpl( styleManager ).GetRecordedStyle( Toolkit::Control( mControlImpl.GetOwner() ) );
1346       if( stylePtr )
1347       {
1348         // Stringify state
1349         std::string stateName = Scripting::GetEnumerationName< Toolkit::DevelControl::State >( mState, ControlStateTable, ControlStateTableCount );
1350
1351         const StylePtr* state = stylePtr->subStates.Find( stateName );
1352         if( state )
1353         {
1354           StylePtr stateStyle(*state);
1355
1356           const StylePtr* newStateStyle = stateStyle->subStates.Find( subStateName );
1357           const StylePtr* oldStateStyle = stateStyle->subStates.Find( mSubStateName );
1358           if( oldStateStyle && newStateStyle )
1359           {
1360             std::string empty;
1361             ReplaceStateVisualsAndProperties( *oldStateStyle, *newStateStyle, empty );
1362           }
1363         }
1364       }
1365     }
1366
1367     mSubStateName = subStateName;
1368   }
1369 }
1370
1371 void Control::Impl::OnSceneDisconnection()
1372 {
1373   Actor self = mControlImpl.Self();
1374
1375   // Any visuals set for replacement but not yet ready should still be registered.
1376   // Reason: If a request was made to register a new visual but the control removed from scene before visual was ready
1377   // then when this control appears back on stage it should use that new visual.
1378
1379   // Iterate through all registered visuals and set off scene
1380   SetVisualsOffScene( mVisuals, self );
1381
1382   // Visuals pending replacement can now be taken out of the removal list and set off scene
1383   // Iterate through all replacement visuals and add to a move queue then set off scene
1384   for( auto removalIter = mRemoveVisuals.Begin(), end = mRemoveVisuals.End(); removalIter != end; removalIter++ )
1385   {
1386     Toolkit::GetImplementation((*removalIter)->visual).SetOffScene( self );
1387   }
1388
1389   for( auto replacedIter = mVisuals.Begin(), end = mVisuals.End(); replacedIter != end; replacedIter++ )
1390   {
1391     (*replacedIter)->pending = false;
1392   }
1393
1394   mRemoveVisuals.Clear();
1395 }
1396
1397 void Control::Impl::SetMargin( Extents margin )
1398 {
1399   mControlImpl.mImpl->mMargin = margin;
1400
1401   // Trigger a size negotiation request that may be needed when setting a margin.
1402   mControlImpl.RelayoutRequest();
1403 }
1404
1405 Extents Control::Impl::GetMargin() const
1406 {
1407   return mControlImpl.mImpl->mMargin;
1408 }
1409
1410 void Control::Impl::SetPadding( Extents padding )
1411 {
1412   mControlImpl.mImpl->mPadding = padding;
1413
1414   // Trigger a size negotiation request that may be needed when setting a padding.
1415   mControlImpl.RelayoutRequest();
1416 }
1417
1418 Extents Control::Impl::GetPadding() const
1419 {
1420   return mControlImpl.mImpl->mPadding;
1421 }
1422
1423 void Control::Impl::SetInputMethodContext( InputMethodContext& inputMethodContext )
1424 {
1425   mInputMethodContext = inputMethodContext;
1426 }
1427
1428 bool Control::Impl::FilterKeyEvent( const KeyEvent& event )
1429 {
1430   bool consumed ( false );
1431
1432   if ( mInputMethodContext )
1433   {
1434     consumed = mInputMethodContext.FilterEventKey( event );
1435   }
1436   return consumed;
1437 }
1438
1439 DevelControl::VisualEventSignalType& Control::Impl::VisualEventSignal()
1440 {
1441   return mVisualEventSignal;
1442 }
1443
1444 void Control::Impl::SetShadow( const Property::Map& map )
1445 {
1446   Toolkit::Visual::Base visual = Toolkit::VisualFactory::Get().CreateVisual( map );
1447   visual.SetName("shadow");
1448
1449   if( visual )
1450   {
1451     mControlImpl.mImpl->RegisterVisual( Toolkit::DevelControl::Property::SHADOW, visual, DepthIndex::BACKGROUND_EFFECT );
1452
1453     mControlImpl.RelayoutRequest();
1454   }
1455 }
1456
1457 void Control::Impl::ClearShadow()
1458 {
1459    mControlImpl.mImpl->UnregisterVisual( Toolkit::DevelControl::Property::SHADOW );
1460
1461    // Trigger a size negotiation request that may be needed when unregistering a visual.
1462    mControlImpl.RelayoutRequest();
1463 }
1464
1465 void Control::Impl::EmitResourceReadySignal()
1466 {
1467   if(!mIsEmittingResourceReadySignal)
1468   {
1469     // Guard against calls to emit the signal during the callback
1470     mIsEmittingResourceReadySignal = true;
1471
1472     // If the signal handler changes visual, it may become ready during this call & therefore this method will
1473     // get called again recursively. If so, mNeedToEmitResourceReady is set below, and we act on it after that secondary
1474     // invocation has completed by notifying in an Idle callback to prevent further recursion.
1475     Dali::Toolkit::Control handle(mControlImpl.GetOwner());
1476     mResourceReadySignal.Emit(handle);
1477
1478     if(mNeedToEmitResourceReady)
1479     {
1480       // Add idler to emit the signal again
1481       if(!mIdleCallback)
1482       {
1483         // The callback manager takes the ownership of the callback object.
1484         mIdleCallback = MakeCallback( this, &Control::Impl::OnIdleCallback);
1485         Adaptor::Get().AddIdle(mIdleCallback, false);
1486       }
1487     }
1488
1489     mIsEmittingResourceReadySignal = false;
1490   }
1491   else
1492   {
1493     mNeedToEmitResourceReady = true;
1494   }
1495 }
1496
1497 void Control::Impl::OnIdleCallback()
1498 {
1499   if(mNeedToEmitResourceReady)
1500   {
1501     // Reset the flag
1502     mNeedToEmitResourceReady = false;
1503
1504     // A visual is ready so control may need relayouting if staged
1505     if(mControlImpl.Self().GetProperty<bool>(Actor::Property::CONNECTED_TO_SCENE))
1506     {
1507       mControlImpl.RelayoutRequest();
1508     }
1509
1510     EmitResourceReadySignal();
1511   }
1512
1513   // Set the pointer to null as the callback manager deletes the callback after execute it.
1514   mIdleCallback = nullptr;
1515 }
1516
1517 void Control::Impl::SetAutofillEnabled( bool autofillEnabled )
1518 {
1519   mIsAutofillEnabled = autofillEnabled;
1520 }
1521
1522 bool Control::Impl::IsAutofillEnabled()
1523 {
1524   return mIsAutofillEnabled;
1525 }
1526
1527 void Control::Impl::SetAutofillItemHandle( Dali::AutofillItem item )
1528 {
1529   mAutofillItem = item;
1530 }
1531
1532 Dali::AutofillItem Control::Impl::GetAutofillItemHandle()
1533 {
1534   return mAutofillItem;
1535 }
1536
1537 void Control::Impl::SetAutofillContainer( Toolkit::AutofillContainer container )
1538 {
1539   mAutofillContainer = container;
1540 }
1541
1542 Toolkit::AutofillContainer Control::Impl::GetAutofillContainer()
1543 {
1544   return mAutofillContainer;
1545 }
1546
1547 } // namespace Internal
1548
1549 } // namespace Toolkit
1550
1551 } // namespace Dali