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.SetColorMode( USE_OWN_MULTIPLY_PARENT_COLOR );
210 actor.SetZ( BACKGROUND_ACTOR_Z_POSITION );
212 Constraint constraint = Constraint::New<Vector3>( constrainingIndex,
213 ParentSource( Actor::SIZE ),
214 EqualToConstraint() );
215 actor.ApplyConstraint( constraint );
218 } // unnamed namespace
223 class Control::Impl : public ConnectionTracker
228 * Size indices for mMinMaxSize array
237 // Construction & Destruction
238 Impl(Control& controlImpl)
239 : mControlImpl( controlImpl ),
241 mStartingPinchScale( NULL ),
243 mPinchGestureDetector(),
244 mPanGestureDetector(),
245 mTapGestureDetector(),
246 mLongPressGestureDetector(),
249 mWidthPolicy( Toolkit::Control::Fixed ),
250 mHeightPolicy( Toolkit::Control::Fixed ),
251 mFlags( Control::CONTROL_BEHAVIOUR_NONE ),
252 mInsideRelayout( false ),
253 mIsKeyboardNavigationSupported( false ),
254 mIsKeyboardFocusGroup( false ),
255 mInitialized( false )
261 // All gesture detectors will be destroyed so no need to disconnect.
263 delete mStartingPinchScale;
266 // Gesture Detection Methods
268 void PinchDetected(Actor actor, PinchGesture pinch)
270 mControlImpl.OnPinch(pinch);
273 void PanDetected(Actor actor, PanGesture pan)
275 mControlImpl.OnPan(pan);
278 void TapDetected(Actor actor, TapGesture tap)
280 mControlImpl.OnTap(tap);
283 void LongPressDetected(Actor actor, LongPressGesture longPress)
285 mControlImpl.OnLongPress(longPress);
288 // Background Methods
291 * Only creates an instance of the background if we actually use it.
292 * @return A reference to the Background structure.
294 Background& GetBackground()
298 mBackground = new Background;
306 * Called when a property of an object of this type is set.
307 * @param[in] object The object whose property is set.
308 * @param[in] index The property index.
309 * @param[in] value The new property value.
311 static void SetProperty( BaseObject* object, Property::Index index, const Property::Value& value )
313 Toolkit::Control control = Toolkit::Control::DownCast( BaseHandle( object ) );
317 Control& controlImpl( control.GetImplementation() );
321 case Toolkit::Control::PROPERTY_BACKGROUND_COLOR:
323 controlImpl.SetBackgroundColor( value.Get< Vector4 >() );
327 case Toolkit::Control::PROPERTY_BACKGROUND:
329 if ( value.HasKey( "image" ) )
331 Property::Map imageMap = value.GetValue( "image" ).Get< Property::Map >();
332 Image image = Scripting::NewImage( imageMap );
336 controlImpl.SetBackground( image );
339 else if ( value.Get< Property::Map >().Empty() )
341 // An empty map means the background is no longer required
342 controlImpl.ClearBackground();
347 case Toolkit::Control::PROPERTY_WIDTH_POLICY:
349 controlImpl.mImpl->mWidthPolicy = Scripting::GetEnumeration< Toolkit::Control::SizePolicy >( value.Get< std::string >(), SIZE_POLICY_STRING_TABLE, SIZE_POLICY_STRING_TABLE_COUNT );
353 case Toolkit::Control::PROPERTY_HEIGHT_POLICY:
355 controlImpl.mImpl->mHeightPolicy = Scripting::GetEnumeration< Toolkit::Control::SizePolicy >( value.Get< std::string >(), SIZE_POLICY_STRING_TABLE, SIZE_POLICY_STRING_TABLE_COUNT );
359 case Toolkit::Control::PROPERTY_MINIMUM_SIZE:
361 controlImpl.SetMinimumSize( value.Get< Vector3 >() );
365 case Toolkit::Control::PROPERTY_MAXIMUM_SIZE:
367 controlImpl.SetMaximumSize( value.Get< Vector3 >() );
371 case Toolkit::Control::PROPERTY_KEY_INPUT_FOCUS:
373 if ( value.Get< bool >() )
375 controlImpl.SetKeyInputFocus();
379 controlImpl.ClearKeyInputFocus();
388 * Called to retrieve a property of an object of this type.
389 * @param[in] object The object whose property is to be retrieved.
390 * @param[in] index The property index.
391 * @return The current value of the property.
393 static Property::Value GetProperty( BaseObject* object, Property::Index index )
395 Property::Value value;
397 Toolkit::Control control = Toolkit::Control::DownCast( BaseHandle( object ) );
401 Control& controlImpl( control.GetImplementation() );
405 case Toolkit::Control::PROPERTY_BACKGROUND_COLOR:
407 value = controlImpl.GetBackgroundColor();
411 case Toolkit::Control::PROPERTY_BACKGROUND:
415 Actor actor = controlImpl.GetBackgroundActor();
418 ImageActor imageActor = ImageActor::DownCast( actor );
421 Image image = imageActor.GetImage();
422 Property::Map imageMap;
423 Scripting::CreatePropertyMap( image, imageMap );
424 map[ "image" ] = imageMap;
432 case Toolkit::Control::PROPERTY_WIDTH_POLICY:
434 value = std::string( Scripting::GetEnumerationName< Toolkit::Control::SizePolicy >( controlImpl.mImpl->mWidthPolicy, SIZE_POLICY_STRING_TABLE, SIZE_POLICY_STRING_TABLE_COUNT ) );
438 case Toolkit::Control::PROPERTY_HEIGHT_POLICY:
440 value = std::string( Scripting::GetEnumerationName< Toolkit::Control::SizePolicy >( controlImpl.mImpl->mHeightPolicy, SIZE_POLICY_STRING_TABLE, SIZE_POLICY_STRING_TABLE_COUNT ) );
444 case Toolkit::Control::PROPERTY_MINIMUM_SIZE:
446 value = controlImpl.mImpl->GetMinimumSize();
450 case Toolkit::Control::PROPERTY_MAXIMUM_SIZE:
452 value = controlImpl.mImpl->GetMaximumSize();
456 case Toolkit::Control::PROPERTY_KEY_INPUT_FOCUS:
458 value = controlImpl.HasKeyInputFocus();
468 * Helper to get minimum size
469 * @return minimum size
471 inline const Vector3& GetMinimumSize()
473 if( mMinMaxSize.Count() > MIN_SIZE_INDEX )
475 return mMinMaxSize[ MIN_SIZE_INDEX ];
479 // its not been allocated so its ZERO
480 return Vector3::ZERO;
484 * Helper to Set minimum size
487 inline void SetMinimumSize( const Vector3& size )
489 if( mMinMaxSize.Count() > MIN_SIZE_INDEX )
491 mMinMaxSize[ MIN_SIZE_INDEX ] = size;
495 // its not been allocated so push the new value there
496 mMinMaxSize.PushBack( size );
501 * Helper to get maximum size
502 * @return maximum size
504 inline const Vector3& GetMaximumSize()
506 if( mMinMaxSize.Count() > MAX_SIZE_INDEX )
508 return mMinMaxSize[ MAX_SIZE_INDEX ];
512 // its not been allocated so its MAX_SIZE
518 * Helper to Set minimum size
521 inline void SetMaximumSize( const Vector3& size )
523 if( mMinMaxSize.Count() > MAX_SIZE_INDEX )
525 mMinMaxSize[ MAX_SIZE_INDEX ] = size;
527 else if( mMinMaxSize.Count() > MIN_SIZE_INDEX )
529 // max has not been allocated, but min has
530 mMinMaxSize.PushBack( size );
534 // min and max both unallocated so allocate both
535 mMinMaxSize.Resize( 2u ); // this will reserve and default construct two Vector3s
536 mMinMaxSize[ MAX_SIZE_INDEX ] = size;
542 Control& mControlImpl;
543 Background* mBackground; ///< Only create the background if we use it
544 Vector3* mStartingPinchScale; ///< The scale when a pinch gesture starts, TODO: consider removing this
545 Toolkit::Control::KeyEventSignalV2 mKeyEventSignalV2;
548 PinchGestureDetector mPinchGestureDetector;
549 PanGestureDetector mPanGestureDetector;
550 TapGestureDetector mTapGestureDetector;
551 LongPressGestureDetector mLongPressGestureDetector;
552 // @todo change all these to Vector2 when we have a chance to sanitize the public API as well
553 Vector3 mCurrentSize; ///< Stores the current control's size, this is the negotiated size
554 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.
555 Dali::Vector< Vector3 > mMinMaxSize; ///< Stores the minimum and maximum size if they are set
557 Toolkit::Control::SizePolicy mWidthPolicy :3; ///< Stores the width policy. 3 bits covers 8 values
558 Toolkit::Control::SizePolicy mHeightPolicy :3; ///< Stores the height policy. 3 bits covers 8 values
559 ControlBehaviour mFlags :6; ///< Flags passed in from constructor. Need to increase this size when new enums are added
560 bool mInsideRelayout:1; ///< Detect when were in Relayout
561 bool mIsKeyboardNavigationSupported:1; ///< Stores whether keyboard navigation is supported by the control.
562 bool mIsKeyboardFocusGroup:1; ///< Stores whether the control is a focus group.
565 // Properties - these need to be members of Internal::Control::Impl as they need to functions within this class.
566 static PropertyRegistration PROPERTY_1;
567 static PropertyRegistration PROPERTY_2;
568 static PropertyRegistration PROPERTY_3;
569 static PropertyRegistration PROPERTY_4;
570 static PropertyRegistration PROPERTY_5;
571 static PropertyRegistration PROPERTY_6;
572 static PropertyRegistration PROPERTY_7;
575 PropertyRegistration Control::Impl::PROPERTY_1( CONTROL_TYPE, "background-color", Toolkit::Control::PROPERTY_BACKGROUND_COLOR, Property::VECTOR4, &Control::Impl::SetProperty, &Control::Impl::GetProperty );
576 PropertyRegistration Control::Impl::PROPERTY_2( CONTROL_TYPE, "background", Toolkit::Control::PROPERTY_BACKGROUND, Property::MAP, &Control::Impl::SetProperty, &Control::Impl::GetProperty );
577 PropertyRegistration Control::Impl::PROPERTY_3( CONTROL_TYPE, "width-policy", Toolkit::Control::PROPERTY_WIDTH_POLICY, Property::STRING, &Control::Impl::SetProperty, &Control::Impl::GetProperty );
578 PropertyRegistration Control::Impl::PROPERTY_4( CONTROL_TYPE, "height-policy", Toolkit::Control::PROPERTY_HEIGHT_POLICY, Property::STRING, &Control::Impl::SetProperty, &Control::Impl::GetProperty );
579 PropertyRegistration Control::Impl::PROPERTY_5( CONTROL_TYPE, "minimum-size", Toolkit::Control::PROPERTY_MINIMUM_SIZE, Property::VECTOR3, &Control::Impl::SetProperty, &Control::Impl::GetProperty );
580 PropertyRegistration Control::Impl::PROPERTY_6( CONTROL_TYPE, "maximum-size", Toolkit::Control::PROPERTY_MAXIMUM_SIZE, Property::VECTOR3, &Control::Impl::SetProperty, &Control::Impl::GetProperty );
581 PropertyRegistration Control::Impl::PROPERTY_7( CONTROL_TYPE, "key-input-focus", Toolkit::Control::PROPERTY_KEY_INPUT_FOCUS, Property::BOOLEAN, &Control::Impl::SetProperty, &Control::Impl::GetProperty );
583 Toolkit::Control Control::New()
585 // Create the implementation, temporarily owned on stack
586 IntrusivePtr<Control> controlImpl = new Control( CONTROL_BEHAVIOUR_NONE );
588 // Pass ownership to handle
589 Toolkit::Control handle( *controlImpl );
591 // Second-phase init of the implementation
592 // This can only be done after the CustomActor connection has been made...
593 controlImpl->Initialize();
603 void Control::Initialize()
606 // Calling deriving classes
609 if( mImpl->mFlags & REQUIRES_STYLE_CHANGE_SIGNALS )
611 Toolkit::StyleManager styleManager = Toolkit::StyleManager::Get();
613 // Register for style changes
614 styleManager.StyleChangeSignal().Connect( this, &Control::DoStyleChange );
617 GetImpl( styleManager ).ApplyThemeStyle( GetOwner() );
620 SetRequiresHoverEvents(mImpl->mFlags & REQUIRES_HOVER_EVENTS);
621 SetRequiresMouseWheelEvents(mImpl->mFlags & REQUIRES_MOUSE_WHEEL_EVENTS);
623 mImpl->mInitialized = true;
626 void Control::EnableGestureDetection(Gesture::Type type)
628 if ( (type & Gesture::Pinch) && !mImpl->mPinchGestureDetector )
630 mImpl->mPinchGestureDetector = PinchGestureDetector::New();
631 mImpl->mPinchGestureDetector.DetectedSignal().Connect(mImpl, &Impl::PinchDetected);
632 mImpl->mPinchGestureDetector.Attach(Self());
635 if ( (type & Gesture::Pan) && !mImpl->mPanGestureDetector )
637 mImpl->mPanGestureDetector = PanGestureDetector::New();
638 mImpl->mPanGestureDetector.DetectedSignal().Connect(mImpl, &Impl::PanDetected);
639 mImpl->mPanGestureDetector.Attach(Self());
642 if ( (type & Gesture::Tap) && !mImpl->mTapGestureDetector )
644 mImpl->mTapGestureDetector = TapGestureDetector::New();
645 mImpl->mTapGestureDetector.DetectedSignal().Connect(mImpl, &Impl::TapDetected);
646 mImpl->mTapGestureDetector.Attach(Self());
649 if ( (type & Gesture::LongPress) && !mImpl->mLongPressGestureDetector )
651 mImpl->mLongPressGestureDetector = LongPressGestureDetector::New();
652 mImpl->mLongPressGestureDetector.DetectedSignal().Connect(mImpl, &Impl::LongPressDetected);
653 mImpl->mLongPressGestureDetector.Attach(Self());
657 void Control::DisableGestureDetection(Gesture::Type type)
659 if ( (type & Gesture::Pinch) && mImpl->mPinchGestureDetector )
661 mImpl->mPinchGestureDetector.Detach(Self());
662 mImpl->mPinchGestureDetector.Reset();
665 if ( (type & Gesture::Pan) && mImpl->mPanGestureDetector )
667 mImpl->mPanGestureDetector.Detach(Self());
668 mImpl->mPanGestureDetector.Reset();
671 if ( (type & Gesture::Tap) && mImpl->mTapGestureDetector )
673 mImpl->mTapGestureDetector.Detach(Self());
674 mImpl->mTapGestureDetector.Reset();
677 if ( (type & Gesture::LongPress) && mImpl->mLongPressGestureDetector)
679 mImpl->mLongPressGestureDetector.Detach(Self());
680 mImpl->mLongPressGestureDetector.Reset();
684 PinchGestureDetector Control::GetPinchGestureDetector() const
686 return mImpl->mPinchGestureDetector;
689 PanGestureDetector Control::GetPanGestureDetector() const
691 return mImpl->mPanGestureDetector;
694 TapGestureDetector Control::GetTapGestureDetector() const
696 return mImpl->mTapGestureDetector;
699 LongPressGestureDetector Control::GetLongPressGestureDetector() const
701 return mImpl->mLongPressGestureDetector;
704 void Control::SetBackgroundColor( const Vector4& color )
706 Background& background( mImpl->GetBackground() );
708 if ( background.actor )
710 // Just set the actor color
711 background.actor.SetColor( color );
716 MeshActor meshActor = MeshActor::New( CreateMesh() );
718 meshActor.SetAffectedByLighting( false );
719 SetupBackgroundActor( meshActor, Actor::SCALE, color );
721 // Set the background actor before adding so that we do not inform deriving classes
722 background.actor = meshActor;
723 Self().Add( meshActor );
726 background.color = color;
729 Vector4 Control::GetBackgroundColor() const
731 if ( mImpl->mBackground )
733 return mImpl->mBackground->color;
735 return Color::TRANSPARENT;
738 void Control::SetBackground( Image image )
740 Background& background( mImpl->GetBackground() );
742 if ( background.actor )
744 // Remove Current actor, unset AFTER removal so that we do not inform deriving classes
745 Self().Remove( background.actor );
746 background.actor = NULL;
749 ImageActor imageActor = ImageActor::New( image );
750 SetupBackgroundActor( imageActor, Actor::SIZE, background.color );
752 // Set the background actor before adding so that we do not inform derived classes
753 background.actor = imageActor;
754 Self().Add( imageActor );
757 void Control::ClearBackground()
759 if ( mImpl->mBackground )
761 Background& background( mImpl->GetBackground() );
762 Self().Remove( background.actor );
764 delete mImpl->mBackground;
765 mImpl->mBackground = NULL;
769 Actor Control::GetBackgroundActor() const
771 if ( mImpl->mBackground )
773 return mImpl->mBackground->actor;
779 void Control::OnThemeChange( Toolkit::StyleManager styleManager )
781 GetImpl( styleManager ).ApplyThemeStyle( GetOwner() );
784 void Control::OnPinch(PinchGesture pinch)
786 if( !( mImpl->mStartingPinchScale ) )
789 mImpl->mStartingPinchScale = new Vector3;
792 if( pinch.state == Gesture::Started )
794 *( mImpl->mStartingPinchScale ) = Self().GetCurrentScale();
797 Self().SetScale( *( mImpl->mStartingPinchScale ) * pinch.scale );
800 void Control::OnStageConnection()
804 // Notify derived classes.
805 OnControlStageConnection();
808 void Control::OnStageDisconnection()
810 // Notify derived classes
811 OnControlStageDisconnection();
814 void Control::OnChildAdd(Actor& child)
816 // If this is the background actor, then we do not want to relayout or inform deriving classes
817 if ( mImpl->mBackground && ( child == mImpl->mBackground->actor ) )
822 // Request for relayout as we may need to position the new child and old ones
825 // Notify derived classes.
826 OnControlChildAdd( child );
829 void Control::OnChildRemove(Actor& child)
831 // If this is the background actor, then we do not want to relayout or inform deriving classes
832 if ( mImpl->mBackground && ( child == mImpl->mBackground->actor ) )
837 // Request for relayout as we may need to re-position the old child
840 // Notify derived classes.
841 OnControlChildRemove( child );
844 void Control::OnSizeSet(const Vector3& targetSize)
846 if( ( !mImpl->mInsideRelayout ) && ( targetSize != mImpl->mNaturalSize ) )
848 // Only updates size if set through Actor's API
849 mImpl->mNaturalSize = targetSize;
852 if( targetSize != mImpl->mCurrentSize )
854 // Update control size.
855 mImpl->mCurrentSize = targetSize;
857 // Notify derived classes.
858 OnControlSizeSet( targetSize );
862 void Control::OnSizeAnimation(Animation& animation, const Vector3& targetSize)
864 // @todo consider animating negotiated child sizes to target size
867 bool Control::OnTouchEvent(const TouchEvent& event)
869 return false; // Do not consume
872 bool Control::OnHoverEvent(const HoverEvent& event)
874 return false; // Do not consume
877 bool Control::OnKeyEvent(const KeyEvent& event)
879 return false; // Do not consume
882 bool Control::OnMouseWheelEvent(const MouseWheelEvent& event)
884 return false; // Do not consume
887 void Control::OnKeyInputFocusGained()
892 void Control::OnKeyInputFocusLost()
897 Actor Control::GetChildByAlias(const std::string& actorAlias)
902 bool Control::OnAccessibilityPan(PanGesture gesture)
904 return false; // Accessibility pan gesture is not handled by default
907 bool Control::OnAccessibilityTouch(const TouchEvent& touchEvent)
909 return false; // Accessibility touch event is not handled by default
912 bool Control::OnAccessibilityValueChange(bool isIncrease)
914 return false; // Accessibility value change action is not handled by default
918 void Control::SetKeyboardNavigationSupport(bool isSupported)
920 mImpl->mIsKeyboardNavigationSupported = isSupported;
923 bool Control::IsKeyboardNavigationSupported()
925 return mImpl->mIsKeyboardNavigationSupported;
928 void Control::SetAsKeyboardFocusGroup(bool isFocusGroup)
930 mImpl->mIsKeyboardFocusGroup = isFocusGroup;
932 // The following line will be removed when the deprecated API in KeyboardFocusManager is deleted
933 Toolkit::KeyboardFocusManager::Get().SetAsFocusGroup(Self(), isFocusGroup);
936 bool Control::IsKeyboardFocusGroup()
938 return Toolkit::KeyboardFocusManager::Get().IsFocusGroup(Self());
941 Actor Control::GetNextKeyboardFocusableActor(Actor currentFocusedActor, Toolkit::Control::KeyboardFocusNavigationDirection direction, bool loopEnabled)
946 bool Control::DoAction(BaseObject* object, const std::string& actionName, const std::vector<Property::Value>& attributes)
950 if( object && (actionName == Toolkit::Control::ACTION_CONTROL_ACTIVATED) )
952 Toolkit::Control control = Toolkit::Control::DownCast( BaseHandle( object ) );
955 // if cast succeeds there is an implementation so no need to check
956 control.GetImplementation().OnActivated();
963 bool Control::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
965 Dali::BaseHandle handle( object );
967 bool connected( false );
968 Toolkit::Control control = Toolkit::Control::DownCast(handle);
971 Control& controlImpl( control.GetImplementation() );
974 if ( Toolkit::Control::SIGNAL_KEY_EVENT == signalName )
976 controlImpl.KeyEventSignal().Connect( tracker, functor );
978 else if( Toolkit::Control::SIGNAL_TAPPED == signalName )
980 controlImpl.EnableGestureDetection( Gesture::Tap );
981 controlImpl.GetTapGestureDetector().DetectedSignal().Connect( tracker, functor );
983 else if( Toolkit::Control::SIGNAL_PANNED == signalName )
985 controlImpl.EnableGestureDetection( Gesture::Pan );
986 controlImpl.GetPanGestureDetector().DetectedSignal().Connect( tracker, functor );
988 else if( Toolkit::Control::SIGNAL_PINCHED == signalName )
990 controlImpl.EnableGestureDetection( Gesture::Pinch );
991 controlImpl.GetPinchGestureDetector().DetectedSignal().Connect( tracker, functor );
993 else if( Toolkit::Control::SIGNAL_LONG_PRESSED == signalName )
995 controlImpl.EnableGestureDetection( Gesture::LongPress );
996 controlImpl.GetLongPressGestureDetector().DetectedSignal().Connect( tracker, functor );
1000 // signalName does not match any signal
1007 void Control::DoStyleChange( Toolkit::StyleManager styleManager, StyleChange change )
1009 if( change.themeChange )
1011 OnThemeChange( styleManager );
1013 else if( change.defaultFontChange || change.defaultFontSizeChange )
1015 OnFontChange( change.defaultFontChange, change.defaultFontSizeChange );
1019 Toolkit::Control::KeyEventSignalV2& Control::KeyEventSignal()
1021 return mImpl->mKeyEventSignalV2;
1024 void Control::SetSizePolicy( Toolkit::Control::SizePolicy widthPolicy, Toolkit::Control::SizePolicy heightPolicy )
1026 bool relayoutRequest( false );
1028 if ( ( mImpl->mWidthPolicy != widthPolicy ) || ( mImpl->mHeightPolicy != heightPolicy ) )
1030 relayoutRequest = true;
1033 mImpl->mWidthPolicy = widthPolicy;
1034 mImpl->mHeightPolicy = heightPolicy;
1036 // Ensure RelayoutRequest is called AFTER new policies have been set.
1037 if ( relayoutRequest )
1043 void Control::GetSizePolicy( Toolkit::Control::SizePolicy& widthPolicy, Toolkit::Control::SizePolicy& heightPolicy ) const
1045 widthPolicy = mImpl->mWidthPolicy;
1046 heightPolicy = mImpl->mHeightPolicy;
1049 void Control::SetMinimumSize( const Vector3& size )
1051 const Vector3& minSize = mImpl->GetMinimumSize();
1052 if ( fabsf( minSize.width - size.width ) > Math::MACHINE_EPSILON_1000 ||
1053 fabsf( minSize.height - size.height ) > Math::MACHINE_EPSILON_1000 )
1055 mImpl->SetMinimumSize( size );
1057 // Only relayout if our control is using the minimum or range policy.
1058 if ( ( mImpl->mHeightPolicy == Toolkit::Control::Minimum ) || ( mImpl->mWidthPolicy == Toolkit::Control::Minimum ) ||
1059 ( mImpl->mHeightPolicy == Toolkit::Control::Range ) || ( mImpl->mWidthPolicy == Toolkit::Control::Range ) )
1066 const Vector3& Control::GetMinimumSize() const
1068 return mImpl->GetMinimumSize();
1071 void Control::SetMaximumSize( const Vector3& size )
1073 const Vector3& maxSize = mImpl->GetMaximumSize();
1074 if ( fabsf( maxSize.width - size.width ) > Math::MACHINE_EPSILON_1000 ||
1075 fabsf( maxSize.height - size.height ) > Math::MACHINE_EPSILON_1000 )
1077 mImpl->SetMaximumSize( size );
1079 // Only relayout if our control is using the maximum or range policy.
1080 if ( ( mImpl->mHeightPolicy == Toolkit::Control::Maximum ) || ( mImpl->mWidthPolicy == Toolkit::Control::Maximum ) ||
1081 ( mImpl->mHeightPolicy == Toolkit::Control::Range ) || ( mImpl->mWidthPolicy == Toolkit::Control::Range ) )
1088 const Vector3& Control::GetMaximumSize() const
1090 return mImpl->GetMaximumSize();
1093 Vector3 Control::GetNaturalSize()
1095 // could be overridden in derived classes.
1096 return mImpl->mNaturalSize;
1099 float Control::GetHeightForWidth( float width )
1101 // could be overridden in derived classes.
1102 float height( 0.0f );
1103 if ( mImpl->mNaturalSize.width > 0.0f )
1105 height = mImpl->mNaturalSize.height * width / mImpl->mNaturalSize.width;
1110 float Control::GetWidthForHeight( float height )
1112 // could be overridden in derived classes.
1113 float width( 0.0f );
1114 if ( mImpl->mNaturalSize.height > 0.0f )
1116 width = mImpl->mNaturalSize.width * height / mImpl->mNaturalSize.height;
1121 const Vector3& Control::GetControlSize() const
1123 return mImpl->mCurrentSize;
1126 const Vector3& Control::GetSizeSet() const
1128 return mImpl->mNaturalSize;
1131 void Control::SetKeyInputFocus()
1133 if( Self().OnStage() )
1135 Toolkit::KeyInputFocusManager::Get().SetFocus(Toolkit::Control::DownCast(Self()));
1139 bool Control::HasKeyInputFocus()
1141 bool result = false;
1142 if( Self().OnStage() )
1144 result = Toolkit::KeyInputFocusManager::Get().IsKeyboardListener(Toolkit::Control::DownCast(Self()));
1149 void Control::ClearKeyInputFocus()
1151 if( Self().OnStage() )
1153 Toolkit::KeyInputFocusManager::Get().RemoveFocus(Toolkit::Control::DownCast(Self()));
1157 void Control::RelayoutRequest()
1159 // unfortunate double negative but thats to guarantee new controls get size negotiation
1160 // by default and have to "opt-out" if they dont want it
1161 if( !(mImpl->mFlags & NO_SIZE_NEGOTIATION) )
1163 Internal::RelayoutController::Request();
1167 void Control::Relayout(Vector2 size, ActorSizeContainer& container)
1169 // Avoids relayout again when OnSizeSet callback arrives.
1170 mImpl->mInsideRelayout = true;
1171 Self().SetSize( size );
1172 // @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
1173 mImpl->mInsideRelayout = false;
1175 // Only relayout controls which requested to be relaid out.
1176 OnRelaidOut( size, container );
1179 void Control::Relayout( Actor actor, Vector2 size, ActorSizeContainer& container )
1183 Toolkit::Control control( Toolkit::Control::DownCast( actor ) );
1186 control.GetImplementation().NegotiateSize( size, container );
1190 container.push_back( ActorSizePair( actor, size ) );
1195 void Control::OnRelaidOut( Vector2 size, ActorSizeContainer& container )
1197 unsigned int numChildren = Self().GetChildCount();
1199 for( unsigned int i=0; i<numChildren; ++i )
1201 container.push_back( ActorSizePair( Self().GetChildAt(i), size ) );
1205 void Control::NegotiateSize( Vector2 allocatedSize, ActorSizeContainer& container )
1209 if ( mImpl->mWidthPolicy == Toolkit::Control::Fixed )
1211 if ( mImpl->mHeightPolicy == Toolkit::Control::Fixed )
1213 // If a control says it has a fixed size, then use the size set by the application / control.
1214 Vector2 setSize( mImpl->mNaturalSize );
1215 if ( setSize != Vector2::ZERO )
1219 // Policy is set to Fixed, so if the application / control has not set one of the dimensions,
1220 // then we should use the natural size of the control rather than the full allocation.
1221 if ( EqualsZero( size.width ) )
1223 size.width = GetWidthForHeight( size.height );
1225 else if ( EqualsZero( size.height ) )
1227 size.height = GetHeightForWidth( size.width );
1232 // If that is not set then set the size to the control's natural size
1233 size = Vector2( GetNaturalSize() );
1238 // Width is fixed so if the application / control has set it, then use that.
1239 if ( !EqualsZero( mImpl->mNaturalSize.width ) )
1241 size.width = mImpl->mNaturalSize.width;
1245 // Otherwise, set the width to what has been allocated.
1246 size.width = allocatedSize.width;
1249 // Height is flexible so ask control what the height should be for our width.
1250 size.height = GetHeightForWidth( size.width );
1252 // Ensure height is within our policy rules
1253 size.height = Calculate( mImpl->mHeightPolicy, GetMinimumSize().height, GetMaximumSize().height, size.height );
1258 if ( mImpl->mHeightPolicy == Toolkit::Control::Fixed )
1260 // Height is fixed so if the application / control has set it, then use that.
1261 if ( !EqualsZero( mImpl->mNaturalSize.height ) )
1263 size.height = mImpl->mNaturalSize.height;
1267 // Otherwise, set the height to what has been allocated.
1268 size.height = allocatedSize.height;
1271 // Width is flexible so ask control what the width should be for our height.
1272 size.width = GetWidthForHeight( size.height );
1274 // Ensure width is within our policy rules
1275 size.width = Calculate( mImpl->mWidthPolicy, mImpl->GetMinimumSize().width, mImpl->GetMaximumSize().width, size.width );
1279 // Width and height are BOTH flexible.
1280 // Calculate the width and height using the policy rules.
1281 size.width = Calculate( mImpl->mWidthPolicy, mImpl->GetMinimumSize().width, mImpl->GetMaximumSize().width, allocatedSize.width );
1282 size.height = Calculate( mImpl->mHeightPolicy, mImpl->GetMinimumSize().height, mImpl->GetMaximumSize().height, allocatedSize.height );
1286 // If the width has not been set, then set to the allocated width.
1287 // Also if the width set is greater than the allocated, then set to allocated (no exceed support).
1288 if ( EqualsZero( size.width ) || ( size.width > allocatedSize.width ) )
1290 size.width = allocatedSize.width;
1293 // If the height has not been set, then set to the allocated height.
1294 // Also if the height set is greater than the allocated, then set to allocated (no exceed support).
1295 if ( EqualsZero( size.height ) || ( size.height > allocatedSize.height ) )
1297 size.height = allocatedSize.height;
1300 DALI_LOG_INFO( gLogFilter, Debug::Verbose,
1301 "%p: Natural: [%.2f, %.2f] Allocated: [%.2f, %.2f] Set: [%.2f, %.2f]\n",
1302 Self().GetObjectPtr(),
1303 GetNaturalSize().x, GetNaturalSize().y,
1304 allocatedSize.x, allocatedSize.y,
1307 Relayout( size, container );
1310 bool Control::EmitKeyEventSignal( const KeyEvent& event )
1312 // Guard against destruction during signal emission
1313 Dali::Toolkit::Control handle( GetOwner() );
1315 bool consumed = false;
1317 // signals are allocated dynamically when someone connects
1318 if ( !mImpl->mKeyEventSignalV2.Empty() )
1320 consumed = mImpl->mKeyEventSignalV2.Emit( handle, event );
1325 // Notification for derived classes
1326 consumed = OnKeyEvent(event);
1332 void Control::SignalConnected( SlotObserver* slotObserver, CallbackBase* callback )
1334 mImpl->SignalConnected( slotObserver, callback );
1337 void Control::SignalDisconnected( SlotObserver* slotObserver, CallbackBase* callback )
1339 mImpl->SignalDisconnected( slotObserver, callback );
1342 Control::Control( ControlBehaviour behaviourFlags )
1343 : CustomActorImpl( behaviourFlags & REQUIRES_TOUCH_EVENTS ),
1344 mImpl(new Impl(*this))
1346 mImpl->mFlags = behaviourFlags;
1349 } // namespace Internal
1351 } // namespace Toolkit