2 // Copyright (c) 2014 Samsung Electronics Co., Ltd.
4 // Licensed under the Flora License, Version 1.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://floralicense.org/license/
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.
17 #include <dali-toolkit/public-api/controls/control-impl.h>
19 #include <boost/thread/tss.hpp>
22 #include <dali/integration-api/debug.h>
24 #include "dali-toolkit/internal/controls/style-change-processor.h"
25 #include "dali-toolkit/internal/controls/relayout-controller.h"
26 #include "dali-toolkit/internal/controls/relayout-helper.h"
27 #include "dali-toolkit/public-api/focus-manager/keyinput-focus-manager.h"
28 #include "dali-toolkit/public-api/focus-manager/keyboard-focus-manager.h"
29 #include <dali-toolkit/public-api/controls/control.h>
40 #if defined(DEBUG_ENABLED)
41 Integration::Log::Filter* gLogFilter = Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_CONTROL");
44 const float MAX_FLOAT_VALUE( std::numeric_limits<float>::max() );
48 return ControlImpl::New();
51 TypeRegistration CONTROL_TYPE( typeid(Control), typeid(CustomActor), Create );
53 TypeAction ACTION_TYPE_1(CONTROL_TYPE, Toolkit::Control::ACTION_CONTROL_ACTIVATED, &ControlImpl::DoAction);
56 * Helper class used to set the Control's size through the Actor's API or through children added.
61 SetSizeLock( bool& lock )
77 * Helper function to calculate a dimension given the policy of that dimension; the minimum &
78 * maximum values that dimension can be; and the allocated value for that dimension.
80 * @param[in] policy The size policy for that dimension.
81 * @param[in] minimum The minimum value that dimension can be.
82 * @param[in] maximum The maximum value that dimension can be.
83 * @param[in] allocated The value allocated for that dimension.
85 * @return The value that the dimension should be.
87 * @note This does not handle Control::Fixed policy.
89 float Calculate( Control::SizePolicy policy, float minimum, float maximum, float allocated )
91 float size( allocated );
97 // Use allocated value
101 case Control::Minimum:
103 // Size is always at least the minimum.
104 size = std::max( allocated, minimum );
108 case Control::Maximum:
110 // Size can grow but up to a maximum value.
111 size = std::min( allocated, maximum );
117 // Size is at least the minimum and can grow up to the maximum
118 size = std::max( size, minimum );
119 size = std::min( size, maximum );
123 case Control::Flexible:
125 // Size grows or shrinks with no limits.
132 DALI_ASSERT_DEBUG( false && "This function was not intended to be used by any other policy." );
140 } // unnamed namespace
142 class ControlImpl::Impl : public ConnectionTrackerInterface
145 // Construction & Destruction
146 Impl(ControlImpl& controlImpl)
147 : mControlImpl(controlImpl),
148 mInitialized( false ),
149 mPinchGestureDetector(),
150 mPanGestureDetector(),
151 mTapGestureDetector(),
152 mLongPressGestureDetector(),
153 mStartingPinchScale(),
154 mLockSetSize( false ),
155 mWidthPolicy( Control::Fixed ),
156 mHeightPolicy( Control::Fixed ),
160 mMaximumSize( MAX_FLOAT_VALUE, MAX_FLOAT_VALUE, MAX_FLOAT_VALUE ),
161 mIsKeyboardNavigationSupported(false),
162 mIsKeyboardFocusGroup(false),
169 // All gesture detectors will be destroyed so no need to disconnect.
172 // Gesture Detection Methods
174 void PinchDetected(Actor actor, PinchGesture pinch)
176 mControlImpl.OnPinch(pinch);
179 void PanDetected(Actor actor, PanGesture pan)
181 mControlImpl.OnPan(pan);
184 void TapDetected(Actor actor, TapGesture tap)
186 mControlImpl.OnTap(tap);
189 void LongPressDetected(Actor actor, LongPressGesture longPress)
191 mControlImpl.OnLongPress(longPress);
195 * @copydoc ConnectionTrackerInterface::SignalConnected
197 virtual void SignalConnected( SlotObserver* slotObserver, CallbackBase* callback )
199 mConnectionTracker.SignalConnected( slotObserver, callback );
203 * @copydoc ConnectionTrackerInterface::SignalDisconnected
205 virtual void SignalDisconnected( SlotObserver* slotObserver, CallbackBase* callback )
207 mConnectionTracker.SignalDisconnected( slotObserver, callback );
211 * @copydoc ConnectionTrackerInterface::GetConnectionCount
213 virtual std::size_t GetConnectionCount() const
215 return mConnectionTracker.GetConnectionCount();
220 ControlImpl& mControlImpl;
224 ConnectionTracker mConnectionTracker; // signal connection tracker
228 PinchGestureDetector mPinchGestureDetector;
229 PanGestureDetector mPanGestureDetector;
230 TapGestureDetector mTapGestureDetector;
231 LongPressGestureDetector mLongPressGestureDetector;
233 Vector3 mStartingPinchScale; ///< The scale when a pinch gesture starts
235 // Relayout and size negotiation
237 bool mLockSetSize; ///< Used to avoid. Can't be a bitfield as a reference to this member is used in SetSizeLock helper class.
239 Control::SizePolicy mWidthPolicy; ///< Stores the width policy.
240 Control::SizePolicy mHeightPolicy; ///< Stores the height policy.
242 Vector3 mSize; ///< Stores the current control's size.
243 Vector3 mSetSize; ///< Always stores the size set through the Actor's API. Useful when reset to the initial size is needed.
244 Vector3 mMinimumSize; ///< Stores the control's minimum size.
245 Vector3 mMaximumSize; ///< Stores the control's maximum size.
247 bool mIsKeyboardNavigationSupported; ///< Stores whether keyboard navigation is supported by the control.
248 bool mIsKeyboardFocusGroup; ///< Stores whether the control is a focus group.
250 Toolkit::Control::KeyEventSignalV2 mKeyEventSignalV2;
253 Control ControlImpl::New()
255 // Create the implementation, temporarily owned on stack
256 IntrusivePtr<ControlImpl> controlImpl = new ControlImpl( false );
258 // Pass ownership to handle
259 Control handle( *controlImpl );
261 // Second-phase init of the implementation
262 // This can only be done after the CustomActor connection has been made...
263 controlImpl->Initialize();
268 ControlImpl::~ControlImpl()
270 if( mImpl->mInitialized )
272 // Unregister only if control has been initialized.
273 Internal::StyleChangeProcessor::Unregister( this );
278 void ControlImpl::Initialize()
280 // Register with the style change processor so we are informed when the default style changes
281 Internal::StyleChangeProcessor::Register( this );
283 // Calling deriving classes
286 mImpl->mInitialized = true;
289 void ControlImpl::EnableGestureDetection(Gesture::Type type)
291 if ( (type & Gesture::Pinch) && !mImpl->mPinchGestureDetector )
293 mImpl->mPinchGestureDetector = PinchGestureDetector::New();
294 mImpl->mPinchGestureDetector.DetectedSignal().Connect(mImpl, &Impl::PinchDetected);
295 mImpl->mPinchGestureDetector.Attach(Self());
298 if ( (type & Gesture::Pan) && !mImpl->mPanGestureDetector )
300 mImpl->mPanGestureDetector = PanGestureDetector::New();
301 mImpl->mPanGestureDetector.DetectedSignal().Connect(mImpl, &Impl::PanDetected);
302 mImpl->mPanGestureDetector.Attach(Self());
305 if ( (type & Gesture::Tap) && !mImpl->mTapGestureDetector )
307 mImpl->mTapGestureDetector = TapGestureDetector::New();
308 mImpl->mTapGestureDetector.DetectedSignal().Connect(mImpl, &Impl::TapDetected);
309 mImpl->mTapGestureDetector.Attach(Self());
312 if ( (type & Gesture::LongPress) && !mImpl->mLongPressGestureDetector )
314 mImpl->mLongPressGestureDetector = LongPressGestureDetector::New();
315 mImpl->mLongPressGestureDetector.DetectedSignal().Connect(mImpl, &Impl::LongPressDetected);
316 mImpl->mLongPressGestureDetector.Attach(Self());
320 void ControlImpl::DisableGestureDetection(Gesture::Type type)
322 if ( (type & Gesture::Pinch) && mImpl->mPinchGestureDetector )
324 mImpl->mPinchGestureDetector.Detach(Self());
325 mImpl->mPinchGestureDetector.Reset();
328 if ( (type & Gesture::Pan) && mImpl->mPanGestureDetector )
330 mImpl->mPanGestureDetector.Detach(Self());
331 mImpl->mPanGestureDetector.Reset();
334 if ( (type & Gesture::Tap) && mImpl->mTapGestureDetector )
336 mImpl->mTapGestureDetector.Detach(Self());
337 mImpl->mTapGestureDetector.Reset();
340 if ( (type & Gesture::LongPress) && mImpl->mLongPressGestureDetector)
342 mImpl->mLongPressGestureDetector.Detach(Self());
343 mImpl->mLongPressGestureDetector.Reset();
347 PinchGestureDetector ControlImpl::GetPinchGestureDetector() const
349 return mImpl->mPinchGestureDetector;
352 PanGestureDetector ControlImpl::GetPanGestureDetector() const
354 return mImpl->mPanGestureDetector;
357 TapGestureDetector ControlImpl::GetTapGestureDetector() const
359 return mImpl->mTapGestureDetector;
362 LongPressGestureDetector ControlImpl::GetLongPressGestureDetector() const
364 return mImpl->mLongPressGestureDetector;
367 void ControlImpl::OnPinch(PinchGesture pinch)
369 if (pinch.state == Gesture::Started)
371 mImpl->mStartingPinchScale = Self().GetCurrentScale();
374 Self().SetScale(mImpl->mStartingPinchScale * pinch.scale);
377 void ControlImpl::OnStageConnection()
381 // Notify derived classes.
382 OnControlStageConnection();
385 void ControlImpl::OnStageDisconnection()
387 // Notify derived classes
388 OnControlStageDisconnection();
391 void ControlImpl::OnChildAdd(Actor& child)
393 // Request for relayout.
396 // Notify derived classes.
397 OnControlChildAdd( child );
400 void ControlImpl::OnChildRemove(Actor& child)
402 // Request for relayout.
405 // Notify derived classes.
406 OnControlChildRemove( child );
409 void ControlImpl::OnSizeSet(const Vector3& targetSize)
411 if( ( !mImpl->mLockSetSize ) && ( targetSize != mImpl->mSetSize ) )
413 // Only updates size if set through Actor's API
414 mImpl->mSetSize = targetSize;
417 if( targetSize != mImpl->mSize )
419 // Update control size.
420 mImpl->mSize = targetSize;
422 // Notify derived classes.
423 OnControlSizeSet( targetSize );
427 void ControlImpl::OnSizeAnimation(Animation& animation, const Vector3& targetSize)
432 bool ControlImpl::OnTouchEvent(const TouchEvent& event)
434 return false; // Do not consume
437 bool ControlImpl::OnKeyEvent(const KeyEvent& event)
439 return false; // Do not consume
442 bool ControlImpl::OnMouseWheelEvent(const MouseWheelEvent& event)
444 return false; // Do not consume
447 void ControlImpl::OnKeyInputFocusGained()
452 void ControlImpl::OnKeyInputFocusLost()
457 Actor ControlImpl::GetChildByAlias(const std::string& actorAlias)
462 bool ControlImpl::OnAccessibilityPan(PanGesture gesture)
464 return false; // Accessibility pan gesture is not handled by default
467 bool ControlImpl::OnAccessibilityValueChange(bool isIncrease)
469 return false; // Accessibility value change action is not handled by default
473 void ControlImpl::SetKeyboardNavigationSupport(bool isSupported)
475 mImpl->mIsKeyboardNavigationSupported = isSupported;
478 bool ControlImpl::IsKeyboardNavigationSupported()
480 return mImpl->mIsKeyboardNavigationSupported;
483 void ControlImpl::SetAsKeyboardFocusGroup(bool isFocusGroup)
485 mImpl->mIsKeyboardFocusGroup = isFocusGroup;
487 // The following line will be removed when the deprecated API in KeyboardFocusManager is deleted
488 KeyboardFocusManager::Get().SetAsFocusGroup(Self(), isFocusGroup);
491 bool ControlImpl::IsKeyboardFocusGroup()
493 return KeyboardFocusManager::Get().IsFocusGroup(Self());
496 Actor ControlImpl::GetNextKeyboardFocusableActor(Actor currentFocusedActor, Control::KeyboardFocusNavigationDirection direction, bool loopEnabled)
501 bool ControlImpl::DoAction(BaseObject* object, const std::string& actionName, const std::vector<Property::Value>& attributes)
508 void ControlImpl::DoActivatedAction(const PropertyValueContainer& attributes)
513 Toolkit::Control::KeyEventSignalV2& ControlImpl::KeyEventSignal()
515 return mImpl->mKeyEventSignalV2;
518 void ControlImpl::SetSizePolicy( Control::SizePolicy widthPolicy, Control::SizePolicy heightPolicy )
520 bool relayoutRequest( false );
522 if ( ( mImpl->mWidthPolicy != widthPolicy ) || ( mImpl->mHeightPolicy != heightPolicy ) )
524 relayoutRequest = true;
527 mImpl->mWidthPolicy = widthPolicy;
528 mImpl->mHeightPolicy = heightPolicy;
530 // Ensure RelayoutRequest is called AFTER new policies have been set.
531 if ( relayoutRequest )
537 void ControlImpl::GetSizePolicy( Control::SizePolicy& widthPolicy, Control::SizePolicy& heightPolicy ) const
539 widthPolicy = mImpl->mWidthPolicy;
540 heightPolicy = mImpl->mHeightPolicy;
543 void ControlImpl::SetMinimumSize( const Vector3& size )
545 if ( mImpl->mMinimumSize != size )
547 mImpl->mMinimumSize = size;
549 // Only relayout if our control is using the minimum or range policy.
550 if ( ( mImpl->mHeightPolicy == Control::Minimum ) || ( mImpl->mWidthPolicy == Control::Minimum ) ||
551 ( mImpl->mHeightPolicy == Control::Range ) || ( mImpl->mWidthPolicy == Control::Range ) )
558 const Vector3& ControlImpl::GetMinimumSize() const
560 return mImpl->mMinimumSize;
563 void ControlImpl::SetMaximumSize( const Vector3& size )
565 if ( mImpl->mMaximumSize != size )
567 mImpl->mMaximumSize = size;
569 // Only relayout if our control is using the maximum or range policy.
570 if ( ( mImpl->mHeightPolicy == Control::Maximum ) || ( mImpl->mWidthPolicy == Control::Maximum ) ||
571 ( mImpl->mHeightPolicy == Control::Range ) || ( mImpl->mWidthPolicy == Control::Range ) )
578 const Vector3& ControlImpl::GetMaximumSize() const
580 return mImpl->mMaximumSize;
583 Vector3 ControlImpl::GetNaturalSize()
585 // could be overridden in derived classes.
586 return mImpl->mSetSize;
589 float ControlImpl::GetHeightForWidth( float width )
591 // could be overridden in derived classes.
592 float height( 0.0f );
593 if ( mImpl->mSetSize.width > 0.0f )
595 height = mImpl->mSetSize.height * width / mImpl->mSetSize.width;
600 float ControlImpl::GetWidthForHeight( float height )
602 // could be overridden in derived classes.
604 if ( mImpl->mSetSize.height > 0.0f )
606 width = mImpl->mSetSize.width * height / mImpl->mSetSize.height;
611 const Vector3& ControlImpl::GetControlSize() const
616 const Vector3& ControlImpl::GetSizeSet() const
618 return mImpl->mSetSize;
621 void ControlImpl::SetKeyInputFocus()
623 if( Self().OnStage() )
625 KeyInputFocusManager::Get().SetFocus(Control::DownCast(Self()));
629 bool ControlImpl::HasKeyInputFocus()
632 if( Self().OnStage() )
634 result = KeyInputFocusManager::Get().IsKeyboardListener(Control::DownCast(Self()));
639 void ControlImpl::ClearKeyInputFocus()
641 if( Self().OnStage() )
643 KeyInputFocusManager::Get().RemoveFocus(Control::DownCast(Self()));
647 void ControlImpl::RelayoutRequest()
649 Internal::RelayoutController::Get().Request();
652 void ControlImpl::Relayout( Vector2 size, ActorSizeContainer& container )
654 // Avoids relayout again when OnSizeSet callback arrives.
656 SetSizeLock lock( mImpl->mLockSetSize );
657 Self().SetSize( size );
660 // Only relayout controls which requested to be relaid out.
661 OnRelaidOut( size, container );
664 void ControlImpl::Relayout( Actor actor, Vector2 size, ActorSizeContainer& container )
668 Control control( Control::DownCast( actor ) );
671 control.GetImplementation().NegotiateSize( size, container );
675 container.push_back( ActorSizePair( actor, size ) );
680 void ControlImpl::OnRelaidOut( Vector2 size, ActorSizeContainer& container )
682 unsigned int numChildren = Self().GetChildCount();
684 for( unsigned int i=0; i<numChildren; ++i )
686 container.push_back( ActorSizePair( Self().GetChildAt(i), size ) );
690 void ControlImpl::NegotiateSize( Vector2 allocatedSize, ActorSizeContainer& container )
694 if ( mImpl->mWidthPolicy == Control::Fixed )
696 if ( mImpl->mHeightPolicy == Control::Fixed )
698 // If a control says it has a fixed size, then use the size set by the application / control.
699 Vector2 setSize( mImpl->mSetSize );
700 if ( setSize != Vector2::ZERO )
704 // Policy is set to Fixed, so if the application / control has not set one of the dimensions,
705 // then we should use the natural size of the control rather than the full allocation.
706 if ( EqualsZero( size.width ) )
708 size.width = GetWidthForHeight( size.height );
710 else if ( EqualsZero( size.height ) )
712 size.height = GetHeightForWidth( size.width );
717 // If that is not set then set the size to the control's natural size
718 size = Vector2( GetNaturalSize() );
723 // Width is fixed so if the application / control has set it, then use that.
724 if ( !EqualsZero( mImpl->mSetSize.width ) )
726 size.width = mImpl->mSetSize.width;
730 // Otherwise, set the width to what has been allocated.
731 size.width = allocatedSize.width;
734 // Height is flexible so ask control what the height should be for our width.
735 size.height = GetHeightForWidth( size.width );
737 // Ensure height is within our policy rules
738 size.height = Calculate( mImpl->mHeightPolicy, mImpl->mMinimumSize.height, mImpl->mMaximumSize.height, size.height );
743 if ( mImpl->mHeightPolicy == Control::Fixed )
745 // Height is fixed so if the application / control has set it, then use that.
746 if ( !EqualsZero( mImpl->mSetSize.height ) )
748 size.height = mImpl->mSetSize.height;
752 // Otherwise, set the height to what has been allocated.
753 size.height = allocatedSize.height;
756 // Width is flexible so ask control what the width should be for our height.
757 size.width = GetWidthForHeight( size.height );
759 // Ensure width is within our policy rules
760 size.width = Calculate( mImpl->mWidthPolicy, mImpl->mMinimumSize.width, mImpl->mMaximumSize.width, size.width );
764 // Width and height are BOTH flexible.
765 // Calculate the width and height using the policy rules.
766 size.width = Calculate( mImpl->mWidthPolicy, mImpl->mMinimumSize.width, mImpl->mMaximumSize.width, allocatedSize.width );
767 size.height = Calculate( mImpl->mHeightPolicy, mImpl->mMinimumSize.height, mImpl->mMaximumSize.height, allocatedSize.height );
771 // If the width has not been set, then set to the allocated width.
772 // Also if the width set is greater than the allocated, then set to allocated (no exceed support).
773 if ( EqualsZero( size.width ) || ( size.width > allocatedSize.width ) )
775 size.width = allocatedSize.width;
778 // If the height has not been set, then set to the allocated height.
779 // Also if the height set is greater than the allocated, then set to allocated (no exceed support).
780 if ( EqualsZero( size.height ) || ( size.height > allocatedSize.height ) )
782 size.height = allocatedSize.height;
785 DALI_LOG_INFO( gLogFilter, Debug::Verbose,
786 "%p: Natural: [%.2f, %.2f] Allocated: [%.2f, %.2f] Set: [%.2f, %.2f]\n",
787 Self().GetObjectPtr(),
788 GetNaturalSize().x, GetNaturalSize().y,
789 allocatedSize.x, allocatedSize.y,
792 Relayout( size, container );
795 bool ControlImpl::EmitKeyEventSignal( const KeyEvent& event )
797 // Guard against destruction during signal emission
798 Dali::Toolkit::Control handle( GetOwner() );
800 bool consumed = false;
802 // signals are allocated dynamically when someone connects
803 if ( !mImpl->mKeyEventSignalV2.Empty() )
805 consumed = mImpl->mKeyEventSignalV2.Emit( handle, event );
810 // Notification for derived classes
811 consumed = OnKeyEvent(event);
817 void ControlImpl::SignalConnected( SlotObserver* slotObserver, CallbackBase* callback )
819 mImpl->SignalConnected( slotObserver, callback );
822 void ControlImpl::SignalDisconnected( SlotObserver* slotObserver, CallbackBase* callback )
824 mImpl->SignalDisconnected( slotObserver, callback );
827 std::size_t ControlImpl::GetConnectionCount() const
829 return mImpl->GetConnectionCount();
832 ControlImpl::ControlImpl( bool requiresTouchEvents )
833 : CustomActorImpl( requiresTouchEvents ),
834 mImpl(new Impl(*this))
838 } // namespace Toolkit