2 * Copyright (c) 2017 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 #include "control-data-impl.h"
22 #include <dali/public-api/common/dali-common.h>
23 #include <dali/integration-api/debug.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>
32 #include <dali-toolkit/internal/visuals/visual-base-impl.h>
33 #include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
34 #include <dali-toolkit/internal/styling/style-manager-impl.h>
35 #include <dali-toolkit/public-api/visuals/image-visual-properties.h>
36 #include <dali-toolkit/devel-api/visuals/visual-properties-devel.h>
37 #include <dali-toolkit/internal/visuals/visual-string-constants.h>
38 #include <dali-toolkit/devel-api/controls/control-devel.h>
52 #if defined(DEBUG_ENABLED)
53 Debug::Filter* gLogFilter = Debug::Filter::New( Debug::NoLogging, false, "LOG_CONTROL_VISUALS");
57 * Finds visual in given array, returning true if found along with the iterator for that visual as a out parameter
59 bool FindVisual( Property::Index targetIndex, const RegisteredVisualContainer& visuals, RegisteredVisualContainer::Iterator& iter )
61 for ( iter = visuals.Begin(); iter != visuals.End(); iter++ )
63 if ( (*iter)->index == targetIndex )
75 * Performs actions as requested using the action name.
76 * @param[in] object The object on which to perform the action.
77 * @param[in] actionName The action to perform.
78 * @param[in] attributes The attributes with which to perfrom this action.
79 * @return true if action has been accepted by this control
81 const char* ACTION_ACCESSIBILITY_ACTIVATED = "accessibilityActivated";
82 static bool DoAction( BaseObject* object, const std::string& actionName, const Property::Map& attributes )
86 if( object && ( 0 == strcmp( actionName.c_str(), ACTION_ACCESSIBILITY_ACTIVATED ) ) )
88 Toolkit::Control control = Toolkit::Control::DownCast( BaseHandle( object ) );
91 // if cast succeeds there is an implementation so no need to check
92 ret = Internal::GetImplementation( control ).OnAccessibilityActivated();
100 * Connects a callback function with the object's signals.
101 * @param[in] object The object providing the signal.
102 * @param[in] tracker Used to disconnect the signal.
103 * @param[in] signalName The signal to connect to.
104 * @param[in] functor A newly allocated FunctorDelegate.
105 * @return True if the signal was connected.
106 * @post If a signal was connected, ownership of functor was passed to CallbackBase. Otherwise the caller is responsible for deleting the unused functor.
108 const char* SIGNAL_KEY_EVENT = "keyEvent";
109 const char* SIGNAL_KEY_INPUT_FOCUS_GAINED = "keyInputFocusGained";
110 const char* SIGNAL_KEY_INPUT_FOCUS_LOST = "keyInputFocusLost";
111 const char* SIGNAL_TAPPED = "tapped";
112 const char* SIGNAL_PANNED = "panned";
113 const char* SIGNAL_PINCHED = "pinched";
114 const char* SIGNAL_LONG_PRESSED = "longPressed";
115 static bool DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
117 Dali::BaseHandle handle( object );
119 bool connected( false );
120 Toolkit::Control control = Toolkit::Control::DownCast( handle );
123 Internal::Control& controlImpl( Internal::GetImplementation( control ) );
126 if ( 0 == strcmp( signalName.c_str(), SIGNAL_KEY_EVENT ) )
128 controlImpl.KeyEventSignal().Connect( tracker, functor );
130 else if( 0 == strcmp( signalName.c_str(), SIGNAL_KEY_INPUT_FOCUS_GAINED ) )
132 controlImpl.KeyInputFocusGainedSignal().Connect( tracker, functor );
134 else if( 0 == strcmp( signalName.c_str(), SIGNAL_KEY_INPUT_FOCUS_LOST ) )
136 controlImpl.KeyInputFocusLostSignal().Connect( tracker, functor );
138 else if( 0 == strcmp( signalName.c_str(), SIGNAL_TAPPED ) )
140 controlImpl.EnableGestureDetection( Gesture::Tap );
141 controlImpl.GetTapGestureDetector().DetectedSignal().Connect( tracker, functor );
143 else if( 0 == strcmp( signalName.c_str(), SIGNAL_PANNED ) )
145 controlImpl.EnableGestureDetection( Gesture::Pan );
146 controlImpl.GetPanGestureDetector().DetectedSignal().Connect( tracker, functor );
148 else if( 0 == strcmp( signalName.c_str(), SIGNAL_PINCHED ) )
150 controlImpl.EnableGestureDetection( Gesture::Pinch );
151 controlImpl.GetPinchGestureDetector().DetectedSignal().Connect( tracker, functor );
153 else if( 0 == strcmp( signalName.c_str(), SIGNAL_LONG_PRESSED ) )
155 controlImpl.EnableGestureDetection( Gesture::LongPress );
156 controlImpl.GetLongPressGestureDetector().DetectedSignal().Connect( tracker, functor );
163 * Creates control through type registry
167 return Internal::Control::New();
169 // Setup signals and actions using the type-registry.
170 DALI_TYPE_REGISTRATION_BEGIN( Control, CustomActor, Create );
172 // Note: Properties are registered separately below.
174 SignalConnectorType registerSignal1( typeRegistration, SIGNAL_KEY_EVENT, &DoConnectSignal );
175 SignalConnectorType registerSignal2( typeRegistration, SIGNAL_KEY_INPUT_FOCUS_GAINED, &DoConnectSignal );
176 SignalConnectorType registerSignal3( typeRegistration, SIGNAL_KEY_INPUT_FOCUS_LOST, &DoConnectSignal );
177 SignalConnectorType registerSignal4( typeRegistration, SIGNAL_TAPPED, &DoConnectSignal );
178 SignalConnectorType registerSignal5( typeRegistration, SIGNAL_PANNED, &DoConnectSignal );
179 SignalConnectorType registerSignal6( typeRegistration, SIGNAL_PINCHED, &DoConnectSignal );
180 SignalConnectorType registerSignal7( typeRegistration, SIGNAL_LONG_PRESSED, &DoConnectSignal );
182 TypeAction registerAction( typeRegistration, ACTION_ACCESSIBILITY_ACTIVATED, &DoAction );
184 DALI_TYPE_REGISTRATION_END()
186 } // unnamed namespace
189 // Properties registered without macro to use specific member variables.
190 const PropertyRegistration Control::Impl::PROPERTY_1( typeRegistration, "styleName", Toolkit::Control::Property::STYLE_NAME, Property::STRING, &Control::Impl::SetProperty, &Control::Impl::GetProperty );
191 const PropertyRegistration Control::Impl::PROPERTY_2( typeRegistration, "backgroundColor", Toolkit::Control::Property::BACKGROUND_COLOR, Property::VECTOR4, &Control::Impl::SetProperty, &Control::Impl::GetProperty );
192 const PropertyRegistration Control::Impl::PROPERTY_3( typeRegistration, "backgroundImage", Toolkit::Control::Property::BACKGROUND_IMAGE, Property::MAP, &Control::Impl::SetProperty, &Control::Impl::GetProperty );
193 const PropertyRegistration Control::Impl::PROPERTY_4( typeRegistration, "keyInputFocus", Toolkit::Control::Property::KEY_INPUT_FOCUS, Property::BOOLEAN, &Control::Impl::SetProperty, &Control::Impl::GetProperty );
194 const PropertyRegistration Control::Impl::PROPERTY_5( typeRegistration, "background", Toolkit::Control::Property::BACKGROUND, Property::MAP, &Control::Impl::SetProperty, &Control::Impl::GetProperty );
198 Control::Impl::Impl( Control& controlImpl )
199 : mControlImpl( controlImpl ),
201 mBackgroundColor(Color::TRANSPARENT),
202 mStartingPinchScale( NULL ),
204 mPinchGestureDetector(),
205 mPanGestureDetector(),
206 mTapGestureDetector(),
207 mLongPressGestureDetector(),
208 mFlags( Control::ControlBehaviour( CONTROL_BEHAVIOUR_DEFAULT ) ),
209 mIsKeyboardNavigationSupported( false ),
210 mIsKeyboardFocusGroup( false )
215 Control::Impl::~Impl()
217 // All gesture detectors will be destroyed so no need to disconnect.
218 delete mStartingPinchScale;
221 Control::Impl& Control::Impl::Get( Internal::Control& internalControl )
223 return *internalControl.mImpl;
226 const Control::Impl& Control::Impl::Get( const Internal::Control& internalControl )
228 return *internalControl.mImpl;
231 // Gesture Detection Methods
232 void Control::Impl::PinchDetected(Actor actor, const PinchGesture& pinch)
234 mControlImpl.OnPinch(pinch);
237 void Control::Impl::PanDetected(Actor actor, const PanGesture& pan)
239 mControlImpl.OnPan(pan);
242 void Control::Impl::TapDetected(Actor actor, const TapGesture& tap)
244 mControlImpl.OnTap(tap);
247 void Control::Impl::LongPressDetected(Actor actor, const LongPressGesture& longPress)
249 mControlImpl.OnLongPress(longPress);
252 // Called by a Visual when it's resource is ready
253 void Control::Impl::ResourceReady( Visual::Base& object)
256 // go through and check if all the visuals are ready, if they are emit a signal
257 for ( RegisteredVisualContainer::ConstIterator visualIter = mVisuals.Begin();
258 visualIter != mVisuals.End(); ++visualIter )
260 const Toolkit::Visual::Base visual = (*visualIter)->visual;
261 const Internal::Visual::Base& visualImpl = Toolkit::GetImplementation( visual );
263 // one of the visuals is not ready
264 if( !visualImpl.IsResourceReady() )
270 // all the visuals are ready
271 Dali::Toolkit::Control handle( mControlImpl.GetOwner() );
272 mResourceReadySignal.Emit( handle );
276 bool Control::Impl::IsResourceReady() const
278 // go through and check all the visuals are ready
279 for ( RegisteredVisualContainer::ConstIterator visualIter = mVisuals.Begin();
280 visualIter != mVisuals.End(); ++visualIter )
282 const Toolkit::Visual::Base visual = (*visualIter)->visual;
283 const Internal::Visual::Base& visualImpl = Toolkit::GetImplementation( visual );
285 // one of the visuals is not ready
286 if( !visualImpl.IsResourceReady() )
294 void Control::Impl::RegisterVisual( Property::Index index, Toolkit::Visual::Base& visual )
296 RegisterVisual( index, visual, true );
299 void Control::Impl::RegisterVisual( Property::Index index, Toolkit::Visual::Base& visual, bool enabled )
301 bool visualReplaced ( false );
302 Actor self = mControlImpl.Self();
304 if( !mVisuals.Empty() )
306 RegisteredVisualContainer::Iterator iter;
307 // Check if visual (index) is already registered. Replace if so.
308 if ( FindVisual( index, mVisuals, iter ) )
310 if( (*iter)->visual && self.OnStage() )
312 Toolkit::GetImplementation((*iter)->visual).SetOffStage( self );
315 StopObservingVisual( (*iter)->visual );
316 StartObservingVisual( visual );
318 (*iter)->visual = visual;
319 visualReplaced = true;
323 if( !visualReplaced ) // New registration entry
325 mVisuals.PushBack( new RegisteredVisual( index, visual, enabled ) );
327 // monitor when the visuals resources are ready
328 StartObservingVisual( visual );
332 if( visual && self.OnStage() && enabled )
334 Toolkit::GetImplementation(visual).SetOnStage( self );
337 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Control::RegisterVisual() Registered %s(%d), enabled:%s\n", visual.GetName().c_str(), index, enabled?"T":"F" );
340 void Control::Impl::UnregisterVisual( Property::Index index )
342 RegisteredVisualContainer::Iterator iter;
343 if ( FindVisual( index, mVisuals, iter ) )
345 // stop observing visual
346 StopObservingVisual( (*iter)->visual );
348 Actor self( mControlImpl.Self() );
349 Toolkit::GetImplementation((*iter)->visual).SetOffStage( self );
350 (*iter)->visual.Reset();
351 mVisuals.Erase( iter );
355 Toolkit::Visual::Base Control::Impl::GetVisual( Property::Index index ) const
357 RegisteredVisualContainer::Iterator iter;
358 if ( FindVisual( index, mVisuals, iter ) )
360 return (*iter)->visual;
363 return Toolkit::Visual::Base();
366 void Control::Impl::EnableVisual( Property::Index index, bool enable )
368 RegisteredVisualContainer::Iterator iter;
369 if ( FindVisual( index, mVisuals, iter ) )
371 if ( (*iter)->enabled == enable )
373 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Control::EnableVisual Visual %s(%d) already %s\n", (*iter)->visual.GetName().c_str(), index, enable?"enabled":"disabled");
377 (*iter)->enabled = enable;
378 Actor parentActor = mControlImpl.Self();
379 if ( mControlImpl.Self().OnStage() ) // If control not on Stage then Visual will be added when StageConnection is called.
383 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Control::EnableVisual Setting %s(%d) on stage \n", (*iter)->visual.GetName().c_str(), index );
384 Toolkit::GetImplementation((*iter)->visual).SetOnStage( parentActor );
388 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Control::EnableVisual Setting %s(%d) off stage \n", (*iter)->visual.GetName().c_str(), index );
389 Toolkit::GetImplementation((*iter)->visual).SetOffStage( parentActor ); // No need to call if control not staged.
395 bool Control::Impl::IsVisualEnabled( Property::Index index ) const
397 RegisteredVisualContainer::Iterator iter;
398 if ( FindVisual( index, mVisuals, iter ) )
400 return (*iter)->enabled;
405 void Control::Impl::StopObservingVisual( Toolkit::Visual::Base& visual )
407 Internal::Visual::Base& visualImpl = Toolkit::GetImplementation( visual );
409 // Stop observing the visual
410 visualImpl.RemoveResourceObserver( *this );
413 void Control::Impl::StartObservingVisual( Toolkit::Visual::Base& visual)
415 Internal::Visual::Base& visualImpl = Toolkit::GetImplementation( visual );
417 // start observing the visual for resource ready
418 visualImpl.AddResourceObserver( *this );
421 void Control::Impl::SetProperty( BaseObject* object, Property::Index index, const Property::Value& value )
423 Toolkit::Control control = Toolkit::Control::DownCast( BaseHandle( object ) );
427 Control& controlImpl( GetImplementation( control ) );
431 case Toolkit::Control::Property::STYLE_NAME:
433 controlImpl.SetStyleName( value.Get< std::string >() );
437 case Toolkit::Control::Property::BACKGROUND_COLOR:
439 DALI_LOG_WARNING( "BACKGROUND_COLOR property is deprecated. Use BACKGROUND property instead\n" );
440 controlImpl.SetBackgroundColor( value.Get< Vector4 >() );
444 case Toolkit::Control::Property::BACKGROUND_IMAGE:
446 DALI_LOG_WARNING( "BACKGROUND_IMAGE property is deprecated. Use BACKGROUND property instead\n" );
447 Image image = Scripting::NewImage( value );
450 controlImpl.SetBackgroundImage( image );
454 // An empty image means the background is no longer required
455 controlImpl.ClearBackground();
460 case Toolkit::Control::Property::KEY_INPUT_FOCUS:
462 if ( value.Get< bool >() )
464 controlImpl.SetKeyInputFocus();
468 controlImpl.ClearKeyInputFocus();
473 case Toolkit::Control::Property::BACKGROUND:
477 const Property::Map* map = value.GetMap();
478 if( map && !map->Empty() )
480 controlImpl.SetBackground( *map );
482 else if( value.Get( url ) )
484 // don't know the size to load
485 Toolkit::Visual::Base visual = Toolkit::VisualFactory::Get().CreateVisual( url, ImageDimensions() );
488 controlImpl.mImpl->RegisterVisual( Toolkit::Control::Property::BACKGROUND, visual );
489 visual.SetDepthIndex( DepthIndex::BACKGROUND );
492 else if( value.Get( color ) )
494 controlImpl.SetBackgroundColor(color);
498 // The background is an empty property map, so we should clear the background
499 controlImpl.ClearBackground();
507 Property::Value Control::Impl::GetProperty( BaseObject* object, Property::Index index )
509 Property::Value value;
511 Toolkit::Control control = Toolkit::Control::DownCast( BaseHandle( object ) );
515 Control& controlImpl( GetImplementation( control ) );
519 case Toolkit::Control::Property::STYLE_NAME:
521 value = controlImpl.GetStyleName();
524 case Toolkit::Control::Property::BACKGROUND_COLOR:
526 DALI_LOG_WARNING( "BACKGROUND_COLOR property is deprecated. Use BACKGROUND property instead\n" );
527 value = controlImpl.GetBackgroundColor();
531 case Toolkit::Control::Property::BACKGROUND_IMAGE:
533 DALI_LOG_WARNING( "BACKGROUND_IMAGE property is deprecated. Use BACKGROUND property instead\n" );
535 Toolkit::Visual::Base visual = controlImpl.mImpl->GetVisual( Toolkit::Control::Property::BACKGROUND );
538 visual.CreatePropertyMap( map );
544 case Toolkit::Control::Property::KEY_INPUT_FOCUS:
546 value = controlImpl.HasKeyInputFocus();
550 case Toolkit::Control::Property::BACKGROUND:
553 Toolkit::Visual::Base visual = controlImpl.mImpl->GetVisual( Toolkit::Control::Property::BACKGROUND );
556 visual.CreatePropertyMap( map );
569 void Control::Impl::RemoveVisual( RegisteredVisualContainer& visuals, const std::string& visualName )
571 Actor self( mControlImpl.Self() );
573 for ( RegisteredVisualContainer::Iterator visualIter = visuals.Begin();
574 visualIter != visuals.End(); ++visualIter )
576 Toolkit::Visual::Base visual = (*visualIter)->visual;
577 if( visual && visual.GetName() == visualName )
579 Toolkit::GetImplementation(visual).SetOffStage( self );
580 (*visualIter)->visual.Reset();
581 visuals.Erase( visualIter );
587 } // namespace Internal
589 } // namespace Toolkit