2 * Copyright (c) 2014 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.
18 #include <dali-toolkit/public-api/controls/control-impl.h>
22 #include <dali/integration-api/debug.h>
24 #include "dali-toolkit/internal/controls/relayout-controller.h"
25 #include "dali-toolkit/internal/controls/relayout-helper.h"
26 #include "dali-toolkit/public-api/focus-manager/keyinput-focus-manager.h"
27 #include "dali-toolkit/public-api/focus-manager/keyboard-focus-manager.h"
28 #include <dali-toolkit/public-api/controls/control.h>
30 #include <dali-toolkit/public-api/styling/style-manager.h>
31 #include <dali-toolkit/internal/styling/style-manager-impl.h>
39 const Property::Index Control::PROPERTY_BACKGROUND_COLOR = Internal::Control::CONTROL_PROPERTY_START_INDEX;
40 const Property::Index Control::PROPERTY_BACKGROUND = Internal::Control::CONTROL_PROPERTY_START_INDEX + 1;
41 const Property::Index Control::PROPERTY_WIDTH_POLICY = Internal::Control::CONTROL_PROPERTY_START_INDEX + 2;
42 const Property::Index Control::PROPERTY_HEIGHT_POLICY = Internal::Control::CONTROL_PROPERTY_START_INDEX + 3;
43 const Property::Index Control::PROPERTY_MINIMUM_SIZE = Internal::Control::CONTROL_PROPERTY_START_INDEX + 4;
44 const Property::Index Control::PROPERTY_MAXIMUM_SIZE = Internal::Control::CONTROL_PROPERTY_START_INDEX + 5;
45 const Property::Index Control::PROPERTY_KEY_INPUT_FOCUS = Internal::Control::CONTROL_PROPERTY_START_INDEX + 6;
50 const Scripting::StringEnum< Control::SizePolicy > SIZE_POLICY_STRING_TABLE[] =
52 { "FIXED", Control::Fixed },
53 { "MINIMUM", Control::Minimum },
54 { "MAXIMUM", Control::Maximum },
55 { "RANGE", Control::Range },
56 { "FLEXIBLE", Control::Flexible },
58 const unsigned int SIZE_POLICY_STRING_TABLE_COUNT = sizeof( SIZE_POLICY_STRING_TABLE ) / sizeof( SIZE_POLICY_STRING_TABLE[0] );
60 #if defined(DEBUG_ENABLED)
61 Integration::Log::Filter* gLogFilter = Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_CONTROL");
64 const float MAX_FLOAT_VALUE( std::numeric_limits<float>::max() );
65 const Vector3 MAX_SIZE( MAX_FLOAT_VALUE, MAX_FLOAT_VALUE, MAX_FLOAT_VALUE );
66 const float BACKGROUND_ACTOR_Z_POSITION( -0.1f );
70 return Internal::Control::New();
73 TypeRegistration CONTROL_TYPE( typeid(Control), typeid(CustomActor), Create );
75 // Property Registration after Internal::Control::Impl definition below
77 TypeAction ACTION_TYPE_1( CONTROL_TYPE, Toolkit::Control::ACTION_CONTROL_ACTIVATED, &Internal::Control::DoAction );
79 SignalConnectorType SIGNAL_CONNECTOR_1( CONTROL_TYPE, Toolkit::Control::SIGNAL_KEY_EVENT, &Internal::Control::DoConnectSignal );
80 SignalConnectorType SIGNAL_CONNECTOR_2( CONTROL_TYPE, Toolkit::Control::SIGNAL_TAPPED, &Internal::Control::DoConnectSignal );
81 SignalConnectorType SIGNAL_CONNECTOR_3( CONTROL_TYPE, Toolkit::Control::SIGNAL_PANNED, &Internal::Control::DoConnectSignal );
82 SignalConnectorType SIGNAL_CONNECTOR_4( CONTROL_TYPE, Toolkit::Control::SIGNAL_PINCHED, &Internal::Control::DoConnectSignal );
83 SignalConnectorType SIGNAL_CONNECTOR_5( CONTROL_TYPE, Toolkit::Control::SIGNAL_LONG_PRESSED, &Internal::Control::DoConnectSignal );
86 * Structure which holds information about the background of a control
90 Actor actor; ///< Either a MeshActor or an ImageActor
91 Vector4 color; ///< The color of the actor.
104 * Helper function to calculate a dimension given the policy of that dimension; the minimum &
105 * maximum values that dimension can be; and the allocated value for that dimension.
107 * @param[in] policy The size policy for that dimension.
108 * @param[in] minimum The minimum value that dimension can be.
109 * @param[in] maximum The maximum value that dimension can be.
110 * @param[in] allocated The value allocated for that dimension.
112 * @return The value that the dimension should be.
114 * @note This does not handle Control::Fixed policy.
116 float Calculate( Control::SizePolicy policy, float minimum, float maximum, float allocated )
118 float size( allocated );
124 // Use allocated value
128 case Control::Minimum:
130 // Size is always at least the minimum.
131 size = std::max( allocated, minimum );
135 case Control::Maximum:
137 // Size can grow but up to a maximum value.
138 size = std::min( allocated, maximum );
144 // Size is at least the minimum and can grow up to the maximum
145 size = std::max( size, minimum );
146 size = std::min( size, maximum );
150 case Control::Flexible:
152 // Size grows or shrinks with no limits.
159 DALI_ASSERT_DEBUG( false && "This function was not intended to be used by any other policy." );
168 * Creates a white coloured Mesh.
172 Vector3 white( Color::WHITE );
176 // Create vertices with a white color (actual color is set by actor color)
177 MeshData::VertexContainer vertices(4);
178 vertices[ 0 ] = MeshData::Vertex( Vector3( -0.5f, -0.5f, 0.0f ), Vector2::ZERO, white );
179 vertices[ 1 ] = MeshData::Vertex( Vector3( 0.5f, -0.5f, 0.0f ), Vector2::ZERO, white );
180 vertices[ 2 ] = MeshData::Vertex( Vector3( -0.5f, 0.5f, 0.0f ), Vector2::ZERO, white );
181 vertices[ 3 ] = MeshData::Vertex( Vector3( 0.5f, 0.5f, 0.0f ), Vector2::ZERO, white );
183 // Specify all the faces
184 MeshData::FaceIndices faces;
185 faces.reserve( 6 ); // 2 triangles in Quad
186 faces.push_back( 0 ); faces.push_back( 3 ); faces.push_back( 1 );
187 faces.push_back( 0 ); faces.push_back( 2 ); faces.push_back( 3 );
189 // Create the mesh data from the vertices and faces
190 meshData.SetMaterial( Material::New( "ControlMaterial" ) );
191 meshData.SetVertices( vertices );
192 meshData.SetFaceIndices( faces );
193 meshData.SetHasColor( true );
195 return Mesh::New( meshData );
199 * Sets all the required properties for the background actor.
201 * @param[in] actor The actor to set the properties on.
202 * @param[in] constrainingIndex The property index to constrain the parent's size on.
203 * @param[in] color The required color of the actor.
205 void SetupBackgroundActor( Actor actor, Property::Index constrainingIndex, const Vector4& color )
207 actor.SetColor( color );
208 actor.SetPositionInheritanceMode( USE_PARENT_POSITION_PLUS_LOCAL_POSITION );
209 actor.SetZ( BACKGROUND_ACTOR_Z_POSITION );
211 Constraint constraint = Constraint::New<Vector3>( constrainingIndex,
212 ParentSource( Actor::SIZE ),
213 EqualToConstraint() );
214 actor.ApplyConstraint( constraint );
217 } // unnamed namespace
222 class Control::Impl : public ConnectionTracker
227 * Size indices for mMinMaxSize array
236 // Construction & Destruction
237 Impl(Control& controlImpl)
238 : mControlImpl( controlImpl ),
240 mStartingPinchScale( NULL ),
242 mPinchGestureDetector(),
243 mPanGestureDetector(),
244 mTapGestureDetector(),
245 mLongPressGestureDetector(),
248 mWidthPolicy( Toolkit::Control::Fixed ),
249 mHeightPolicy( Toolkit::Control::Fixed ),
250 mFlags( Control::CONTROL_BEHAVIOUR_NONE ),
251 mInsideRelayout( false ),
252 mIsKeyboardNavigationSupported( false ),
253 mIsKeyboardFocusGroup( false ),
254 mInitialized( false )
260 // All gesture detectors will be destroyed so no need to disconnect.
262 delete mStartingPinchScale;
265 // Gesture Detection Methods
267 void PinchDetected(Actor actor, PinchGesture pinch)
269 mControlImpl.OnPinch(pinch);
272 void PanDetected(Actor actor, PanGesture pan)
274 mControlImpl.OnPan(pan);
277 void TapDetected(Actor actor, TapGesture tap)
279 mControlImpl.OnTap(tap);
282 void LongPressDetected(Actor actor, LongPressGesture longPress)
284 mControlImpl.OnLongPress(longPress);
287 // Background Methods
290 * Only creates an instance of the background if we actually use it.
291 * @return A reference to the Background structure.
293 Background& GetBackground()
297 mBackground = new Background;
305 * Called when a property of an object of this type is set.
306 * @param[in] object The object whose property is set.
307 * @param[in] index The property index.
308 * @param[in] value The new property value.
310 static void SetProperty( BaseObject* object, Property::Index index, const Property::Value& value )
312 Toolkit::Control control = Toolkit::Control::DownCast( BaseHandle( object ) );
316 Control& controlImpl( control.GetImplementation() );
320 case Toolkit::Control::PROPERTY_BACKGROUND_COLOR:
322 controlImpl.SetBackgroundColor( value.Get< Vector4 >() );
326 case Toolkit::Control::PROPERTY_BACKGROUND:
328 if ( value.HasKey( "image" ) )
330 Property::Map imageMap = value.GetValue( "image" ).Get< Property::Map >();
331 Image image = Scripting::NewImage( imageMap );
335 controlImpl.SetBackground( image );
338 else if ( value.Get< Property::Map >().empty() )
340 // An empty map means the background is no longer required
341 controlImpl.ClearBackground();
346 case Toolkit::Control::PROPERTY_WIDTH_POLICY:
348 controlImpl.mImpl->mWidthPolicy = Scripting::GetEnumeration< Toolkit::Control::SizePolicy >( value.Get< std::string >(), SIZE_POLICY_STRING_TABLE, SIZE_POLICY_STRING_TABLE_COUNT );
352 case Toolkit::Control::PROPERTY_HEIGHT_POLICY:
354 controlImpl.mImpl->mHeightPolicy = Scripting::GetEnumeration< Toolkit::Control::SizePolicy >( value.Get< std::string >(), SIZE_POLICY_STRING_TABLE, SIZE_POLICY_STRING_TABLE_COUNT );
358 case Toolkit::Control::PROPERTY_MINIMUM_SIZE:
360 controlImpl.SetMinimumSize( value.Get< Vector3 >() );
364 case Toolkit::Control::PROPERTY_MAXIMUM_SIZE:
366 controlImpl.SetMaximumSize( value.Get< Vector3 >() );
370 case Toolkit::Control::PROPERTY_KEY_INPUT_FOCUS:
372 if ( value.Get< bool >() )
374 controlImpl.SetKeyInputFocus();
378 controlImpl.ClearKeyInputFocus();
387 * Called to retrieve a property of an object of this type.
388 * @param[in] object The object whose property is to be retrieved.
389 * @param[in] index The property index.
390 * @return The current value of the property.
392 static Property::Value GetProperty( BaseObject* object, Property::Index index )
394 Property::Value value;
396 Toolkit::Control control = Toolkit::Control::DownCast( BaseHandle( object ) );
400 Control& controlImpl( control.GetImplementation() );
404 case Toolkit::Control::PROPERTY_BACKGROUND_COLOR:
406 value = controlImpl.GetBackgroundColor();
410 case Toolkit::Control::PROPERTY_BACKGROUND:
414 Actor actor = controlImpl.GetBackgroundActor();
417 ImageActor imageActor = ImageActor::DownCast( actor );
420 Image image = imageActor.GetImage();
421 Property::Map imageMap;
422 Scripting::CreatePropertyMap( image, imageMap );
423 map.push_back( Property::StringValuePair( "image", imageMap ) );
431 case Toolkit::Control::PROPERTY_WIDTH_POLICY:
433 value = std::string( Scripting::GetEnumerationName< Toolkit::Control::SizePolicy >( controlImpl.mImpl->mWidthPolicy, SIZE_POLICY_STRING_TABLE, SIZE_POLICY_STRING_TABLE_COUNT ) );
437 case Toolkit::Control::PROPERTY_HEIGHT_POLICY:
439 value = std::string( Scripting::GetEnumerationName< Toolkit::Control::SizePolicy >( controlImpl.mImpl->mHeightPolicy, SIZE_POLICY_STRING_TABLE, SIZE_POLICY_STRING_TABLE_COUNT ) );
443 case Toolkit::Control::PROPERTY_MINIMUM_SIZE:
445 value = controlImpl.mImpl->GetMinimumSize();
449 case Toolkit::Control::PROPERTY_MAXIMUM_SIZE:
451 value = controlImpl.mImpl->GetMaximumSize();
455 case Toolkit::Control::PROPERTY_KEY_INPUT_FOCUS:
457 value = controlImpl.HasKeyInputFocus();
467 * Helper to get minimum size
468 * @return minimum size
470 inline const Vector3& GetMinimumSize()
472 if( mMinMaxSize.Count() > MIN_SIZE_INDEX )
474 return mMinMaxSize[ MIN_SIZE_INDEX ];
478 // its not been allocated so its ZERO
479 return Vector3::ZERO;
483 * Helper to Set minimum size
486 inline void SetMinimumSize( const Vector3& size )
488 if( mMinMaxSize.Count() > MIN_SIZE_INDEX )
490 mMinMaxSize[ MIN_SIZE_INDEX ] = size;
494 // its not been allocated so push the new value there
495 mMinMaxSize.PushBack( size );
500 * Helper to get maximum size
501 * @return maximum size
503 inline const Vector3& GetMaximumSize()
505 if( mMinMaxSize.Count() > MAX_SIZE_INDEX )
507 return mMinMaxSize[ MAX_SIZE_INDEX ];
511 // its not been allocated so its MAX_SIZE
517 * Helper to Set minimum size
520 inline void SetMaximumSize( const Vector3& size )
522 if( mMinMaxSize.Count() > MAX_SIZE_INDEX )
524 mMinMaxSize[ MAX_SIZE_INDEX ] = size;
526 else if( mMinMaxSize.Count() > MIN_SIZE_INDEX )
528 // max has not been allocated, but min has
529 mMinMaxSize.PushBack( size );
533 // min and max both unallocated so allocate both
534 mMinMaxSize.Resize( 2u ); // this will reserve and default construct two Vector3s
535 mMinMaxSize[ MAX_SIZE_INDEX ] = size;
541 Control& mControlImpl;
542 Background* mBackground; ///< Only create the background if we use it
543 Vector3* mStartingPinchScale; ///< The scale when a pinch gesture starts, TODO: consider removing this
544 Toolkit::Control::KeyEventSignalV2 mKeyEventSignalV2;
547 PinchGestureDetector mPinchGestureDetector;
548 PanGestureDetector mPanGestureDetector;
549 TapGestureDetector mTapGestureDetector;
550 LongPressGestureDetector mLongPressGestureDetector;
551 // @todo change all these to Vector2 when we have a chance to sanitize the public API as well
552 Vector3 mCurrentSize; ///< Stores the current control's size, this is the negotiated size
553 Vector3 mNaturalSize; ///< Stores the size set through the Actor's API. This is size the actor wants to be. Useful when reset to the initial size is needed.
554 Dali::Vector< Vector3 > mMinMaxSize; ///< Stores the minimum and maximum size if they are set
556 Toolkit::Control::SizePolicy mWidthPolicy :3; ///< Stores the width policy. 3 bits covers 8 values
557 Toolkit::Control::SizePolicy mHeightPolicy :3; ///< Stores the height policy. 3 bits covers 8 values
558 ControlBehaviour mFlags :4; ///< Flags passed in from constructor. Need to increase this size when new enums are added
559 bool mInsideRelayout:1; ///< Detect when were in Relayout
560 bool mIsKeyboardNavigationSupported:1; ///< Stores whether keyboard navigation is supported by the control.
561 bool mIsKeyboardFocusGroup:1; ///< Stores whether the control is a focus group.
564 // Properties - these need to be members of Internal::Control::Impl as they need to functions within this class.
565 static PropertyRegistration PROPERTY_1;
566 static PropertyRegistration PROPERTY_2;
567 static PropertyRegistration PROPERTY_3;
568 static PropertyRegistration PROPERTY_4;
569 static PropertyRegistration PROPERTY_5;
570 static PropertyRegistration PROPERTY_6;
571 static PropertyRegistration PROPERTY_7;
574 PropertyRegistration Control::Impl::PROPERTY_1( CONTROL_TYPE, "background-color", Toolkit::Control::PROPERTY_BACKGROUND_COLOR, Property::VECTOR4, &Control::Impl::SetProperty, &Control::Impl::GetProperty );
575 PropertyRegistration Control::Impl::PROPERTY_2( CONTROL_TYPE, "background", Toolkit::Control::PROPERTY_BACKGROUND, Property::MAP, &Control::Impl::SetProperty, &Control::Impl::GetProperty );
576 PropertyRegistration Control::Impl::PROPERTY_3( CONTROL_TYPE, "width-policy", Toolkit::Control::PROPERTY_WIDTH_POLICY, Property::STRING, &Control::Impl::SetProperty, &Control::Impl::GetProperty );
577 PropertyRegistration Control::Impl::PROPERTY_4( CONTROL_TYPE, "height-policy", Toolkit::Control::PROPERTY_HEIGHT_POLICY, Property::STRING, &Control::Impl::SetProperty, &Control::Impl::GetProperty );
578 PropertyRegistration Control::Impl::PROPERTY_5( CONTROL_TYPE, "minimum-size", Toolkit::Control::PROPERTY_MINIMUM_SIZE, Property::VECTOR3, &Control::Impl::SetProperty, &Control::Impl::GetProperty );
579 PropertyRegistration Control::Impl::PROPERTY_6( CONTROL_TYPE, "maximum-size", Toolkit::Control::PROPERTY_MAXIMUM_SIZE, Property::VECTOR3, &Control::Impl::SetProperty, &Control::Impl::GetProperty );
580 PropertyRegistration Control::Impl::PROPERTY_7( CONTROL_TYPE, "key-input-focus", Toolkit::Control::PROPERTY_KEY_INPUT_FOCUS, Property::BOOLEAN, &Control::Impl::SetProperty, &Control::Impl::GetProperty );
582 Toolkit::Control Control::New()
584 // Create the implementation, temporarily owned on stack
585 IntrusivePtr<Control> controlImpl = new Control( CONTROL_BEHAVIOUR_NONE );
587 // Pass ownership to handle
588 Toolkit::Control handle( *controlImpl );
590 // Second-phase init of the implementation
591 // This can only be done after the CustomActor connection has been made...
592 controlImpl->Initialize();
602 void Control::Initialize()
605 // Calling deriving classes
608 if( mImpl->mFlags & REQUIRES_STYLE_CHANGE_SIGNALS )
610 Toolkit::StyleManager styleManager = Toolkit::StyleManager::Get();
612 // Register for style changes
613 styleManager.StyleChangeSignal().Connect( this, &Control::DoStyleChange );
616 GetImpl( styleManager ).ApplyThemeStyle( GetOwner() );
619 mImpl->mInitialized = true;
622 void Control::EnableGestureDetection(Gesture::Type type)
624 if ( (type & Gesture::Pinch) && !mImpl->mPinchGestureDetector )
626 mImpl->mPinchGestureDetector = PinchGestureDetector::New();
627 mImpl->mPinchGestureDetector.DetectedSignal().Connect(mImpl, &Impl::PinchDetected);
628 mImpl->mPinchGestureDetector.Attach(Self());
631 if ( (type & Gesture::Pan) && !mImpl->mPanGestureDetector )
633 mImpl->mPanGestureDetector = PanGestureDetector::New();
634 mImpl->mPanGestureDetector.DetectedSignal().Connect(mImpl, &Impl::PanDetected);
635 mImpl->mPanGestureDetector.Attach(Self());
638 if ( (type & Gesture::Tap) && !mImpl->mTapGestureDetector )
640 mImpl->mTapGestureDetector = TapGestureDetector::New();
641 mImpl->mTapGestureDetector.DetectedSignal().Connect(mImpl, &Impl::TapDetected);
642 mImpl->mTapGestureDetector.Attach(Self());
645 if ( (type & Gesture::LongPress) && !mImpl->mLongPressGestureDetector )
647 mImpl->mLongPressGestureDetector = LongPressGestureDetector::New();
648 mImpl->mLongPressGestureDetector.DetectedSignal().Connect(mImpl, &Impl::LongPressDetected);
649 mImpl->mLongPressGestureDetector.Attach(Self());
653 void Control::DisableGestureDetection(Gesture::Type type)
655 if ( (type & Gesture::Pinch) && mImpl->mPinchGestureDetector )
657 mImpl->mPinchGestureDetector.Detach(Self());
658 mImpl->mPinchGestureDetector.Reset();
661 if ( (type & Gesture::Pan) && mImpl->mPanGestureDetector )
663 mImpl->mPanGestureDetector.Detach(Self());
664 mImpl->mPanGestureDetector.Reset();
667 if ( (type & Gesture::Tap) && mImpl->mTapGestureDetector )
669 mImpl->mTapGestureDetector.Detach(Self());
670 mImpl->mTapGestureDetector.Reset();
673 if ( (type & Gesture::LongPress) && mImpl->mLongPressGestureDetector)
675 mImpl->mLongPressGestureDetector.Detach(Self());
676 mImpl->mLongPressGestureDetector.Reset();
680 PinchGestureDetector Control::GetPinchGestureDetector() const
682 return mImpl->mPinchGestureDetector;
685 PanGestureDetector Control::GetPanGestureDetector() const
687 return mImpl->mPanGestureDetector;
690 TapGestureDetector Control::GetTapGestureDetector() const
692 return mImpl->mTapGestureDetector;
695 LongPressGestureDetector Control::GetLongPressGestureDetector() const
697 return mImpl->mLongPressGestureDetector;
700 void Control::SetBackgroundColor( const Vector4& color )
702 Background& background( mImpl->GetBackground() );
704 if ( background.actor )
706 // Just set the actor color
707 background.actor.SetColor( color );
712 MeshActor meshActor = MeshActor::New( CreateMesh() );
714 meshActor.SetAffectedByLighting( false );
715 SetupBackgroundActor( meshActor, Actor::SCALE, color );
717 // Set the background actor before adding so that we do not inform deriving classes
718 background.actor = meshActor;
719 Self().Add( meshActor );
722 background.color = color;
725 Vector4 Control::GetBackgroundColor() const
727 if ( mImpl->mBackground )
729 return mImpl->mBackground->color;
731 return Color::TRANSPARENT;
734 void Control::SetBackground( Image image )
736 Background& background( mImpl->GetBackground() );
738 if ( background.actor )
740 // Remove Current actor, unset AFTER removal so that we do not inform deriving classes
741 Self().Remove( background.actor );
742 background.actor = NULL;
745 ImageActor imageActor = ImageActor::New( image );
746 SetupBackgroundActor( imageActor, Actor::SIZE, background.color );
748 // Set the background actor before adding so that we do not inform derived classes
749 background.actor = imageActor;
750 Self().Add( imageActor );
753 void Control::ClearBackground()
755 if ( mImpl->mBackground )
757 Background& background( mImpl->GetBackground() );
758 Self().Remove( background.actor );
760 delete mImpl->mBackground;
761 mImpl->mBackground = NULL;
765 Actor Control::GetBackgroundActor() const
767 if ( mImpl->mBackground )
769 return mImpl->mBackground->actor;
775 void Control::OnThemeChange( Toolkit::StyleManager styleManager )
777 GetImpl( styleManager ).ApplyThemeStyle( GetOwner() );
780 void Control::OnPinch(PinchGesture pinch)
782 if( !( mImpl->mStartingPinchScale ) )
785 mImpl->mStartingPinchScale = new Vector3;
788 if( pinch.state == Gesture::Started )
790 *( mImpl->mStartingPinchScale ) = Self().GetCurrentScale();
793 Self().SetScale( *( mImpl->mStartingPinchScale ) * pinch.scale );
796 void Control::OnStageConnection()
800 // Notify derived classes.
801 OnControlStageConnection();
804 void Control::OnStageDisconnection()
806 // Notify derived classes
807 OnControlStageDisconnection();
810 void Control::OnChildAdd(Actor& child)
812 // If this is the background actor, then we do not want to relayout or inform deriving classes
813 if ( mImpl->mBackground && ( child == mImpl->mBackground->actor ) )
818 // Request for relayout as we may need to position the new child and old ones
821 // Notify derived classes.
822 OnControlChildAdd( child );
825 void Control::OnChildRemove(Actor& child)
827 // If this is the background actor, then we do not want to relayout or inform deriving classes
828 if ( mImpl->mBackground && ( child == mImpl->mBackground->actor ) )
833 // Request for relayout as we may need to re-position the old child
836 // Notify derived classes.
837 OnControlChildRemove( child );
840 void Control::OnSizeSet(const Vector3& targetSize)
842 if( ( !mImpl->mInsideRelayout ) && ( targetSize != mImpl->mNaturalSize ) )
844 // Only updates size if set through Actor's API
845 mImpl->mNaturalSize = targetSize;
848 if( targetSize != mImpl->mCurrentSize )
850 // Update control size.
851 mImpl->mCurrentSize = targetSize;
853 // Notify derived classes.
854 OnControlSizeSet( targetSize );
858 void Control::OnSizeAnimation(Animation& animation, const Vector3& targetSize)
860 // @todo consider animating negotiated child sizes to target size
863 bool Control::OnTouchEvent(const TouchEvent& event)
865 return false; // Do not consume
868 bool Control::OnKeyEvent(const KeyEvent& event)
870 return false; // Do not consume
873 bool Control::OnMouseWheelEvent(const MouseWheelEvent& event)
875 return false; // Do not consume
878 void Control::OnKeyInputFocusGained()
883 void Control::OnKeyInputFocusLost()
888 Actor Control::GetChildByAlias(const std::string& actorAlias)
893 bool Control::OnAccessibilityPan(PanGesture gesture)
895 return false; // Accessibility pan gesture is not handled by default
898 bool Control::OnAccessibilityTouch(const TouchEvent& touchEvent)
900 return false; // Accessibility touch event is not handled by default
903 bool Control::OnAccessibilityValueChange(bool isIncrease)
905 return false; // Accessibility value change action is not handled by default
909 void Control::SetKeyboardNavigationSupport(bool isSupported)
911 mImpl->mIsKeyboardNavigationSupported = isSupported;
914 bool Control::IsKeyboardNavigationSupported()
916 return mImpl->mIsKeyboardNavigationSupported;
919 void Control::SetAsKeyboardFocusGroup(bool isFocusGroup)
921 mImpl->mIsKeyboardFocusGroup = isFocusGroup;
923 // The following line will be removed when the deprecated API in KeyboardFocusManager is deleted
924 Toolkit::KeyboardFocusManager::Get().SetAsFocusGroup(Self(), isFocusGroup);
927 bool Control::IsKeyboardFocusGroup()
929 return Toolkit::KeyboardFocusManager::Get().IsFocusGroup(Self());
932 Actor Control::GetNextKeyboardFocusableActor(Actor currentFocusedActor, Toolkit::Control::KeyboardFocusNavigationDirection direction, bool loopEnabled)
937 bool Control::DoAction(BaseObject* object, const std::string& actionName, const std::vector<Property::Value>& attributes)
941 if( object && (actionName == Toolkit::Control::ACTION_CONTROL_ACTIVATED) )
943 Toolkit::Control control = Toolkit::Control::DownCast( BaseHandle( object ) );
946 // if cast succeeds there is an implementation so no need to check
947 control.GetImplementation().OnActivated();
954 bool Control::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
956 Dali::BaseHandle handle( object );
958 bool connected( false );
959 Toolkit::Control control = Toolkit::Control::DownCast(handle);
962 Control& controlImpl( control.GetImplementation() );
965 if ( Toolkit::Control::SIGNAL_KEY_EVENT == signalName )
967 controlImpl.KeyEventSignal().Connect( tracker, functor );
969 else if( Toolkit::Control::SIGNAL_TAPPED == signalName )
971 controlImpl.EnableGestureDetection( Gesture::Tap );
972 controlImpl.GetTapGestureDetector().DetectedSignal().Connect( tracker, functor );
974 else if( Toolkit::Control::SIGNAL_PANNED == signalName )
976 controlImpl.EnableGestureDetection( Gesture::Pan );
977 controlImpl.GetPanGestureDetector().DetectedSignal().Connect( tracker, functor );
979 else if( Toolkit::Control::SIGNAL_PINCHED == signalName )
981 controlImpl.EnableGestureDetection( Gesture::Pinch );
982 controlImpl.GetPinchGestureDetector().DetectedSignal().Connect( tracker, functor );
984 else if( Toolkit::Control::SIGNAL_LONG_PRESSED == signalName )
986 controlImpl.EnableGestureDetection( Gesture::LongPress );
987 controlImpl.GetLongPressGestureDetector().DetectedSignal().Connect( tracker, functor );
991 // signalName does not match any signal
998 void Control::DoStyleChange( Toolkit::StyleManager styleManager, StyleChange change )
1000 if( change.themeChange )
1002 OnThemeChange( styleManager );
1004 else if( change.defaultFontChange || change.defaultFontSizeChange )
1006 OnFontChange( change.defaultFontChange, change.defaultFontSizeChange );
1010 Toolkit::Control::KeyEventSignalV2& Control::KeyEventSignal()
1012 return mImpl->mKeyEventSignalV2;
1015 void Control::SetSizePolicy( Toolkit::Control::SizePolicy widthPolicy, Toolkit::Control::SizePolicy heightPolicy )
1017 bool relayoutRequest( false );
1019 if ( ( mImpl->mWidthPolicy != widthPolicy ) || ( mImpl->mHeightPolicy != heightPolicy ) )
1021 relayoutRequest = true;
1024 mImpl->mWidthPolicy = widthPolicy;
1025 mImpl->mHeightPolicy = heightPolicy;
1027 // Ensure RelayoutRequest is called AFTER new policies have been set.
1028 if ( relayoutRequest )
1034 void Control::GetSizePolicy( Toolkit::Control::SizePolicy& widthPolicy, Toolkit::Control::SizePolicy& heightPolicy ) const
1036 widthPolicy = mImpl->mWidthPolicy;
1037 heightPolicy = mImpl->mHeightPolicy;
1040 void Control::SetMinimumSize( const Vector3& size )
1042 const Vector3& minSize = mImpl->GetMinimumSize();
1043 if ( fabsf( minSize.width - size.width ) > Math::MACHINE_EPSILON_1000 ||
1044 fabsf( minSize.height - size.height ) > Math::MACHINE_EPSILON_1000 )
1046 mImpl->SetMinimumSize( size );
1048 // Only relayout if our control is using the minimum or range policy.
1049 if ( ( mImpl->mHeightPolicy == Toolkit::Control::Minimum ) || ( mImpl->mWidthPolicy == Toolkit::Control::Minimum ) ||
1050 ( mImpl->mHeightPolicy == Toolkit::Control::Range ) || ( mImpl->mWidthPolicy == Toolkit::Control::Range ) )
1057 const Vector3& Control::GetMinimumSize() const
1059 return mImpl->GetMinimumSize();
1062 void Control::SetMaximumSize( const Vector3& size )
1064 const Vector3& maxSize = mImpl->GetMaximumSize();
1065 if ( fabsf( maxSize.width - size.width ) > Math::MACHINE_EPSILON_1000 ||
1066 fabsf( maxSize.height - size.height ) > Math::MACHINE_EPSILON_1000 )
1068 mImpl->SetMaximumSize( size );
1070 // Only relayout if our control is using the maximum or range policy.
1071 if ( ( mImpl->mHeightPolicy == Toolkit::Control::Maximum ) || ( mImpl->mWidthPolicy == Toolkit::Control::Maximum ) ||
1072 ( mImpl->mHeightPolicy == Toolkit::Control::Range ) || ( mImpl->mWidthPolicy == Toolkit::Control::Range ) )
1079 const Vector3& Control::GetMaximumSize() const
1081 return mImpl->GetMaximumSize();
1084 Vector3 Control::GetNaturalSize()
1086 // could be overridden in derived classes.
1087 return mImpl->mNaturalSize;
1090 float Control::GetHeightForWidth( float width )
1092 // could be overridden in derived classes.
1093 float height( 0.0f );
1094 if ( mImpl->mNaturalSize.width > 0.0f )
1096 height = mImpl->mNaturalSize.height * width / mImpl->mNaturalSize.width;
1101 float Control::GetWidthForHeight( float height )
1103 // could be overridden in derived classes.
1104 float width( 0.0f );
1105 if ( mImpl->mNaturalSize.height > 0.0f )
1107 width = mImpl->mNaturalSize.width * height / mImpl->mNaturalSize.height;
1112 const Vector3& Control::GetControlSize() const
1114 return mImpl->mCurrentSize;
1117 const Vector3& Control::GetSizeSet() const
1119 return mImpl->mNaturalSize;
1122 void Control::SetKeyInputFocus()
1124 if( Self().OnStage() )
1126 Toolkit::KeyInputFocusManager::Get().SetFocus(Toolkit::Control::DownCast(Self()));
1130 bool Control::HasKeyInputFocus()
1132 bool result = false;
1133 if( Self().OnStage() )
1135 result = Toolkit::KeyInputFocusManager::Get().IsKeyboardListener(Toolkit::Control::DownCast(Self()));
1140 void Control::ClearKeyInputFocus()
1142 if( Self().OnStage() )
1144 Toolkit::KeyInputFocusManager::Get().RemoveFocus(Toolkit::Control::DownCast(Self()));
1148 void Control::RelayoutRequest()
1150 // unfortunate double negative but thats to guarantee new controls get size negotiation
1151 // by default and have to "opt-out" if they dont want it
1152 if( !(mImpl->mFlags & NO_SIZE_NEGOTIATION) )
1154 Internal::RelayoutController::Request();
1158 void Control::Relayout(Vector2 size, ActorSizeContainer& container)
1160 // Avoids relayout again when OnSizeSet callback arrives.
1161 mImpl->mInsideRelayout = true;
1162 Self().SetSize( size );
1163 // @todo this really needs to be at the end of method but not sure why the scope used to be only the SetSize, needs to be cleaned up in size negotiation rework
1164 mImpl->mInsideRelayout = false;
1166 // Only relayout controls which requested to be relaid out.
1167 OnRelaidOut( size, container );
1170 void Control::Relayout( Actor actor, Vector2 size, ActorSizeContainer& container )
1174 Toolkit::Control control( Toolkit::Control::DownCast( actor ) );
1177 control.GetImplementation().NegotiateSize( size, container );
1181 container.push_back( ActorSizePair( actor, size ) );
1186 void Control::OnRelaidOut( Vector2 size, ActorSizeContainer& container )
1188 unsigned int numChildren = Self().GetChildCount();
1190 for( unsigned int i=0; i<numChildren; ++i )
1192 container.push_back( ActorSizePair( Self().GetChildAt(i), size ) );
1196 void Control::NegotiateSize( Vector2 allocatedSize, ActorSizeContainer& container )
1200 if ( mImpl->mWidthPolicy == Toolkit::Control::Fixed )
1202 if ( mImpl->mHeightPolicy == Toolkit::Control::Fixed )
1204 // If a control says it has a fixed size, then use the size set by the application / control.
1205 Vector2 setSize( mImpl->mNaturalSize );
1206 if ( setSize != Vector2::ZERO )
1210 // Policy is set to Fixed, so if the application / control has not set one of the dimensions,
1211 // then we should use the natural size of the control rather than the full allocation.
1212 if ( EqualsZero( size.width ) )
1214 size.width = GetWidthForHeight( size.height );
1216 else if ( EqualsZero( size.height ) )
1218 size.height = GetHeightForWidth( size.width );
1223 // If that is not set then set the size to the control's natural size
1224 size = Vector2( GetNaturalSize() );
1229 // Width is fixed so if the application / control has set it, then use that.
1230 if ( !EqualsZero( mImpl->mNaturalSize.width ) )
1232 size.width = mImpl->mNaturalSize.width;
1236 // Otherwise, set the width to what has been allocated.
1237 size.width = allocatedSize.width;
1240 // Height is flexible so ask control what the height should be for our width.
1241 size.height = GetHeightForWidth( size.width );
1243 // Ensure height is within our policy rules
1244 size.height = Calculate( mImpl->mHeightPolicy, GetMinimumSize().height, GetMaximumSize().height, size.height );
1249 if ( mImpl->mHeightPolicy == Toolkit::Control::Fixed )
1251 // Height is fixed so if the application / control has set it, then use that.
1252 if ( !EqualsZero( mImpl->mNaturalSize.height ) )
1254 size.height = mImpl->mNaturalSize.height;
1258 // Otherwise, set the height to what has been allocated.
1259 size.height = allocatedSize.height;
1262 // Width is flexible so ask control what the width should be for our height.
1263 size.width = GetWidthForHeight( size.height );
1265 // Ensure width is within our policy rules
1266 size.width = Calculate( mImpl->mWidthPolicy, mImpl->GetMinimumSize().width, mImpl->GetMaximumSize().width, size.width );
1270 // Width and height are BOTH flexible.
1271 // Calculate the width and height using the policy rules.
1272 size.width = Calculate( mImpl->mWidthPolicy, mImpl->GetMinimumSize().width, mImpl->GetMaximumSize().width, allocatedSize.width );
1273 size.height = Calculate( mImpl->mHeightPolicy, mImpl->GetMinimumSize().height, mImpl->GetMaximumSize().height, allocatedSize.height );
1277 // If the width has not been set, then set to the allocated width.
1278 // Also if the width set is greater than the allocated, then set to allocated (no exceed support).
1279 if ( EqualsZero( size.width ) || ( size.width > allocatedSize.width ) )
1281 size.width = allocatedSize.width;
1284 // If the height has not been set, then set to the allocated height.
1285 // Also if the height set is greater than the allocated, then set to allocated (no exceed support).
1286 if ( EqualsZero( size.height ) || ( size.height > allocatedSize.height ) )
1288 size.height = allocatedSize.height;
1291 DALI_LOG_INFO( gLogFilter, Debug::Verbose,
1292 "%p: Natural: [%.2f, %.2f] Allocated: [%.2f, %.2f] Set: [%.2f, %.2f]\n",
1293 Self().GetObjectPtr(),
1294 GetNaturalSize().x, GetNaturalSize().y,
1295 allocatedSize.x, allocatedSize.y,
1298 Relayout( size, container );
1301 bool Control::EmitKeyEventSignal( const KeyEvent& event )
1303 // Guard against destruction during signal emission
1304 Dali::Toolkit::Control handle( GetOwner() );
1306 bool consumed = false;
1308 // signals are allocated dynamically when someone connects
1309 if ( !mImpl->mKeyEventSignalV2.Empty() )
1311 consumed = mImpl->mKeyEventSignalV2.Emit( handle, event );
1316 // Notification for derived classes
1317 consumed = OnKeyEvent(event);
1323 void Control::SignalConnected( SlotObserver* slotObserver, CallbackBase* callback )
1325 mImpl->SignalConnected( slotObserver, callback );
1328 void Control::SignalDisconnected( SlotObserver* slotObserver, CallbackBase* callback )
1330 mImpl->SignalDisconnected( slotObserver, callback );
1333 Control::Control( ControlBehaviour behaviourFlags )
1334 : CustomActorImpl( behaviourFlags & REQUIRES_TOUCH_EVENTS ),
1335 mImpl(new Impl(*this))
1337 mImpl->mFlags = behaviourFlags;
1340 } // namespace Internal
1342 } // namespace Toolkit