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.
19 #include <dali-toolkit/public-api/controls/control-impl.h>
23 #include <dali/public-api/actors/image-actor.h>
24 #include <dali/public-api/actors/mesh-actor.h>
25 #include <dali/public-api/animation/constraints.h>
26 #include <dali/public-api/geometry/mesh.h>
27 #include <dali/public-api/object/type-registry.h>
28 #include <dali/public-api/scripting/scripting.h>
29 #include <dali/integration-api/debug.h>
31 #include <dali-toolkit/internal/controls/relayout-controller.h>
32 #include <dali-toolkit/internal/controls/relayout-helper.h>
33 #include <dali-toolkit/public-api/focus-manager/keyinput-focus-manager.h>
34 #include <dali-toolkit/public-api/focus-manager/keyboard-focus-manager.h>
35 #include <dali-toolkit/public-api/controls/control.h>
36 #include <dali-toolkit/public-api/styling/style-manager.h>
37 #include <dali-toolkit/internal/styling/style-manager-impl.h>
45 const Property::Index Control::PROPERTY_BACKGROUND_COLOR = Internal::Control::CONTROL_PROPERTY_START_INDEX;
46 const Property::Index Control::PROPERTY_BACKGROUND = Internal::Control::CONTROL_PROPERTY_START_INDEX + 1;
47 const Property::Index Control::PROPERTY_WIDTH_POLICY = Internal::Control::CONTROL_PROPERTY_START_INDEX + 2;
48 const Property::Index Control::PROPERTY_HEIGHT_POLICY = Internal::Control::CONTROL_PROPERTY_START_INDEX + 3;
49 const Property::Index Control::PROPERTY_MINIMUM_SIZE = Internal::Control::CONTROL_PROPERTY_START_INDEX + 4;
50 const Property::Index Control::PROPERTY_MAXIMUM_SIZE = Internal::Control::CONTROL_PROPERTY_START_INDEX + 5;
51 const Property::Index Control::PROPERTY_KEY_INPUT_FOCUS = Internal::Control::CONTROL_PROPERTY_START_INDEX + 6;
58 const char* const SIGNAL_KEY_EVENT = "key-event";
59 const char* const SIGNAL_TAPPED = "tapped";
60 const char* const SIGNAL_PANNED = "panned";
61 const char* const SIGNAL_PINCHED = "pinched";
62 const char* const SIGNAL_LONG_PRESSED = "long-pressed";
66 const char* const ACTION_CONTROL_ACTIVATED = "control-activated";
68 const Scripting::StringEnum< Control::SizePolicy > SIZE_POLICY_STRING_TABLE[] =
70 { "FIXED", Control::Fixed },
71 { "MINIMUM", Control::Minimum },
72 { "MAXIMUM", Control::Maximum },
73 { "RANGE", Control::Range },
74 { "FLEXIBLE", Control::Flexible },
76 const unsigned int SIZE_POLICY_STRING_TABLE_COUNT = sizeof( SIZE_POLICY_STRING_TABLE ) / sizeof( SIZE_POLICY_STRING_TABLE[0] );
78 #if defined(DEBUG_ENABLED)
79 Integration::Log::Filter* gLogFilter = Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_CONTROL");
82 const float MAX_FLOAT_VALUE( std::numeric_limits<float>::max() );
83 const Vector3 MAX_SIZE( MAX_FLOAT_VALUE, MAX_FLOAT_VALUE, MAX_FLOAT_VALUE );
84 const float BACKGROUND_ACTOR_Z_POSITION( -0.1f );
88 return Internal::Control::New();
91 TypeRegistration CONTROL_TYPE( typeid(Control), typeid(CustomActor), Create );
93 // Property Registration after Internal::Control::Impl definition below
95 TypeAction ACTION_TYPE_1( CONTROL_TYPE, ACTION_CONTROL_ACTIVATED, &Internal::Control::DoAction );
97 SignalConnectorType SIGNAL_CONNECTOR_1( CONTROL_TYPE, SIGNAL_KEY_EVENT, &Internal::Control::DoConnectSignal );
98 SignalConnectorType SIGNAL_CONNECTOR_2( CONTROL_TYPE, SIGNAL_TAPPED, &Internal::Control::DoConnectSignal );
99 SignalConnectorType SIGNAL_CONNECTOR_3( CONTROL_TYPE, SIGNAL_PANNED, &Internal::Control::DoConnectSignal );
100 SignalConnectorType SIGNAL_CONNECTOR_4( CONTROL_TYPE, SIGNAL_PINCHED, &Internal::Control::DoConnectSignal );
101 SignalConnectorType SIGNAL_CONNECTOR_5( CONTROL_TYPE, SIGNAL_LONG_PRESSED, &Internal::Control::DoConnectSignal );
104 * Structure which holds information about the background of a control
108 Actor actor; ///< Either a MeshActor or an ImageActor
109 Vector4 color; ///< The color of the actor.
116 color( Color::WHITE )
122 * Helper function to calculate a dimension given the policy of that dimension; the minimum &
123 * maximum values that dimension can be; and the allocated value for that dimension.
125 * @param[in] policy The size policy for that dimension.
126 * @param[in] minimum The minimum value that dimension can be.
127 * @param[in] maximum The maximum value that dimension can be.
128 * @param[in] allocated The value allocated for that dimension.
130 * @return The value that the dimension should be.
132 * @note This does not handle Control::Fixed policy.
134 float Calculate( Control::SizePolicy policy, float minimum, float maximum, float allocated )
136 float size( allocated );
142 // Use allocated value
146 case Control::Minimum:
148 // Size is always at least the minimum.
149 size = std::max( allocated, minimum );
153 case Control::Maximum:
155 // Size can grow but up to a maximum value.
156 size = std::min( allocated, maximum );
162 // Size is at least the minimum and can grow up to the maximum
163 size = std::max( size, minimum );
164 size = std::min( size, maximum );
168 case Control::Flexible:
170 // Size grows or shrinks with no limits.
177 DALI_ASSERT_DEBUG( false && "This function was not intended to be used by any other policy." );
186 * Creates a white coloured Mesh.
190 Vector3 white( Color::WHITE );
194 // Create vertices with a white color (actual color is set by actor color)
195 MeshData::VertexContainer vertices(4);
196 vertices[ 0 ] = MeshData::Vertex( Vector3( -0.5f, -0.5f, 0.0f ), Vector2::ZERO, white );
197 vertices[ 1 ] = MeshData::Vertex( Vector3( 0.5f, -0.5f, 0.0f ), Vector2::ZERO, white );
198 vertices[ 2 ] = MeshData::Vertex( Vector3( -0.5f, 0.5f, 0.0f ), Vector2::ZERO, white );
199 vertices[ 3 ] = MeshData::Vertex( Vector3( 0.5f, 0.5f, 0.0f ), Vector2::ZERO, white );
201 // Specify all the faces
202 MeshData::FaceIndices faces;
203 faces.reserve( 6 ); // 2 triangles in Quad
204 faces.push_back( 0 ); faces.push_back( 3 ); faces.push_back( 1 );
205 faces.push_back( 0 ); faces.push_back( 2 ); faces.push_back( 3 );
207 // Create the mesh data from the vertices and faces
208 meshData.SetMaterial( Material::New( "ControlMaterial" ) );
209 meshData.SetVertices( vertices );
210 meshData.SetFaceIndices( faces );
211 meshData.SetHasColor( true );
213 return Mesh::New( meshData );
217 * Sets all the required properties for the background actor.
219 * @param[in] actor The actor to set the properties on.
220 * @param[in] constrainingIndex The property index to constrain the parent's size on.
221 * @param[in] color The required color of the actor.
223 void SetupBackgroundActor( Actor actor, Property::Index constrainingIndex, const Vector4& color )
225 actor.SetColor( color );
226 actor.SetPositionInheritanceMode( USE_PARENT_POSITION_PLUS_LOCAL_POSITION );
227 actor.SetColorMode( USE_OWN_MULTIPLY_PARENT_COLOR );
228 actor.SetZ( BACKGROUND_ACTOR_Z_POSITION );
230 Constraint constraint = Constraint::New<Vector3>( constrainingIndex,
231 ParentSource( Actor::SIZE ),
232 EqualToConstraint() );
233 actor.ApplyConstraint( constraint );
236 } // unnamed namespace
241 class Control::Impl : public ConnectionTracker
246 * Size indices for mMinMaxSize array
255 // Construction & Destruction
256 Impl(Control& controlImpl)
257 : mControlImpl( controlImpl ),
259 mStartingPinchScale( NULL ),
261 mPinchGestureDetector(),
262 mPanGestureDetector(),
263 mTapGestureDetector(),
264 mLongPressGestureDetector(),
267 mWidthPolicy( Toolkit::Control::Fixed ),
268 mHeightPolicy( Toolkit::Control::Fixed ),
269 mFlags( Control::CONTROL_BEHAVIOUR_NONE ),
270 mInsideRelayout( false ),
271 mIsKeyboardNavigationSupported( false ),
272 mIsKeyboardFocusGroup( false ),
273 mInitialized( false )
279 // All gesture detectors will be destroyed so no need to disconnect.
281 delete mStartingPinchScale;
284 // Gesture Detection Methods
286 void PinchDetected(Actor actor, const PinchGesture& pinch)
288 mControlImpl.OnPinch(pinch);
291 void PanDetected(Actor actor, const PanGesture& pan)
293 mControlImpl.OnPan(pan);
296 void TapDetected(Actor actor, const TapGesture& tap)
298 mControlImpl.OnTap(tap);
301 void LongPressDetected(Actor actor, const LongPressGesture& longPress)
303 mControlImpl.OnLongPress(longPress);
306 // Background Methods
309 * Only creates an instance of the background if we actually use it.
310 * @return A reference to the Background structure.
312 Background& GetBackground()
316 mBackground = new Background;
324 * Called when a property of an object of this type is set.
325 * @param[in] object The object whose property is set.
326 * @param[in] index The property index.
327 * @param[in] value The new property value.
329 static void SetProperty( BaseObject* object, Property::Index index, const Property::Value& value )
331 Toolkit::Control control = Toolkit::Control::DownCast( BaseHandle( object ) );
335 Control& controlImpl( control.GetImplementation() );
339 case Toolkit::Control::PROPERTY_BACKGROUND_COLOR:
341 controlImpl.SetBackgroundColor( value.Get< Vector4 >() );
345 case Toolkit::Control::PROPERTY_BACKGROUND:
347 if ( value.HasKey( "image" ) )
349 Property::Map imageMap = value.GetValue( "image" ).Get< Property::Map >();
350 Image image = Scripting::NewImage( imageMap );
354 controlImpl.SetBackground( image );
357 else if ( value.Get< Property::Map >().Empty() )
359 // An empty map means the background is no longer required
360 controlImpl.ClearBackground();
365 case Toolkit::Control::PROPERTY_WIDTH_POLICY:
367 controlImpl.mImpl->mWidthPolicy = Scripting::GetEnumeration< Toolkit::Control::SizePolicy >( value.Get< std::string >().c_str(), SIZE_POLICY_STRING_TABLE, SIZE_POLICY_STRING_TABLE_COUNT );
371 case Toolkit::Control::PROPERTY_HEIGHT_POLICY:
373 controlImpl.mImpl->mHeightPolicy = Scripting::GetEnumeration< Toolkit::Control::SizePolicy >( value.Get< std::string >().c_str(), SIZE_POLICY_STRING_TABLE, SIZE_POLICY_STRING_TABLE_COUNT );
377 case Toolkit::Control::PROPERTY_MINIMUM_SIZE:
379 controlImpl.SetMinimumSize( value.Get< Vector3 >() );
383 case Toolkit::Control::PROPERTY_MAXIMUM_SIZE:
385 controlImpl.SetMaximumSize( value.Get< Vector3 >() );
389 case Toolkit::Control::PROPERTY_KEY_INPUT_FOCUS:
391 if ( value.Get< bool >() )
393 controlImpl.SetKeyInputFocus();
397 controlImpl.ClearKeyInputFocus();
406 * Called to retrieve a property of an object of this type.
407 * @param[in] object The object whose property is to be retrieved.
408 * @param[in] index The property index.
409 * @return The current value of the property.
411 static Property::Value GetProperty( BaseObject* object, Property::Index index )
413 Property::Value value;
415 Toolkit::Control control = Toolkit::Control::DownCast( BaseHandle( object ) );
419 Control& controlImpl( control.GetImplementation() );
423 case Toolkit::Control::PROPERTY_BACKGROUND_COLOR:
425 value = controlImpl.GetBackgroundColor();
429 case Toolkit::Control::PROPERTY_BACKGROUND:
433 Actor actor = controlImpl.GetBackgroundActor();
436 ImageActor imageActor = ImageActor::DownCast( actor );
439 Image image = imageActor.GetImage();
440 Property::Map imageMap;
441 Scripting::CreatePropertyMap( image, imageMap );
442 map[ "image" ] = imageMap;
450 case Toolkit::Control::PROPERTY_WIDTH_POLICY:
452 value = std::string( Scripting::GetEnumerationName< Toolkit::Control::SizePolicy >( controlImpl.mImpl->mWidthPolicy, SIZE_POLICY_STRING_TABLE, SIZE_POLICY_STRING_TABLE_COUNT ) );
456 case Toolkit::Control::PROPERTY_HEIGHT_POLICY:
458 value = std::string( Scripting::GetEnumerationName< Toolkit::Control::SizePolicy >( controlImpl.mImpl->mHeightPolicy, SIZE_POLICY_STRING_TABLE, SIZE_POLICY_STRING_TABLE_COUNT ) );
462 case Toolkit::Control::PROPERTY_MINIMUM_SIZE:
464 value = controlImpl.mImpl->GetMinimumSize();
468 case Toolkit::Control::PROPERTY_MAXIMUM_SIZE:
470 value = controlImpl.mImpl->GetMaximumSize();
474 case Toolkit::Control::PROPERTY_KEY_INPUT_FOCUS:
476 value = controlImpl.HasKeyInputFocus();
486 * Helper to get minimum size
487 * @return minimum size
489 inline const Vector3& GetMinimumSize()
491 if( mMinMaxSize.Count() > MIN_SIZE_INDEX )
493 return mMinMaxSize[ MIN_SIZE_INDEX ];
497 // its not been allocated so its ZERO
498 return Vector3::ZERO;
502 * Helper to Set minimum size
505 inline void SetMinimumSize( const Vector3& size )
507 if( mMinMaxSize.Count() > MIN_SIZE_INDEX )
509 mMinMaxSize[ MIN_SIZE_INDEX ] = size;
513 // its not been allocated so push the new value there
514 mMinMaxSize.PushBack( size );
519 * Helper to get maximum size
520 * @return maximum size
522 inline const Vector3& GetMaximumSize()
524 if( mMinMaxSize.Count() > MAX_SIZE_INDEX )
526 return mMinMaxSize[ MAX_SIZE_INDEX ];
530 // its not been allocated so its MAX_SIZE
536 * Helper to Set minimum size
539 inline void SetMaximumSize( const Vector3& size )
541 if( mMinMaxSize.Count() > MAX_SIZE_INDEX )
543 mMinMaxSize[ MAX_SIZE_INDEX ] = size;
545 else if( mMinMaxSize.Count() > MIN_SIZE_INDEX )
547 // max has not been allocated, but min has
548 mMinMaxSize.PushBack( size );
552 // min and max both unallocated so allocate both
553 mMinMaxSize.Resize( 2u ); // this will reserve and default construct two Vector3s
554 mMinMaxSize[ MAX_SIZE_INDEX ] = size;
560 Control& mControlImpl;
561 Background* mBackground; ///< Only create the background if we use it
562 Vector3* mStartingPinchScale; ///< The scale when a pinch gesture starts, TODO: consider removing this
563 Toolkit::Control::KeyEventSignalType mKeyEventSignal;
566 PinchGestureDetector mPinchGestureDetector;
567 PanGestureDetector mPanGestureDetector;
568 TapGestureDetector mTapGestureDetector;
569 LongPressGestureDetector mLongPressGestureDetector;
570 // @todo change all these to Vector2 when we have a chance to sanitize the public API as well
571 Vector3 mCurrentSize; ///< Stores the current control's size, this is the negotiated size
572 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.
573 Dali::Vector< Vector3 > mMinMaxSize; ///< Stores the minimum and maximum size if they are set
575 Toolkit::Control::SizePolicy mWidthPolicy :3; ///< Stores the width policy. 3 bits covers 8 values
576 Toolkit::Control::SizePolicy mHeightPolicy :3; ///< Stores the height policy. 3 bits covers 8 values
577 ControlBehaviour mFlags :6; ///< Flags passed in from constructor. Need to increase this size when new enums are added
578 bool mInsideRelayout:1; ///< Detect when were in Relayout
579 bool mIsKeyboardNavigationSupported:1; ///< Stores whether keyboard navigation is supported by the control.
580 bool mIsKeyboardFocusGroup:1; ///< Stores whether the control is a focus group.
583 // Properties - these need to be members of Internal::Control::Impl as they need to functions within this class.
584 static PropertyRegistration PROPERTY_1;
585 static PropertyRegistration PROPERTY_2;
586 static PropertyRegistration PROPERTY_3;
587 static PropertyRegistration PROPERTY_4;
588 static PropertyRegistration PROPERTY_5;
589 static PropertyRegistration PROPERTY_6;
590 static PropertyRegistration PROPERTY_7;
593 PropertyRegistration Control::Impl::PROPERTY_1( CONTROL_TYPE, "background-color", Toolkit::Control::PROPERTY_BACKGROUND_COLOR, Property::VECTOR4, &Control::Impl::SetProperty, &Control::Impl::GetProperty );
594 PropertyRegistration Control::Impl::PROPERTY_2( CONTROL_TYPE, "background", Toolkit::Control::PROPERTY_BACKGROUND, Property::MAP, &Control::Impl::SetProperty, &Control::Impl::GetProperty );
595 PropertyRegistration Control::Impl::PROPERTY_3( CONTROL_TYPE, "width-policy", Toolkit::Control::PROPERTY_WIDTH_POLICY, Property::STRING, &Control::Impl::SetProperty, &Control::Impl::GetProperty );
596 PropertyRegistration Control::Impl::PROPERTY_4( CONTROL_TYPE, "height-policy", Toolkit::Control::PROPERTY_HEIGHT_POLICY, Property::STRING, &Control::Impl::SetProperty, &Control::Impl::GetProperty );
597 PropertyRegistration Control::Impl::PROPERTY_5( CONTROL_TYPE, "minimum-size", Toolkit::Control::PROPERTY_MINIMUM_SIZE, Property::VECTOR3, &Control::Impl::SetProperty, &Control::Impl::GetProperty );
598 PropertyRegistration Control::Impl::PROPERTY_6( CONTROL_TYPE, "maximum-size", Toolkit::Control::PROPERTY_MAXIMUM_SIZE, Property::VECTOR3, &Control::Impl::SetProperty, &Control::Impl::GetProperty );
599 PropertyRegistration Control::Impl::PROPERTY_7( CONTROL_TYPE, "key-input-focus", Toolkit::Control::PROPERTY_KEY_INPUT_FOCUS, Property::BOOLEAN, &Control::Impl::SetProperty, &Control::Impl::GetProperty );
601 Toolkit::Control Control::New()
603 // Create the implementation, temporarily owned on stack
604 IntrusivePtr<Control> controlImpl = new Control( CONTROL_BEHAVIOUR_NONE );
606 // Pass ownership to handle
607 Toolkit::Control handle( *controlImpl );
609 // Second-phase init of the implementation
610 // This can only be done after the CustomActor connection has been made...
611 controlImpl->Initialize();
621 void Control::SetSizePolicy( Toolkit::Control::SizePolicy widthPolicy, Toolkit::Control::SizePolicy heightPolicy )
623 bool relayoutRequest( false );
625 if ( ( mImpl->mWidthPolicy != widthPolicy ) || ( mImpl->mHeightPolicy != heightPolicy ) )
627 relayoutRequest = true;
630 mImpl->mWidthPolicy = widthPolicy;
631 mImpl->mHeightPolicy = heightPolicy;
633 // Ensure RelayoutRequest is called AFTER new policies have been set.
634 if ( relayoutRequest )
640 void Control::GetSizePolicy( Toolkit::Control::SizePolicy& widthPolicy, Toolkit::Control::SizePolicy& heightPolicy ) const
642 widthPolicy = mImpl->mWidthPolicy;
643 heightPolicy = mImpl->mHeightPolicy;
646 void Control::SetMinimumSize( const Vector3& size )
648 const Vector3& minSize = mImpl->GetMinimumSize();
649 if ( fabsf( minSize.width - size.width ) > Math::MACHINE_EPSILON_1000 ||
650 fabsf( minSize.height - size.height ) > Math::MACHINE_EPSILON_1000 )
652 mImpl->SetMinimumSize( size );
654 // Only relayout if our control is using the minimum or range policy.
655 if ( ( mImpl->mHeightPolicy == Toolkit::Control::Minimum ) || ( mImpl->mWidthPolicy == Toolkit::Control::Minimum ) ||
656 ( mImpl->mHeightPolicy == Toolkit::Control::Range ) || ( mImpl->mWidthPolicy == Toolkit::Control::Range ) )
663 const Vector3& Control::GetMinimumSize() const
665 return mImpl->GetMinimumSize();
668 void Control::SetMaximumSize( const Vector3& size )
670 const Vector3& maxSize = mImpl->GetMaximumSize();
671 if ( fabsf( maxSize.width - size.width ) > Math::MACHINE_EPSILON_1000 ||
672 fabsf( maxSize.height - size.height ) > Math::MACHINE_EPSILON_1000 )
674 mImpl->SetMaximumSize( size );
676 // Only relayout if our control is using the maximum or range policy.
677 if ( ( mImpl->mHeightPolicy == Toolkit::Control::Maximum ) || ( mImpl->mWidthPolicy == Toolkit::Control::Maximum ) ||
678 ( mImpl->mHeightPolicy == Toolkit::Control::Range ) || ( mImpl->mWidthPolicy == Toolkit::Control::Range ) )
685 const Vector3& Control::GetMaximumSize() const
687 return mImpl->GetMaximumSize();
690 Vector3 Control::GetNaturalSize()
692 // could be overridden in derived classes.
693 return mImpl->mNaturalSize;
696 float Control::GetHeightForWidth( float width )
698 // could be overridden in derived classes.
699 float height( 0.0f );
700 if ( mImpl->mNaturalSize.width > 0.0f )
702 height = mImpl->mNaturalSize.height * width / mImpl->mNaturalSize.width;
707 float Control::GetWidthForHeight( float height )
709 // could be overridden in derived classes.
711 if ( mImpl->mNaturalSize.height > 0.0f )
713 width = mImpl->mNaturalSize.width * height / mImpl->mNaturalSize.height;
718 const Vector3& Control::GetControlSize() const
720 return mImpl->mCurrentSize;
723 const Vector3& Control::GetSizeSet() const
725 return mImpl->mNaturalSize;
728 void Control::SetKeyInputFocus()
730 if( Self().OnStage() )
732 Toolkit::KeyInputFocusManager::Get().SetFocus(Toolkit::Control::DownCast(Self()));
736 bool Control::HasKeyInputFocus()
739 if( Self().OnStage() )
741 result = Toolkit::KeyInputFocusManager::Get().IsKeyboardListener(Toolkit::Control::DownCast(Self()));
746 void Control::ClearKeyInputFocus()
748 if( Self().OnStage() )
750 Toolkit::KeyInputFocusManager::Get().RemoveFocus(Toolkit::Control::DownCast(Self()));
754 PinchGestureDetector Control::GetPinchGestureDetector() const
756 return mImpl->mPinchGestureDetector;
759 PanGestureDetector Control::GetPanGestureDetector() const
761 return mImpl->mPanGestureDetector;
764 TapGestureDetector Control::GetTapGestureDetector() const
766 return mImpl->mTapGestureDetector;
769 LongPressGestureDetector Control::GetLongPressGestureDetector() const
771 return mImpl->mLongPressGestureDetector;
774 void Control::SetBackgroundColor( const Vector4& color )
776 Background& background( mImpl->GetBackground() );
778 if ( background.actor )
780 // Just set the actor color
781 background.actor.SetColor( color );
786 MeshActor meshActor = MeshActor::New( CreateMesh() );
788 meshActor.SetAffectedByLighting( false );
789 SetupBackgroundActor( meshActor, Actor::SCALE, color );
791 // Set the background actor before adding so that we do not inform deriving classes
792 background.actor = meshActor;
793 Self().Add( meshActor );
796 background.color = color;
799 Vector4 Control::GetBackgroundColor() const
801 if ( mImpl->mBackground )
803 return mImpl->mBackground->color;
805 return Color::TRANSPARENT;
808 void Control::SetBackground( Image image )
810 Background& background( mImpl->GetBackground() );
812 if ( background.actor )
814 // Remove Current actor, unset AFTER removal so that we do not inform deriving classes
815 Self().Remove( background.actor );
816 background.actor.Reset();
819 ImageActor imageActor = ImageActor::New( image );
820 SetupBackgroundActor( imageActor, Actor::SIZE, background.color );
822 // Set the background actor before adding so that we do not inform derived classes
823 background.actor = imageActor;
824 Self().Add( imageActor );
827 void Control::ClearBackground()
829 if ( mImpl->mBackground )
831 Background& background( mImpl->GetBackground() );
832 Self().Remove( background.actor );
834 delete mImpl->mBackground;
835 mImpl->mBackground = NULL;
839 Actor Control::GetBackgroundActor() const
841 if ( mImpl->mBackground )
843 return mImpl->mBackground->actor;
849 void Control::SetKeyboardNavigationSupport(bool isSupported)
851 mImpl->mIsKeyboardNavigationSupported = isSupported;
854 bool Control::IsKeyboardNavigationSupported()
856 return mImpl->mIsKeyboardNavigationSupported;
859 void Control::Activate()
861 // Inform deriving classes
865 bool Control::OnAccessibilityPan(PanGesture gesture)
867 return false; // Accessibility pan gesture is not handled by default
870 bool Control::OnAccessibilityTouch(const TouchEvent& touchEvent)
872 return false; // Accessibility touch event is not handled by default
875 bool Control::OnAccessibilityValueChange(bool isIncrease)
877 return false; // Accessibility value change action is not handled by default
880 void Control::NegotiateSize( const Vector2& allocatedSize, ActorSizeContainer& container )
884 if ( mImpl->mWidthPolicy == Toolkit::Control::Fixed )
886 if ( mImpl->mHeightPolicy == Toolkit::Control::Fixed )
888 // If a control says it has a fixed size, then use the size set by the application / control.
889 Vector2 setSize( mImpl->mNaturalSize );
890 if ( setSize != Vector2::ZERO )
894 // Policy is set to Fixed, so if the application / control has not set one of the dimensions,
895 // then we should use the natural size of the control rather than the full allocation.
896 if ( EqualsZero( size.width ) )
898 size.width = GetWidthForHeight( size.height );
900 else if ( EqualsZero( size.height ) )
902 size.height = GetHeightForWidth( size.width );
907 // If that is not set then set the size to the control's natural size
908 size = Vector2( GetNaturalSize() );
913 // Width is fixed so if the application / control has set it, then use that.
914 if ( !EqualsZero( mImpl->mNaturalSize.width ) )
916 size.width = mImpl->mNaturalSize.width;
920 // Otherwise, set the width to what has been allocated.
921 size.width = allocatedSize.width;
924 // Height is flexible so ask control what the height should be for our width.
925 size.height = GetHeightForWidth( size.width );
927 // Ensure height is within our policy rules
928 size.height = Calculate( mImpl->mHeightPolicy, GetMinimumSize().height, GetMaximumSize().height, size.height );
933 if ( mImpl->mHeightPolicy == Toolkit::Control::Fixed )
935 // Height is fixed so if the application / control has set it, then use that.
936 if ( !EqualsZero( mImpl->mNaturalSize.height ) )
938 size.height = mImpl->mNaturalSize.height;
942 // Otherwise, set the height to what has been allocated.
943 size.height = allocatedSize.height;
946 // Width is flexible so ask control what the width should be for our height.
947 size.width = GetWidthForHeight( size.height );
949 // Ensure width is within our policy rules
950 size.width = Calculate( mImpl->mWidthPolicy, mImpl->GetMinimumSize().width, mImpl->GetMaximumSize().width, size.width );
954 // Width and height are BOTH flexible.
955 // Calculate the width and height using the policy rules.
956 size.width = Calculate( mImpl->mWidthPolicy, mImpl->GetMinimumSize().width, mImpl->GetMaximumSize().width, allocatedSize.width );
957 size.height = Calculate( mImpl->mHeightPolicy, mImpl->GetMinimumSize().height, mImpl->GetMaximumSize().height, allocatedSize.height );
961 // If the width has not been set, then set to the allocated width.
962 // Also if the width set is greater than the allocated, then set to allocated (no exceed support).
963 if ( EqualsZero( size.width ) || ( size.width > allocatedSize.width ) )
965 size.width = allocatedSize.width;
968 // If the height has not been set, then set to the allocated height.
969 // Also if the height set is greater than the allocated, then set to allocated (no exceed support).
970 if ( EqualsZero( size.height ) || ( size.height > allocatedSize.height ) )
972 size.height = allocatedSize.height;
975 DALI_LOG_INFO( gLogFilter, Debug::Verbose,
976 "%p: Natural: [%.2f, %.2f] Allocated: [%.2f, %.2f] Set: [%.2f, %.2f]\n",
977 Self().GetObjectPtr(),
978 GetNaturalSize().x, GetNaturalSize().y,
979 allocatedSize.x, allocatedSize.y,
982 // Avoids relayout again when OnSizeSet callback arrives as a function of us or deriving class calling SetSize()
983 mImpl->mInsideRelayout = true;
984 Self().SetSize( size );
985 // Only relayout controls which requested to be relaid out.
986 OnRelayout( size, container );
987 mImpl->mInsideRelayout = false;
990 void Control::SetAsKeyboardFocusGroup(bool isFocusGroup)
992 mImpl->mIsKeyboardFocusGroup = isFocusGroup;
994 // The following line will be removed when the deprecated API in KeyboardFocusManager is deleted
995 Toolkit::KeyboardFocusManager::Get().SetAsFocusGroup(Self(), isFocusGroup);
998 bool Control::IsKeyboardFocusGroup()
1000 return Toolkit::KeyboardFocusManager::Get().IsFocusGroup(Self());
1003 Actor Control::GetNextKeyboardFocusableActor(Actor currentFocusedActor, Toolkit::Control::KeyboardFocusNavigationDirection direction, bool loopEnabled)
1008 void Control::OnKeyboardFocusChangeCommitted(Actor commitedFocusableActor)
1012 bool Control::DoAction(BaseObject* object, const std::string& actionName, const PropertyValueContainer& attributes)
1016 if( object && ( 0 == strcmp( actionName.c_str(), ACTION_CONTROL_ACTIVATED ) ) )
1018 Toolkit::Control control = Toolkit::Control::DownCast( BaseHandle( object ) );
1021 // if cast succeeds there is an implementation so no need to check
1022 control.GetImplementation().OnActivated();
1029 bool Control::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
1031 Dali::BaseHandle handle( object );
1033 bool connected( false );
1034 Toolkit::Control control = Toolkit::Control::DownCast( handle );
1037 Control& controlImpl( control.GetImplementation() );
1040 if ( 0 == strcmp( signalName.c_str(), SIGNAL_KEY_EVENT ) )
1042 controlImpl.KeyEventSignal().Connect( tracker, functor );
1044 else if( 0 == strcmp( signalName.c_str(), SIGNAL_TAPPED ) )
1046 controlImpl.EnableGestureDetection( Gesture::Tap );
1047 controlImpl.GetTapGestureDetector().DetectedSignal().Connect( tracker, functor );
1049 else if( 0 == strcmp( signalName.c_str(), SIGNAL_PANNED ) )
1051 controlImpl.EnableGestureDetection( Gesture::Pan );
1052 controlImpl.GetPanGestureDetector().DetectedSignal().Connect( tracker, functor );
1054 else if( 0 == strcmp( signalName.c_str(), SIGNAL_PINCHED ) )
1056 controlImpl.EnableGestureDetection( Gesture::Pinch );
1057 controlImpl.GetPinchGestureDetector().DetectedSignal().Connect( tracker, functor );
1059 else if( 0 == strcmp( signalName.c_str(), SIGNAL_LONG_PRESSED ) )
1061 controlImpl.EnableGestureDetection( Gesture::LongPress );
1062 controlImpl.GetLongPressGestureDetector().DetectedSignal().Connect( tracker, functor );
1066 // signalName does not match any signal
1073 Toolkit::Control::KeyEventSignalType& Control::KeyEventSignal()
1075 return mImpl->mKeyEventSignal;
1078 bool Control::EmitKeyEventSignal( const KeyEvent& event )
1080 // Guard against destruction during signal emission
1081 Dali::Toolkit::Control handle( GetOwner() );
1083 bool consumed = false;
1085 // signals are allocated dynamically when someone connects
1086 if ( !mImpl->mKeyEventSignal.Empty() )
1088 consumed = mImpl->mKeyEventSignal.Emit( handle, event );
1093 // Notification for derived classes
1094 consumed = OnKeyEvent(event);
1100 Control::Control( ControlBehaviour behaviourFlags )
1101 : CustomActorImpl( behaviourFlags & REQUIRES_TOUCH_EVENTS ),
1102 mImpl(new Impl(*this))
1104 mImpl->mFlags = behaviourFlags;
1107 void Control::Initialize()
1110 // Calling deriving classes
1113 if( mImpl->mFlags & REQUIRES_STYLE_CHANGE_SIGNALS )
1115 Toolkit::StyleManager styleManager = Toolkit::StyleManager::Get();
1117 // Register for style changes
1118 styleManager.StyleChangeSignal().Connect( this, &Control::DoStyleChange );
1121 GetImpl( styleManager ).ApplyThemeStyle( Toolkit::Control( GetOwner() ) );
1124 SetRequiresHoverEvents(mImpl->mFlags & REQUIRES_HOVER_EVENTS);
1125 SetRequiresMouseWheelEvents(mImpl->mFlags & REQUIRES_MOUSE_WHEEL_EVENTS);
1127 mImpl->mInitialized = true;
1130 void Control::EnableGestureDetection(Gesture::Type type)
1132 if ( (type & Gesture::Pinch) && !mImpl->mPinchGestureDetector )
1134 mImpl->mPinchGestureDetector = PinchGestureDetector::New();
1135 mImpl->mPinchGestureDetector.DetectedSignal().Connect(mImpl, &Impl::PinchDetected);
1136 mImpl->mPinchGestureDetector.Attach(Self());
1139 if ( (type & Gesture::Pan) && !mImpl->mPanGestureDetector )
1141 mImpl->mPanGestureDetector = PanGestureDetector::New();
1142 mImpl->mPanGestureDetector.DetectedSignal().Connect(mImpl, &Impl::PanDetected);
1143 mImpl->mPanGestureDetector.Attach(Self());
1146 if ( (type & Gesture::Tap) && !mImpl->mTapGestureDetector )
1148 mImpl->mTapGestureDetector = TapGestureDetector::New();
1149 mImpl->mTapGestureDetector.DetectedSignal().Connect(mImpl, &Impl::TapDetected);
1150 mImpl->mTapGestureDetector.Attach(Self());
1153 if ( (type & Gesture::LongPress) && !mImpl->mLongPressGestureDetector )
1155 mImpl->mLongPressGestureDetector = LongPressGestureDetector::New();
1156 mImpl->mLongPressGestureDetector.DetectedSignal().Connect(mImpl, &Impl::LongPressDetected);
1157 mImpl->mLongPressGestureDetector.Attach(Self());
1161 void Control::DisableGestureDetection(Gesture::Type type)
1163 if ( (type & Gesture::Pinch) && mImpl->mPinchGestureDetector )
1165 mImpl->mPinchGestureDetector.Detach(Self());
1166 mImpl->mPinchGestureDetector.Reset();
1169 if ( (type & Gesture::Pan) && mImpl->mPanGestureDetector )
1171 mImpl->mPanGestureDetector.Detach(Self());
1172 mImpl->mPanGestureDetector.Reset();
1175 if ( (type & Gesture::Tap) && mImpl->mTapGestureDetector )
1177 mImpl->mTapGestureDetector.Detach(Self());
1178 mImpl->mTapGestureDetector.Reset();
1181 if ( (type & Gesture::LongPress) && mImpl->mLongPressGestureDetector)
1183 mImpl->mLongPressGestureDetector.Detach(Self());
1184 mImpl->mLongPressGestureDetector.Reset();
1188 void Control::RelayoutRequest()
1190 // unfortunate double negative but thats to guarantee new controls get size negotiation
1191 // by default and have to "opt-out" if they dont want it
1192 if( !(mImpl->mFlags & NO_SIZE_NEGOTIATION) )
1194 Internal::RelayoutController::Request();
1198 void Control::Relayout( Actor actor, const Vector2& size, ActorSizeContainer& container )
1202 Toolkit::Control control( Toolkit::Control::DownCast( actor ) );
1205 control.GetImplementation().NegotiateSize( size, container );
1209 container.push_back( ActorSizePair( actor, size ) );
1214 void Control::OnInitialize()
1218 void Control::OnActivated()
1222 void Control::OnThemeChange( Toolkit::StyleManager styleManager )
1224 GetImpl( styleManager ).ApplyThemeStyle( Toolkit::Control( GetOwner() ) );
1227 void Control::OnFontChange( bool defaultFontChange, bool defaultFontSizeChange )
1231 void Control::OnPinch(const PinchGesture& pinch)
1233 if( !( mImpl->mStartingPinchScale ) )
1236 mImpl->mStartingPinchScale = new Vector3;
1239 if( pinch.state == Gesture::Started )
1241 *( mImpl->mStartingPinchScale ) = Self().GetCurrentScale();
1244 Self().SetScale( *( mImpl->mStartingPinchScale ) * pinch.scale );
1247 void Control::OnPan( const PanGesture& pan )
1251 void Control::OnTap(const TapGesture& tap)
1255 void Control::OnLongPress( const LongPressGesture& longPress )
1259 void Control::OnControlStageConnection()
1263 void Control::OnControlStageDisconnection()
1267 void Control::OnControlChildAdd( Actor& child )
1271 void Control::OnControlChildRemove( Actor& child )
1275 void Control::OnControlSizeSet( const Vector3& size )
1279 void Control::OnRelayout( const Vector2& size, ActorSizeContainer& container )
1281 unsigned int numChildren = Self().GetChildCount();
1283 for( unsigned int i=0; i<numChildren; ++i )
1285 container.push_back( ActorSizePair( Self().GetChildAt(i), size ) );
1289 void Control::OnKeyInputFocusGained()
1294 void Control::OnKeyInputFocusLost()
1299 void Control::OnSizeAnimation(Animation& animation, const Vector3& targetSize)
1301 // @todo consider animating negotiated child sizes to target size
1304 bool Control::OnTouchEvent(const TouchEvent& event)
1306 return false; // Do not consume
1309 bool Control::OnHoverEvent(const HoverEvent& event)
1311 return false; // Do not consume
1314 bool Control::OnKeyEvent(const KeyEvent& event)
1316 return false; // Do not consume
1319 bool Control::OnMouseWheelEvent(const MouseWheelEvent& event)
1321 return false; // Do not consume
1324 Actor Control::GetChildByAlias(const std::string& actorAlias)
1329 void Control::OnStageConnection()
1333 // Notify derived classes.
1334 OnControlStageConnection();
1337 void Control::OnStageDisconnection()
1339 // Notify derived classes
1340 OnControlStageDisconnection();
1343 void Control::OnChildAdd(Actor& child)
1345 // If this is the background actor, then we do not want to relayout or inform deriving classes
1346 if ( mImpl->mBackground && ( child == mImpl->mBackground->actor ) )
1351 // Request for relayout as we may need to position the new child and old ones
1354 // Notify derived classes.
1355 OnControlChildAdd( child );
1358 void Control::OnChildRemove(Actor& child)
1360 // If this is the background actor, then we do not want to relayout or inform deriving classes
1361 if ( mImpl->mBackground && ( child == mImpl->mBackground->actor ) )
1366 // Request for relayout as we may need to re-position the old child
1369 // Notify derived classes.
1370 OnControlChildRemove( child );
1373 void Control::OnSizeSet(const Vector3& targetSize)
1375 if( ( !mImpl->mInsideRelayout ) && ( targetSize != mImpl->mNaturalSize ) )
1377 // Only updates size if set through Actor's API
1378 mImpl->mNaturalSize = targetSize;
1381 if( targetSize != mImpl->mCurrentSize )
1383 // Update control size.
1384 mImpl->mCurrentSize = targetSize;
1386 // Notify derived classes.
1387 OnControlSizeSet( targetSize );
1391 void Control::SignalConnected( SlotObserver* slotObserver, CallbackBase* callback )
1393 mImpl->SignalConnected( slotObserver, callback );
1396 void Control::SignalDisconnected( SlotObserver* slotObserver, CallbackBase* callback )
1398 mImpl->SignalDisconnected( slotObserver, callback );
1401 void Control::DoStyleChange( Toolkit::StyleManager styleManager, StyleChange change )
1403 if( change.themeChange )
1405 OnThemeChange( styleManager );
1407 else if( change.defaultFontChange || change.defaultFontSizeChange )
1409 OnFontChange( change.defaultFontChange, change.defaultFontSizeChange );
1413 } // namespace Internal
1415 } // namespace Toolkit