Merge "add base type of enum to reduce class size." into devel/master
authorDavid Steele <david.steele@samsung.com>
Mon, 19 Oct 2020 13:35:41 +0000 (13:35 +0000)
committerGerrit Code Review <gerrit@review>
Mon, 19 Oct 2020 13:35:41 +0000 (13:35 +0000)
34 files changed:
automated-tests/src/dali/utc-Dali-SignalTemplates.cpp
automated-tests/src/dali/utc-Dali-TouchProcessing.cpp [changed mode: 0644->0755]
automated-tests/src/dali/utc-Dali-Vector.cpp
dali/devel-api/actors/actor-devel.cpp [changed mode: 0644->0755]
dali/devel-api/actors/actor-devel.h [changed mode: 0644->0755]
dali/internal/event/actors/actor-impl.cpp [changed mode: 0644->0755]
dali/internal/event/actors/actor-impl.h [changed mode: 0644->0755]
dali/internal/event/events/touch-event-processor.cpp [changed mode: 0644->0755]
dali/internal/render/common/render-algorithms.cpp
dali/internal/update/animation/scene-graph-animation.cpp
dali/internal/update/animation/scene-graph-animation.h
dali/internal/update/manager/transform-manager.cpp
dali/internal/update/manager/transform-manager.h
dali/internal/update/manager/update-manager.cpp
dali/internal/update/manager/update-manager.h
dali/internal/update/rendering/scene-graph-renderer.cpp
dali/internal/update/rendering/scene-graph-renderer.h
dali/public-api/actors/custom-actor-impl.h
dali/public-api/actors/custom-actor.h
dali/public-api/animation/alpha-function.h
dali/public-api/animation/constraint.h
dali/public-api/common/dali-vector.h
dali/public-api/dali-core-version.cpp
dali/public-api/object/handle.h
dali/public-api/signals/base-signal.cpp
dali/public-api/signals/base-signal.h
dali/public-api/signals/callback.cpp
dali/public-api/signals/callback.h
dali/public-api/signals/connection-tracker.cpp
dali/public-api/signals/connection-tracker.h
dali/public-api/signals/dali-signal.h
dali/public-api/signals/signal-slot-connections.cpp
dali/public-api/signals/signal-slot-connections.h
packaging/dali.spec

index e612ccb..d3a03fc 100644 (file)
@@ -167,23 +167,16 @@ int UtcDaliSignalConnectP01(void)
 
 int UtcDaliSignalConnectN01(void)
 {
-  // difficult to perform a negative test on Connect as no checks are performed
-  // when creating a callback for a null function ( during Connect).
-  // so we test an assert on Emit
   TestApplication application; // Create core for debug logging
 
   TestSignals::VoidRetNoParamSignal signal;
-  signal.Connect(NULL);
-  try
-  {
-    signal.Emit();
-  }
-  catch(Dali::DaliException& e)
-  {
-    // Tests that a negative test of an assertion succeeds
-    DALI_TEST_PRINT_ASSERT(e);
-    tet_result(TET_PASS);
-  }
+  signal.Connect(nullptr);
+  signal.Emit();
+
+  // No assert occurs any more - the callback is silently ignored.
+  // If we execute this code, then the test case didn't crash.
+  tet_result(TET_PASS);
+
   END_TEST;
 }
 
old mode 100644 (file)
new mode 100755 (executable)
index 2aaf3e2..3c01346
@@ -2068,3 +2068,56 @@ int UtcDaliTouchEventIntegNewTouchEvent(void)
 
   END_TEST;
 }
+
+
+int UtcDaliTouchEventIntercept(void)
+{
+  TestApplication application;
+
+  Actor parent = Actor::New();
+  parent.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f));
+  parent.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+  application.GetScene().Add(parent);
+
+  Actor actor = Actor::New();
+  actor.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f));
+  actor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+  parent.Add(actor);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Connect to actor's touched signal
+  SignalData        data;
+  TouchEventFunctor functor(data, false /* Do not consume */);
+  actor.TouchedSignal().Connect(&application, functor);
+
+
+  // Connect to parent's touched signal
+  SignalData        parentData;
+  TouchEventFunctor parentFunctor(parentData, false /* Do not consume */);
+  parent.TouchedSignal().Connect(&application, parentFunctor);
+  // Connect to parent's intercept touched signal
+  SignalData        interceptData;
+  TouchEventFunctor interceptFunctor(interceptData, true /* Do intercept */);
+  Dali::DevelActor::InterceptTouchedSignal(parent).Connect(&application, interceptFunctor);
+
+  // Emit a down signal
+  application.ProcessEvent(GenerateSingleTouch(PointState::DOWN, Vector2(10.0f, 10.0f)));
+  // The actor touched signal is not called because the touch is intercepted in the parent.
+  DALI_TEST_EQUALS(false, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(true, interceptData.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::DOWN, interceptData.receivedTouch.points[0].state, TEST_LOCATION);
+  DALI_TEST_CHECK(actor == interceptData.receivedTouch.points[0].hitActor);
+  DALI_TEST_CHECK(parent == interceptData.touchedActor);
+  DALI_TEST_EQUALS(true, parentData.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::DOWN, parentData.receivedTouch.points[0].state, TEST_LOCATION);
+  DALI_TEST_CHECK(actor == parentData.receivedTouch.points[0].hitActor);
+  DALI_TEST_CHECK(parent == parentData.touchedActor);
+  data.Reset();
+  parentData.Reset();
+
+  END_TEST;
+}
+
index f0dd410..7616cc0 100644 (file)
@@ -1389,6 +1389,108 @@ int UtcDaliVectorMoveAssignment(void)
   END_TEST;
 }
 
+int UtcDaliVectorEraseFreeFunction(void)
+{
+  tet_infoline("Testing Dali::Erase<Vector<int>>");
+
+  Vector<int> vector;
+
+  // erasing from empty vector
+  Dali::Erase(vector, 2);
+  DALI_TEST_EQUALS(ZERO, vector.Count(), TEST_LOCATION);
+  DALI_TEST_EQUALS(ZERO, vector.Capacity(), TEST_LOCATION);
+
+
+  vector.PushBack(1);
+  vector.PushBack(2);
+  vector.PushBack(3);
+  vector.PushBack(4);
+  vector.PushBack(5);
+  vector.PushBack(3);
+
+  // erase multiple value
+  Dali::Erase(vector, 3);
+  DALI_TEST_EQUALS(static_cast<Dali::VectorBase::SizeType>(4), vector.Count(), TEST_LOCATION);
+
+  DALI_TEST_EQUALS(vector[0], 1, TEST_LOCATION);
+  DALI_TEST_EQUALS(vector[1], 2, TEST_LOCATION);
+  DALI_TEST_EQUALS(vector[2], 4, TEST_LOCATION);
+  DALI_TEST_EQUALS(vector[3], 5, TEST_LOCATION);
+
+
+  // erase an element present at start
+  Dali::Erase(vector, 1);
+  DALI_TEST_EQUALS(static_cast<Dali::VectorBase::SizeType>(3), vector.Count(), TEST_LOCATION);
+  DALI_TEST_EQUALS(vector[0], 2, TEST_LOCATION);
+  DALI_TEST_EQUALS(vector[1], 4, TEST_LOCATION);
+  DALI_TEST_EQUALS(vector[2], 5, TEST_LOCATION);
+
+  // erase an element present at end
+  Dali::Erase(vector, 5);
+  DALI_TEST_EQUALS(static_cast<Dali::VectorBase::SizeType>(2), vector.Count(), TEST_LOCATION);
+  DALI_TEST_EQUALS(vector[0], 2, TEST_LOCATION);
+  DALI_TEST_EQUALS(vector[1], 4, TEST_LOCATION);
+
+  // erase an element not present in the vector
+  Dali::Erase(vector, 42);
+  DALI_TEST_EQUALS(static_cast<Dali::VectorBase::SizeType>(2), vector.Count(), TEST_LOCATION);
+  DALI_TEST_EQUALS(vector[0], 2, TEST_LOCATION);
+  DALI_TEST_EQUALS(vector[1], 4, TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliVectorEraseIfFreeFunction(void)
+{
+  tet_infoline("Testing Dali::EraseIf<Vector<int>>");
+
+  Vector<int> vector;
+
+  // erasing from empty vector
+  Dali::EraseIf(vector, [](const auto & value) {return value == 2;});
+  DALI_TEST_EQUALS(ZERO, vector.Count(), TEST_LOCATION);
+  DALI_TEST_EQUALS(ZERO, vector.Capacity(), TEST_LOCATION);
+
+
+  vector.PushBack(1);
+  vector.PushBack(2);
+  vector.PushBack(3);
+  vector.PushBack(4);
+  vector.PushBack(5);
+  vector.PushBack(3);
+
+  // erase multiple value
+  Dali::EraseIf(vector, [](const auto & value) {return value == 3;});
+  DALI_TEST_EQUALS(static_cast<Dali::VectorBase::SizeType>(4), vector.Count(), TEST_LOCATION);
+
+  DALI_TEST_EQUALS(vector[0], 1, TEST_LOCATION);
+  DALI_TEST_EQUALS(vector[1], 2, TEST_LOCATION);
+  DALI_TEST_EQUALS(vector[2], 4, TEST_LOCATION);
+  DALI_TEST_EQUALS(vector[3], 5, TEST_LOCATION);
+
+
+  // erase an element present at start
+  Dali::EraseIf(vector, [](const auto & value) {return value == 1;});
+  DALI_TEST_EQUALS(static_cast<Dali::VectorBase::SizeType>(3), vector.Count(), TEST_LOCATION);
+  DALI_TEST_EQUALS(vector[0], 2, TEST_LOCATION);
+  DALI_TEST_EQUALS(vector[1], 4, TEST_LOCATION);
+  DALI_TEST_EQUALS(vector[2], 5, TEST_LOCATION);
+
+  // erase an element present at end
+  Dali::EraseIf(vector, [](const auto & value) {return value == 5;});
+  DALI_TEST_EQUALS(static_cast<Dali::VectorBase::SizeType>(2), vector.Count(), TEST_LOCATION);
+  DALI_TEST_EQUALS(vector[0], 2, TEST_LOCATION);
+  DALI_TEST_EQUALS(vector[1], 4, TEST_LOCATION);
+
+  // erase an element not present in the vector
+  Dali::EraseIf(vector, [](const auto & value) {return value == 42;});
+  DALI_TEST_EQUALS(static_cast<Dali::VectorBase::SizeType>(2), vector.Count(), TEST_LOCATION);
+  DALI_TEST_EQUALS(vector[0], 2, TEST_LOCATION);
+  DALI_TEST_EQUALS(vector[1], 4, TEST_LOCATION);
+
+  END_TEST;
+}
+
 /*
  * this does not compile at the moment
  * Vector< Actor > classvector; this does not compile yet either
old mode 100644 (file)
new mode 100755 (executable)
index 68a5205..fd08434
@@ -48,6 +48,11 @@ ChildOrderChangedSignalType& ChildOrderChangedSignal(Actor actor)
   return GetImplementation(actor).ChildOrderChangedSignal();
 }
 
+Actor::TouchEventSignalType& InterceptTouchedSignal(Actor actor)
+{
+  return GetImplementation(actor).InterceptTouchedSignal();
+}
+
 } // namespace DevelActor
 
 } // namespace Dali
old mode 100644 (file)
new mode 100755 (executable)
index 43b44f7..cda374f
@@ -215,6 +215,40 @@ using ChildOrderChangedSignalType = Signal<void(Actor)>; ///< Used when the acto
  */
 DALI_CORE_API ChildOrderChangedSignalType& ChildOrderChangedSignal(Actor actor);
 
+/**
+ * @brief This signal is emitted when intercepting the actor's touch event.
+ *
+ * A callback of the following type may be connected:
+ * @code
+ *   void MyCallbackName( Actor actor );
+ * @endcode
+ * actor The actor to intercept
+ *
+ * @note TouchEvent callbacks are called from the last child in the order of the parent's actor.
+ * The InterceptTouchEvent callback is to intercept the touch event in the parent.
+ * So, if the parent interepts the touch event, the child cannot receive the touch event.
+ *
+ * @note example
+ *   Actor parent = Actor::New();
+ *   Actor child = Actor::New();
+ *   parent.Add(child);
+ *   child.TouchedSignal().Connect(&application, childFunctor);
+ *   parent.TouchedSignal().Connect(&application, parentFunctor);
+ * The touch event callbacks are called in the order childFunctor -> parentFunctor.
+ *
+ * If you connect interceptTouchSignal to parentActor.
+ *   Dali::DevelActor::InterceptTouchedSignal(parent).Connect(&application, interceptFunctor);
+ *
+ * When interceptFunctor returns false, the touch event callbacks are called in the same order childFunctor -> parentFunctor.
+ * If interceptFunctor returns true, it means that the TouchEvent was intercepted.
+ * So the child actor will not be able to receive touch events.
+ * Only the parentFunctor is called.
+ *
+ * @return The signal to connect to
+ * @pre The Actor has been initialized
+ */
+DALI_CORE_API Actor::TouchEventSignalType& InterceptTouchedSignal(Actor actor);
+
 } // namespace DevelActor
 
 } // namespace Dali
old mode 100644 (file)
new mode 100755 (executable)
index 321b111..4fdf0c2
@@ -836,6 +836,8 @@ void Actor::SetOpacity( float opacity )
 
   // node is being used in a separate thread; queue a message to set the value & base value
   SceneGraph::NodePropertyComponentMessage<Vector4>::Send( GetEventThreadServices(), &GetNode(), &GetNode().mColor, &AnimatableProperty<Vector4>::BakeW, opacity );
+
+  RequestRenderingMessage( GetEventThreadServices().GetUpdateManager() );
 }
 
 float Actor::GetCurrentOpacity() const
@@ -855,6 +857,8 @@ void Actor::SetColor( const Vector4& color )
 
   // node is being used in a separate thread; queue a message to set the value & base value
   SceneGraph::NodePropertyMessage<Vector4>::Send( GetEventThreadServices(), &GetNode(), &GetNode().mColor, &AnimatableProperty<Vector4>::Bake, color );
+
+  RequestRenderingMessage( GetEventThreadServices().GetUpdateManager() );
 }
 
 void Actor::SetColorRed( float red )
@@ -863,6 +867,8 @@ void Actor::SetColorRed( float red )
 
   // node is being used in a separate thread; queue a message to set the value & base value
   SceneGraph::NodePropertyComponentMessage<Vector4>::Send( GetEventThreadServices(), &GetNode(), &GetNode().mColor, &AnimatableProperty<Vector4>::BakeX, red );
+
+  RequestRenderingMessage( GetEventThreadServices().GetUpdateManager() );
 }
 
 void Actor::SetColorGreen( float green )
@@ -871,6 +877,8 @@ void Actor::SetColorGreen( float green )
 
   // node is being used in a separate thread; queue a message to set the value & base value
   SceneGraph::NodePropertyComponentMessage<Vector4>::Send( GetEventThreadServices(), &GetNode(), &GetNode().mColor, &AnimatableProperty<Vector4>::BakeY, green );
+
+  RequestRenderingMessage( GetEventThreadServices().GetUpdateManager() );
 }
 
 void Actor::SetColorBlue( float blue )
@@ -879,6 +887,8 @@ void Actor::SetColorBlue( float blue )
 
   // node is being used in a separate thread; queue a message to set the value & base value
   SceneGraph::NodePropertyComponentMessage<Vector4>::Send( GetEventThreadServices(), &GetNode(), &GetNode().mColor, &AnimatableProperty<Vector4>::BakeZ, blue );
+
+  RequestRenderingMessage( GetEventThreadServices().GetUpdateManager() );
 }
 
 const Vector4& Actor::GetCurrentColor() const
@@ -1319,6 +1329,11 @@ bool Actor::IsGestureRequired( GestureType::Value type ) const
   return mGestureData && mGestureData->IsGestureRequired( type );
 }
 
+bool Actor::EmitInterceptTouchEventSignal( const Dali::TouchEvent& touch )
+{
+  return EmitConsumingSignal( *this, mInterceptTouchedSignal, touch );
+}
+
 bool Actor::EmitTouchEventSignal( const Dali::TouchEvent& touch )
 {
   return EmitConsumingSignal( *this, mTouchedSignal, touch );
@@ -1418,6 +1433,7 @@ Actor::Actor( DerivedType derivedType, const SceneGraph::Node& node )
   mAnchorPoint( nullptr ),
   mRelayoutData( nullptr ),
   mGestureData( nullptr ),
+  mInterceptTouchedSignal(),
   mTouchedSignal(),
   mHoveredSignal(),
   mWheelEventSignal(),
@@ -2492,6 +2508,8 @@ void Actor::SetVisibleInternal( bool visible, SendMessage::Type sendMessage )
     {
       // node is being used in a separate thread; queue a message to set the value & base value
       SceneGraph::NodePropertyMessage<bool>::Send( GetEventThreadServices(), &GetNode(), &GetNode().mVisible, &AnimatableProperty<bool>::Bake, visible );
+
+      RequestRenderingMessage( GetEventThreadServices().GetUpdateManager() );
     }
 
     mVisible = visible;
old mode 100644 (file)
new mode 100755 (executable)
index 5a11cd0..a982904
@@ -1326,6 +1326,16 @@ public:
     return mKeyboardFocusable;
   }
 
+
+  /**
+   * Query whether the application or derived actor type requires intercept touch events.
+   * @return True if intercept touch events are required.
+   */
+  bool GetInterceptTouchRequired() const
+  {
+    return !mInterceptTouchedSignal.Empty();
+  }
+
   /**
    * Query whether the application or derived actor type requires touch events.
    * @return True if touch events are required.
@@ -1394,6 +1404,13 @@ public:
   // Signals
 
   /**
+   * Used by the EventProcessor to emit intercept touch event signals.
+   * @param[in] touch The touch data.
+   * @return True if the event was intercepted.
+   */
+  bool EmitInterceptTouchEventSignal( const Dali::TouchEvent& touch );
+
+  /**
    * Used by the EventProcessor to emit touch event signals.
    * @param[in] touch The touch data.
    * @return True if the event was consumed.
@@ -1440,6 +1457,14 @@ public:
   void EmitChildRemovedSignal( Actor& child );
 
   /**
+   * @copydoc DevelActor::InterceptTouchedSignal()
+   */
+  Dali::Actor::TouchEventSignalType& InterceptTouchedSignal()
+  {
+    return mInterceptTouchedSignal;
+  }
+
+  /**
    * @copydoc Dali::Actor::TouchedSignal()
    */
   Dali::Actor::TouchEventSignalType& TouchedSignal()
@@ -1982,6 +2007,7 @@ protected:
   ActorGestureData* mGestureData;   ///< Optional Gesture data. Only created when actor requires gestures
 
   // Signals
+  Dali::Actor::TouchEventSignalType         mInterceptTouchedSignal;
   Dali::Actor::TouchEventSignalType        mTouchedSignal;
   Dali::Actor::HoverSignalType             mHoveredSignal;
   Dali::Actor::WheelEventSignalType        mWheelEventSignal;
old mode 100644 (file)
new mode 100755 (executable)
index 864ce8c..146387c
@@ -60,6 +60,36 @@ const char * TOUCH_POINT_STATE[ 6 ] =
 
 #endif // defined(DEBUG_ENABLED)
 
+Dali::Actor EmitInterceptTouchSignals( Dali::Actor actor, const Dali::TouchEvent& touchEvent )
+{
+  Dali::Actor interceptedActor;
+
+  if( actor )
+  {
+     Dali::Actor parent = actor.GetParent();
+     if( parent )
+     {
+       // Recursively deliver events to the actor and its parents for intercept touch event.
+       interceptedActor = EmitInterceptTouchSignals( parent, touchEvent );
+     }
+
+     if( !interceptedActor )
+     {
+       bool intercepted = false;
+       Actor& actorImpl( GetImplementation(actor) );
+       if( actorImpl.GetInterceptTouchRequired() )
+       {
+          intercepted = actorImpl.EmitInterceptTouchEventSignal( touchEvent );
+          if( intercepted )
+          {
+            interceptedActor = Dali::Actor( &actorImpl );
+          }
+       }
+     }
+  }
+
+  return interceptedActor;
+}
 
 /**
  *  Recursively deliver events to the actor and its parents, until the event is consumed or the stage is reached.
@@ -315,7 +345,16 @@ bool TouchEventProcessor::ProcessTouchEvent( const Integration::TouchEvent& even
   Dali::Actor consumedActor;
   if ( currentRenderTask )
   {
-    consumedActor = EmitTouchSignals( touchEventImpl->GetPoint( 0 ).GetHitActor(), touchEventHandle );
+    // Emit the intercept touch signal
+    Dali::Actor interceptedActor = EmitInterceptTouchSignals( touchEventImpl->GetPoint( 0 ).GetHitActor(), touchEventHandle );
+    if( interceptedActor )
+    {
+      consumedActor = EmitTouchSignals( interceptedActor, touchEventHandle );
+    }
+    else
+    {
+      consumedActor = EmitTouchSignals( touchEventImpl->GetPoint( 0 ).GetHitActor(), touchEventHandle );
+    }
     consumed = consumedActor ? true : false;
   }
 
index f5d540c..d40614c 100755 (executable)
@@ -442,6 +442,22 @@ inline void RenderAlgorithms::ProcessRenderList( const RenderList& renderList,
   {
     const RenderItem& item = renderList.GetItem( index );
 
+    // Discard renderers outside the root clipping rect
+    bool skip = true;
+    if( !rootClippingRect.IsEmpty() )
+    {
+      auto rect = item.CalculateViewportSpaceAABB( item.mUpdateSize, mViewportRectangle.width, mViewportRectangle.height );
+
+      if(rect.Intersect( rootClippingRect ))
+      {
+        skip = false;
+      }
+    }
+    else
+    {
+      skip = false;
+    }
+
     DALI_PRINT_RENDER_ITEM( item );
 
     // Set up clipping based on both the Renderer and Actor APIs.
@@ -455,9 +471,9 @@ inline void RenderAlgorithms::ProcessRenderList( const RenderList& renderList,
       // draw-mode state, such as Overlays.
       // If the flags are set to "AUTO", the behavior then depends on the type of renderer. Overlay Renderers will always
       // disable depth testing and writing. Color Renderers will enable them if the Layer does.
-      if( depthBufferAvailable == Integration::DepthBufferAvailable::TRUE )
+      if (depthBufferAvailable == Integration::DepthBufferAvailable::TRUE)
       {
-        SetupDepthBuffer( item, context, autoDepthTestMode, firstDepthBufferUse );
+        SetupDepthBuffer(item, context, autoDepthTestMode, firstDepthBufferUse);
       }
 
       // Depending on whether the renderer has draw commands attached or not the rendering process will
@@ -465,12 +481,15 @@ inline void RenderAlgorithms::ProcessRenderList( const RenderList& renderList,
       // iteration must be done and the default behaviour of the renderer will be executed.
       // The queues allow to iterate over the same renderer multiple times changing the state of the renderer.
       // It is similar to the multi-pass rendering.
-      auto const MAX_QUEUE = item.mRenderer->GetDrawCommands().empty() ? 1 : DevelRenderer::RENDER_QUEUE_MAX;
-      for( auto queue = 0u; queue < MAX_QUEUE; ++queue )
+      if( !skip )
       {
-        // Render the item.
-        item.mRenderer->Render(context, bufferIndex, *item.mNode, item.mModelMatrix, item.mModelViewMatrix,
-                               viewMatrix, projectionMatrix, item.mSize, !item.mIsOpaque, boundTextures, instruction, queue);
+        auto const MAX_QUEUE = item.mRenderer->GetDrawCommands().empty() ? 1 : DevelRenderer::RENDER_QUEUE_MAX;
+        for (auto queue = 0u; queue < MAX_QUEUE; ++queue)
+        {
+          // Render the item.
+          item.mRenderer->Render(context, bufferIndex, *item.mNode, item.mModelMatrix, item.mModelViewMatrix,
+                                 viewMatrix, projectionMatrix, item.mSize, !item.mIsOpaque, boundTextures, instruction, queue);
+        }
       }
     }
   }
index f0d961d..bd4656f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -78,7 +78,8 @@ Animation::Animation( float durationSeconds, float speedFactor, const Vector2& p
   mDisconnectAction(disconnectAction),
   mState(Stopped),
   mProgressReachedSignalRequired( false ),
-  mAutoReverseEnabled( false )
+  mAutoReverseEnabled( false ),
+  mIsActive{ false }
 {
 }
 
@@ -426,6 +427,8 @@ void Animation::Update( BufferIndex bufferIndex, float elapsedSeconds, bool& loo
 
 void Animation::UpdateAnimators( BufferIndex bufferIndex, bool bake, bool animationFinished )
 {
+  mIsActive[bufferIndex] = false;
+
   const Vector2 playRange( mPlayRange * mDurationSeconds );
   float elapsedSecondsClamped = Clamp( mElapsedSeconds, playRange.x, playRange.y );
 
@@ -456,6 +459,11 @@ void Animation::UpdateAnimators( BufferIndex bufferIndex, bool bake, bool animat
             progress = Clamp((elapsedSecondsClamped - intervalDelay) / animatorDuration, 0.0f , 1.0f );
           }
           animator->Update(bufferIndex, progress, bake);
+
+          if (animatorDuration > 0.0f && (elapsedSecondsClamped - intervalDelay) <= animatorDuration)
+          {
+            mIsActive[bufferIndex] = true;
+          }
         }
         applied = true;
       }
index a4e309f..0617041 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_INTERNAL_SCENE_GRAPH_ANIMATION_H
 
 /*
- * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -259,6 +259,16 @@ public:
   }
 
   /**
+   * Query whether the animation is currently active (i.e. at least one of the animators has been updated in either frame)
+   * @return True if the animation is currently active
+   */
+  bool IsActive() const
+  {
+    // As we have double buffering, if animator is updated in either frame, it needs to be rendered.
+    return mIsActive[0] || mIsActive[1];
+  }
+
+  /**
    * @brief Sets the looping mode.
    *
    * Animation plays forwards and then restarts from the beginning or runs backwards again.
@@ -349,6 +359,7 @@ protected:
 
   bool mProgressReachedSignalRequired;  // Flag to indicate the progress marker was hit
   bool mAutoReverseEnabled;             // Flag to identify that the looping mode is auto reverse.
+  bool mIsActive[2];                    // Flag to indicate whether the animation is active in the current frame (which is double buffered)
 };
 
 }; //namespace SceneGraph
index c2cc4bb..7951e32 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -229,8 +229,10 @@ void TransformManager::ResetToBaseValue()
   }
 }
 
-void TransformManager::Update()
+bool TransformManager::Update()
 {
+  bool componentsChanged = false;
+
   if( mReorder )
   {
     //If some transform component has change its parent or has been removed since last update
@@ -322,8 +324,11 @@ void TransformManager::Update()
     mBoundingSpheres[i] = mWorld[i].GetTranslation();
     mBoundingSpheres[i].w = Length( centerToEdgeWorldSpace );
 
+    componentsChanged = componentsChanged || mComponentDirty[i];
     mComponentDirty[i] = false;
   }
+
+  return componentsChanged;
 }
 
 void TransformManager::SwapComponents( unsigned int i, unsigned int j )
@@ -382,31 +387,26 @@ Vector3& TransformManager::GetVector3PropertyValue( TransformId id, TransformMan
     case TRANSFORM_PROPERTY_POSITION:
     {
       TransformId index( mIds[id] );
-      mComponentDirty[ index ] = true;
       return mTxComponentAnimatable[ index ].mPosition;
     }
     case TRANSFORM_PROPERTY_SCALE:
     {
       TransformId index( mIds[id] );
-      mComponentDirty[ index ] = true;
       return mTxComponentAnimatable[ index ].mScale;
     }
     case TRANSFORM_PROPERTY_PARENT_ORIGIN:
     {
       TransformId index( mIds[id] );
-      mComponentDirty[ index ] = true;
       return mTxComponentStatic[ index ].mParentOrigin;
     }
     case TRANSFORM_PROPERTY_ANCHOR_POINT:
     {
       TransformId index( mIds[id] );
-      mComponentDirty[ index ] = true;
       return mTxComponentStatic[ index ].mAnchorPoint;
     }
     case TRANSFORM_PROPERTY_SIZE:
     {
       TransformId index( mIds[id] );
-      mComponentDirty[ index ] = true;
       return mSize[ index ];
     }
     default:
@@ -835,7 +835,6 @@ void TransformManager::BakeZVector3PropertyValue( TransformId id, TransformManag
 Quaternion& TransformManager::GetQuaternionPropertyValue( TransformId id )
 {
   TransformId index( mIds[id] );
-  mComponentDirty[ index ] = true;
   return mTxComponentAnimatable[ index ].mOrientation;
 }
 
index d003f57..068c39f 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_INTERNAL_TRANSFORM_MANAGER_H
 
 /*
- * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -192,8 +192,9 @@ public:
 
   /**
    * Recomputes all world transform matrices
+   * @return true if any component has been changed in this frame, false otherwise
    */
-  void Update();
+  bool Update();
 
   /**
    * Resets all the animatable properties to its base value
index 58fb0bc..a7ca327 100644 (file)
@@ -189,7 +189,8 @@ struct UpdateManager::Impl
     previousUpdateScene( false ),
     renderTaskWaiting( false ),
     renderersAdded( false ),
-    surfaceRectChanged( false )
+    surfaceRectChanged( false ),
+    renderingRequired( false )
   {
     sceneController = new SceneControllerImpl( renderMessageDispatcher, renderQueue, discardQueue );
 
@@ -298,6 +299,7 @@ struct UpdateManager::Impl
   bool                                 renderTaskWaiting;             ///< A REFRESH_ONCE render task is waiting to be rendered
   bool                                 renderersAdded;                ///< Flag to keep track when renderers have been added to avoid unnecessary processing
   bool                                 surfaceRectChanged;            ///< True if the default surface rect is changed
+  bool                                 renderingRequired;             ///< True if required to render the current frame
 
 private:
 
@@ -734,8 +736,10 @@ bool UpdateManager::ProcessGestures( BufferIndex bufferIndex, uint32_t lastVSync
   return gestureUpdated;
 }
 
-void UpdateManager::Animate( BufferIndex bufferIndex, float elapsedSeconds )
+bool UpdateManager::Animate( BufferIndex bufferIndex, float elapsedSeconds )
 {
+  bool animationActive = false;
+
   auto&& iter = mImpl->animations.Begin();
   bool animationLooped = false;
 
@@ -747,6 +751,8 @@ void UpdateManager::Animate( BufferIndex bufferIndex, float elapsedSeconds )
     bool progressMarkerReached = false;
     animation->Update( bufferIndex, elapsedSeconds, looped, finished, progressMarkerReached );
 
+    animationActive = animationActive || animation->IsActive();
+
     if ( progressMarkerReached )
     {
       mImpl->notificationManager.QueueMessage( Internal::NotifyProgressReachedMessage( mImpl->animationPlaylist, animation ) );
@@ -772,6 +778,8 @@ void UpdateManager::Animate( BufferIndex bufferIndex, float elapsedSeconds )
     // The application should be notified by NotificationManager, in another thread
     mImpl->notificationManager.QueueCompleteNotification( &mImpl->animationPlaylist );
   }
+
+  return animationActive;
 }
 
 void UpdateManager::ConstrainCustomObjects( BufferIndex bufferIndex )
@@ -852,7 +860,7 @@ void UpdateManager::UpdateRenderers( BufferIndex bufferIndex )
     //Apply constraints
     ConstrainPropertyOwner( *renderer, bufferIndex );
 
-    renderer->PrepareRender( bufferIndex );
+    mImpl->renderingRequired = renderer->PrepareRender( bufferIndex ) || mImpl->renderingRequired;
   }
 }
 
@@ -884,17 +892,20 @@ uint32_t UpdateManager::Update( float elapsedSeconds,
   //Clear nodes/resources which were previously discarded
   mImpl->discardQueue.Clear( bufferIndex );
 
+  bool isAnimationRunning = IsAnimationRunning();
+
   //Process Touches & Gestures
   const bool gestureUpdated = ProcessGestures( bufferIndex, lastVSyncTimeMilliseconds, nextVSyncTimeMilliseconds );
 
   bool updateScene = // The scene-graph requires an update if..
       (mImpl->nodeDirtyFlags & RenderableUpdateFlags) ||    // ..nodes were dirty in previous frame OR
-      IsAnimationRunning()                            ||    // ..at least one animation is running OR
+      isAnimationRunning                              ||    // ..at least one animation is running OR
       mImpl->messageQueue.IsSceneUpdateRequired()     ||    // ..a message that modifies the scene graph node tree is queued OR
       mImpl->frameCallbackProcessor                   ||    // ..a frame callback processor is existed OR
       gestureUpdated;                                       // ..a gesture property was updated
 
   bool keepRendererRendering = false;
+  mImpl->renderingRequired = false;
 
   // Although the scene-graph may not require an update, we still need to synchronize double-buffered
   // values if the scene was updated in the previous frame.
@@ -919,7 +930,7 @@ uint32_t UpdateManager::Update( float elapsedSeconds,
   if( updateScene || mImpl->previousUpdateScene )
   {
     //Animate
-    Animate( bufferIndex, elapsedSeconds );
+    bool animationActive = Animate( bufferIndex, elapsedSeconds );
 
     //Constraint custom objects
     ConstrainCustomObjects( bufferIndex );
@@ -957,7 +968,10 @@ uint32_t UpdateManager::Update( float elapsedSeconds,
     UpdateRenderers( bufferIndex );
 
     //Update the transformations of all the nodes
-    mImpl->transformManager.Update();
+    if ( mImpl->transformManager.Update() )
+    {
+      mImpl->nodeDirtyFlags |= NodePropertyFlags::TRANSFORM;
+    }
 
     //Process Property Notifications
     ProcessPropertyNotifications( bufferIndex );
@@ -982,7 +996,6 @@ uint32_t UpdateManager::Update( float elapsedSeconds,
         }
       }
 
-
       std::size_t numberOfRenderInstructions = 0;
       for ( auto&& scene : mImpl->scenes )
       {
@@ -991,13 +1004,19 @@ uint32_t UpdateManager::Update( float elapsedSeconds,
           scene->scene->GetRenderInstructions().ResetAndReserve( bufferIndex,
                                                      static_cast<uint32_t>( scene->taskList->GetTasks().Count() ) );
 
-          keepRendererRendering |= mImpl->renderTaskProcessor.Process( bufferIndex,
-                                              *scene->taskList,
-                                              *scene->root,
-                                              scene->sortedLayerList,
-                                              scene->scene->GetRenderInstructions(),
-                                              renderToFboEnabled,
-                                              isRenderingToFbo );
+          // If there are animations running, only add render instruction if at least one animation is currently active (i.e. not delayed)
+          // or the nodes are dirty
+          if ( !isAnimationRunning || animationActive || mImpl->renderingRequired || (mImpl->nodeDirtyFlags & RenderableUpdateFlags) )
+          {
+            keepRendererRendering |= mImpl->renderTaskProcessor.Process( bufferIndex,
+                                                *scene->taskList,
+                                                *scene->root,
+                                                scene->sortedLayerList,
+                                                scene->scene->GetRenderInstructions(),
+                                                renderToFboEnabled,
+                                                isRenderingToFbo );
+
+          }
 
           numberOfRenderInstructions += scene->scene->GetRenderInstructions().Count( bufferIndex );
         }
@@ -1139,6 +1158,11 @@ void UpdateManager::SetRenderingBehavior( DevelStage::Rendering renderingBehavio
   mImpl->renderingBehavior = renderingBehavior;
 }
 
+void UpdateManager::RequestRendering()
+{
+  mImpl->renderingRequired = true;
+}
+
 void UpdateManager::SetLayerDepths( const SortedLayerPointers& layers, const Layer* rootLayer )
 {
   for ( auto&& scene : mImpl->scenes )
index bf5d3e4..3368970 100644 (file)
@@ -646,6 +646,14 @@ public:
   void SetRenderingBehavior( DevelStage::Rendering renderingBehavior );
 
   /**
+   * Request to render the current frame
+   * @note This is a temporary workaround (to be removed in the future) to request the rendering of
+   *       the current frame if the color or visibility of any actor is updated. It MUST NOT be used
+   *       for any other purposes.
+   */
+  void RequestRendering();
+
+  /**
    * Sets the depths of all layers.
    * @param layers The layers in depth order.
    * @param[in] rootLayer The root layer of the sorted layers.
@@ -711,8 +719,9 @@ private:
    * Perform animation updates
    * @param[in] bufferIndex to use
    * @param[in] elapsedSeconds time since last frame
+   * @return true if at least one animations is currently active or false otherwise
    */
-  void Animate( BufferIndex bufferIndex, float elapsedSeconds );
+  bool Animate( BufferIndex bufferIndex, float elapsedSeconds );
 
   /**
    * Applies constraints to CustomObjects
@@ -1110,6 +1119,17 @@ inline void SetRenderingBehaviorMessage( UpdateManager& manager, DevelStage::Ren
   new (slot) LocalType( &manager, &UpdateManager::SetRenderingBehavior, renderingBehavior );
 }
 
+inline void RequestRenderingMessage( UpdateManager& manager )
+{
+  using LocalType = Message<UpdateManager>;
+
+  // Reserve some memory inside the message queue
+  uint32_t* slot = manager.ReserveMessageSlot( sizeof( LocalType ) );
+
+  // Construct message in the message queue memory; note that delete should not be called on the return value
+  new (slot) LocalType( &manager, &UpdateManager::RequestRendering );
+}
+
 /**
  * Create a message for setting the depth of a layer
  * @param[in] manager The update manager
index e821f6e..cce7464 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -181,7 +181,7 @@ void Renderer::operator delete( void* ptr )
 }
 
 
-void Renderer::PrepareRender( BufferIndex updateBufferIndex )
+bool Renderer::PrepareRender( BufferIndex updateBufferIndex )
 {
   if( mRegenerateUniformMap == UNIFORM_MAP_READY )
   {
@@ -221,6 +221,8 @@ void Renderer::PrepareRender( BufferIndex updateBufferIndex )
     mRegenerateUniformMap--;
   }
 
+  bool rendererUpdated = mUniformMapChanged[updateBufferIndex] || mResendFlag;
+
   if( mResendFlag != 0 )
   {
     if( mResendFlag & RESEND_GEOMETRY )
@@ -365,6 +367,8 @@ void Renderer::PrepareRender( BufferIndex updateBufferIndex )
 
     mResendFlag = 0;
   }
+
+  return rendererUpdated;
 }
 
 void Renderer::SetTextures( TextureSet* textureSet )
index b3ab63e..a06fa2a 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_INTERNAL_SCENE_GRAPH_RENDERER_H
 
 /*
- * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -339,8 +339,9 @@ public:
    * Prepare the object for rendering.
    * This is called by the UpdateManager when an object is due to be rendered in the current frame.
    * @param[in] updateBufferIndex The current update buffer index.
+   * @return Whether this renderer has been updated in the current frame
    */
-  void PrepareRender( BufferIndex updateBufferIndex );
+  bool PrepareRender( BufferIndex updateBufferIndex );
 
   /**
    * Retrieve the Render thread renderer
index 3afaa88..120d5e1 100644 (file)
@@ -105,7 +105,6 @@ public:
    *   D   E   F
    *
    * @endcode
-   * @param[in] depth The depth in the hierarchy for the actor
    */
   virtual void OnSceneConnection(int32_t depth) = 0;
 
index 5a4a98a..d353d6c 100644 (file)
@@ -93,7 +93,6 @@ public:
    *
    * @SINCE_1_0.0
    * @param[in] implementation The implementation for this custom actor
-   * @return A handle to a newly allocated Dali resource
    */
   CustomActor(CustomActorImpl& implementation);
 
index 1ea2677..48c32b0 100644 (file)
@@ -83,7 +83,6 @@ public:
    * @brief Default constructor.
    * Creates an alpha function object with the default built-in alpha function.
    * @SINCE_1_0.0
-   * @return The alpha function
    */
   AlphaFunction();
 
@@ -93,7 +92,6 @@ public:
    * to the constructor.
    * @SINCE_1_0.0
    * @param[in] function One of the built-in alpha functions
-   * @return The alpha function
    */
   AlphaFunction(BuiltinFunction function);
 
@@ -103,7 +101,6 @@ public:
    * to the constructor.
    * @SINCE_1_0.0
    * @param[in] function A pointer to an alpha function
-   * @return The alpha function
    */
   AlphaFunction(AlphaFunctionPrototype function);
 
@@ -115,7 +112,6 @@ public:
    * @SINCE_1_0.0
    * @param[in] controlPoint0 A Vector2 which will be used as the first control point of the curve
    * @param[in] controlPoint1 A Vector2 which will be used as the second control point of the curve
-   * @return The alpha function
    * @note The x components of the control points will be clamped to the range [0,1] to prevent
    * non monotonic curves.
    */
index 5a487ac..6bdcb7c 100644 (file)
@@ -170,12 +170,12 @@ public:
     CallbackBase* Clone()
     {
       CallbackBase* callback = nullptr;
-      if(mImpl && mImpl->mObjectPointer && mCopyConstructorDispatcher)
+      if(mImpl.mObjectPointer && mCopyConstructorDispatcher)
       {
-        callback = new Function(mCopyConstructorDispatcher(reinterpret_cast<UndefinedClass*>(mImpl->mObjectPointer)) /* Copy the object */,
+        callback = new Function(mCopyConstructorDispatcher(reinterpret_cast<UndefinedClass*>(mImpl.mObjectPointer)) /* Copy the object */,
                                 mMemberFunction,
-                                mImpl->mMemberFunctionDispatcher,
-                                mImpl->mDestructorDispatcher,
+                                mImpl.mMemberFunctionDispatcher,
+                                mImpl.mDestructorDispatcher,
                                 mCopyConstructorDispatcher);
       }
       else
index e4bb8ce..5a61b64 100644 (file)
@@ -847,6 +847,38 @@ public: // API
 };
 
 /**
+ * @brief Erases all elements that compare equal to value from the vector.
+ *
+ * @SINCE_1_9.33
+ * @param[in] vector The vector
+ * @param[in] value The value to be removed.
+ */
+template <class T, class U>
+inline void Erase(Dali::Vector<T>& vector, const U& value)
+{
+  auto begin = vector.Begin();
+  auto end = vector.End();
+
+  vector.Erase(std::remove(begin, end, value), end);
+}
+
+/**
+ * @brief Erases all elements that satisfy the predicate from the vector.
+ *
+ * @SINCE_1_9.33
+ * @param[in] vector The vector
+ * @param[in] predicate The predicate
+ */
+template <class T, class Predicate>
+inline void EraseIf(Dali::Vector<T>& vector, Predicate predicate)
+{
+  auto begin = vector.Begin();
+  auto end = vector.End();
+
+  vector.Erase(std::remove_if(begin, end, predicate), end);
+}
+
+/**
  * @}
  */
 } // namespace Dali
index 7ee6ca0..8ff52e1 100644 (file)
@@ -27,7 +27,7 @@ namespace Dali
 {
 const uint32_t    CORE_MAJOR_VERSION = 1;
 const uint32_t    CORE_MINOR_VERSION = 9;
-const uint32_t    CORE_MICRO_VERSION = 32;
+const uint32_t    CORE_MICRO_VERSION = 34;
 const char* const CORE_BUILD_DATE    = __DATE__ " " __TIME__;
 
 #ifdef DEBUG_ENABLED
index b98df2f..d7dc63f 100644 (file)
@@ -74,7 +74,7 @@ public:
   /**
    * @brief PropertySetSignal function prototype for signal handler. Called when a property is set on this object.
    */
-  using PropertySetSignalType = Signal<void(Handle& handle, Property::Index index, Property::Value value)>;
+  using PropertySetSignalType = Signal<void(Handle& handle, Property::Index index, const Property::Value& value)>;
 
 public:
   /**
index 0b3cfd7..eb52b56 100644 (file)
@@ -47,71 +47,17 @@ BaseSignal::~BaseSignal()
 
   // The signal is being destroyed. We have to inform any slots
   // that are connected, that the signal is dead.
-  const std::size_t count(mSignalConnections.Count());
+  const std::size_t count(mSignalConnections.size());
   for(std::size_t i = 0; i < count; i++)
   {
-    SignalConnection* connection = mSignalConnections[i];
+    auto& connection = mSignalConnections[i];
 
     // Note that values are set to NULL in DeleteConnection
     if(connection)
     {
-      connection->Disconnect(this);
-      delete connection;
+      connection.Disconnect(this);
     }
   }
-
-  mSignalConnections.Clear();
-}
-
-bool BaseSignal::Empty() const
-{
-  return (0 == GetConnectionCount());
-}
-
-std::size_t BaseSignal::GetConnectionCount() const
-{
-  std::size_t count(0);
-
-  const std::size_t size(mSignalConnections.Count());
-  for(std::size_t i = 0; i < size; ++i)
-  {
-    // Note that values are set to NULL in DeleteConnection
-    if(nullptr != mSignalConnections[i])
-    {
-      ++count;
-    }
-  }
-
-  return count;
-}
-
-void BaseSignal::Emit()
-{
-  // Guards against nested Emit() calls
-  EmitGuard guard(mEmittingFlag); // Guards against nested Emit() calls
-  if(guard.ErrorOccurred())
-  {
-    return;
-  }
-
-  // If more connections are added by callbacks, these are ignore until the next Emit()
-  // Note that mSignalConnections.Count() count cannot be reduced while iterating
-  const std::size_t initialCount(mSignalConnections.Count());
-
-  for(std::size_t i = 0; i < initialCount; ++i)
-  {
-    CallbackBase* callback(GetCallback(i));
-
-    // Note that connections will be set to NULL when disconnected
-    // This is preferable to reducing the connection count while iterating
-    if(callback)
-    {
-      CallbackBase::Execute(*callback);
-    }
-  }
-
-  // Cleanup NULL values from Connection container
-  CleanupConnections();
 }
 
 void BaseSignal::OnConnect(CallbackBase* callback)
@@ -124,9 +70,9 @@ void BaseSignal::OnConnect(CallbackBase* callback)
   if(INVALID_CALLBACK_INDEX == index)
   {
     // create a new signal connection object, to allow the signal to track the connection.
-    SignalConnection* connection = new SignalConnection(callback);
+    //SignalConnection* connection = new SignalConnection(callback);
 
-    mSignalConnections.PushBack(connection);
+    mSignalConnections.push_back(SignalConnection(callback));
   }
   else
   {
@@ -161,9 +107,9 @@ void BaseSignal::OnConnect(ConnectionTrackerInterface* tracker, CallbackBase* ca
   if(INVALID_CALLBACK_INDEX == index)
   {
     // create a new signal connection object, to allow the signal to track the connection.
-    SignalConnection* connection = new SignalConnection(tracker, callback);
+    //SignalConnection* connection = new SignalConnection(tracker, callback);
 
-    mSignalConnections.PushBack(connection);
+    mSignalConnections.push_back({tracker, callback});
 
     // Let the connection tracker know that a connection between a signal and a slot has been made.
     tracker->SignalConnected(this, callback);
@@ -185,7 +131,7 @@ void BaseSignal::OnDisconnect(ConnectionTrackerInterface* tracker, CallbackBase*
   if(index > INVALID_CALLBACK_INDEX)
   {
     // temporary pointer to disconnected callback
-    CallbackBase* disconnectedCallback = mSignalConnections[index]->GetCallback();
+    CallbackBase* disconnectedCallback = mSignalConnections[index].GetCallback();
 
     // close the signal side connection first.
     DeleteConnection(index);
@@ -201,7 +147,7 @@ void BaseSignal::OnDisconnect(ConnectionTrackerInterface* tracker, CallbackBase*
 // for SlotObserver::SlotDisconnected
 void BaseSignal::SlotDisconnected(CallbackBase* callback)
 {
-  const std::size_t count(mSignalConnections.Count());
+  const std::size_t count(mSignalConnections.size());
   for(std::size_t i = 0; i < count; ++i)
   {
     const CallbackBase* connectionCallback = GetCallback(i);
@@ -220,32 +166,15 @@ void BaseSignal::SlotDisconnected(CallbackBase* callback)
   DALI_ABORT("Callback lost in SlotDisconnected()");
 }
 
-CallbackBase* BaseSignal::GetCallback(std::size_t connectionIndex) const
-{
-  DALI_ASSERT_ALWAYS(connectionIndex < mSignalConnections.Count() && "GetCallback called with invalid index");
-
-  CallbackBase* callback(nullptr);
-
-  SignalConnection* connection(mSignalConnections[connectionIndex]);
 
-  // Note that values are set to NULL in DeleteConnection
-  if(connection)
-  {
-    callback = connection->GetCallback();
-  }
-
-  return callback;
-}
-
-int32_t BaseSignal::FindCallback(CallbackBase* callback)
+int32_t BaseSignal::FindCallback(CallbackBase* callback) const noexcept
 {
   int32_t index(INVALID_CALLBACK_INDEX);
 
   // A signal can have multiple slots connected to it.
   // We need to search for the slot which has the same call back function (if it's static)
   // Or the same object / member function (for non-static)
-  const std::size_t count = mSignalConnections.Count();
-  for(std::size_t i = 0; i < count; ++i)
+  for(auto i = 0u; i < mSignalConnections.size(); ++i)
   {
     const CallbackBase* connectionCallback = GetCallback(i);
 
@@ -262,49 +191,34 @@ int32_t BaseSignal::FindCallback(CallbackBase* callback)
 
 void BaseSignal::DeleteConnection(std::size_t connectionIndex)
 {
-  DALI_ASSERT_ALWAYS(connectionIndex < mSignalConnections.Count() && "DeleteConnection called with invalid index");
-
-  // delete the object
-  SignalConnection* connection(mSignalConnections[connectionIndex]);
-  delete connection;
 
   if(mEmittingFlag)
   {
-    // IMPORTANT - do not remove from items from mSignalConnections, set to NULL instead.
+    // IMPORTANT - do not remove from items from mSignalConnections, reset instead.
     // Signal Emit() methods require that connection count is not reduced while iterating
     // i.e. DeleteConnection can be called from within callbacks, while iterating through mSignalConnections.
-    mSignalConnections[connectionIndex] = nullptr;
+    mSignalConnections[connectionIndex] = {nullptr};
+    ++mNullConnections;
   }
   else
   {
     // If application connects and disconnects without the signal never emitting,
     // the mSignalConnections vector keeps growing and growing as CleanupConnections() is done from Emit.
-    mSignalConnections.Erase(mSignalConnections.Begin() + connectionIndex);
+    mSignalConnections.erase(mSignalConnections.begin() + connectionIndex);
   }
 }
 
 void BaseSignal::CleanupConnections()
 {
-  const std::size_t total = mSignalConnections.Count();
-  // only do something if there are items
-  if(total > 0)
+  if(!mSignalConnections.empty())
   {
-    std::size_t index = 0;
-    // process the whole vector
-    for(std::size_t i = 0; i < total; ++i)
-    {
-      if(mSignalConnections[index] == nullptr)
-      {
-        // items will be moved so don't increase index (erase will decrease the count of vector)
-        mSignalConnections.Erase(mSignalConnections.Begin() + index);
-      }
-      else
-      {
-        // increase to next element
-        ++index;
-      }
-    }
+    //Remove Signals that are already markeed nullptr.
+    mSignalConnections.erase(std::remove_if(mSignalConnections.begin(),
+                                            mSignalConnections.end(),
+                                            [](auto& elm) { return (elm) ? false : true; }),
+                             mSignalConnections.end());
   }
+  mNullConnections = 0;
 }
 
 // BaseSignal::EmitGuard
index ddfe915..63dc801 100644 (file)
@@ -18,6 +18,9 @@
  *
  */
 
+// EXTERNAL INCLUDES
+#include <vector>
+
 // INTERNAL INCLUDES
 #include <dali/public-api/common/dali-common.h>
 #include <dali/public-api/common/dali-vector.h>
@@ -96,7 +99,10 @@ public:
    * @SINCE_1_0.0
    * @return True if there are any slots connected to the signal.
    */
-  bool Empty() const;
+  bool Empty() const
+  {
+    return (0 == GetConnectionCount());
+  }
 
   /**
    * @brief Queries the number of slots.
@@ -104,7 +110,10 @@ public:
    * @SINCE_1_0.0
    * @return The number of slots connected to this signal
    */
-  std::size_t GetConnectionCount() const;
+  std::size_t GetConnectionCount() const
+  {
+    return mSignalConnections.size() - mNullConnections;
+  }
 
   // Templated Emit functions for the Signal implementations
 
@@ -141,22 +150,15 @@ public:
   };
 
   /**
-   * @brief Emits a signal with no parameters.
-   *
-   * @SINCE_1_0.0
-   * @pre Cannot be called from inside the same Signal's Emit methods.
-   */
-  void Emit();
-
-  /**
-   * @brief Emits a signal with no parameters.
+   * @brief Emits a signal with parameter pack.
    *
-   * @SINCE_1_0.0
+   * @SINCE_1_9.33
+   * @param[in] args The parameter pack
    * @return The value returned by the last callback
    * @pre Cannot be called from inside the same Signal's Emit methods.
    */
-  template<typename Ret>
-  Ret EmitReturn()
+  template<typename Ret, typename... Args>
+  Ret EmitReturn(Args... args)
   {
     Ret returnVal = Ret();
 
@@ -169,167 +171,7 @@ public:
 
     // If more connections are added by callbacks, these are ignore until the next Emit()
     // Note that count cannot be reduced while iterating
-    const std::size_t initialCount(mSignalConnections.Count());
-
-    for(std::size_t i = 0; i < initialCount; ++i)
-    {
-      CallbackBase* callback(GetCallback(i));
-
-      // Note that connections will be set to NULL when disconnected
-      // This is preferable to reducing the connection count while iterating
-      if(callback)
-      {
-        returnVal = CallbackBase::ExecuteReturn<Ret>(*callback);
-      }
-    }
-
-    // Cleanup NULL values from Connection container
-    CleanupConnections();
-
-    return returnVal;
-  }
-
-  /**
-   * @brief Emits a signal with 1 parameter.
-   *
-   * @SINCE_1_0.0
-   * @param[in] arg0 The first parameter
-   * @pre Cannot be called from inside the same Signal's Emit methods.
-   */
-  template<typename Arg0>
-  void Emit(Arg0 arg0)
-  {
-    // Guards against nested Emit() calls
-    EmitGuard guard(mEmittingFlag); // Guards against nested Emit() calls
-    if(guard.ErrorOccurred())
-    {
-      return;
-    }
-
-    // If more connections are added by callbacks, these are ignore until the next Emit()
-    // Note that count cannot be reduced while iterating
-    const std::size_t initialCount(mSignalConnections.Count());
-
-    for(std::size_t i = 0; i < initialCount; ++i)
-    {
-      CallbackBase* callback(GetCallback(i));
-
-      // Note that connections will be set to NULL when disconnected
-      // This is preferable to reducing the connection count while iterating
-      if(callback)
-      {
-        CallbackBase::Execute<Arg0>(*callback, arg0);
-      }
-    }
-
-    // Cleanup NULL values from Connection container
-    CleanupConnections();
-  }
-
-  /**
-   * @brief Emits a signal with 1 parameter.
-   *
-   * @SINCE_1_0.0
-   * @param[in] arg0 The first parameter
-   * @return The value returned by the last callback
-   * @pre Cannot be called from inside the same Signal's Emit methods.
-   */
-  template<typename Ret, typename Arg0>
-  Ret EmitReturn(Arg0 arg0)
-  {
-    Ret returnVal = Ret();
-
-    // Guards against nested Emit() calls
-    EmitGuard guard(mEmittingFlag); // Guards against nested Emit() calls
-    if(guard.ErrorOccurred())
-    {
-      return returnVal;
-    }
-
-    // If more connections are added by callbacks, these are ignore until the next Emit()
-    // Note that count cannot be reduced while iterating
-    const std::size_t initialCount(mSignalConnections.Count());
-
-    for(std::size_t i = 0; i < initialCount; ++i)
-    {
-      CallbackBase* callback(GetCallback(i));
-
-      // Note that connections will be set to NULL when disconnected
-      // This is preferable to reducing the connection count while iterating
-      if(callback)
-      {
-        returnVal = CallbackBase::ExecuteReturn<Ret, Arg0>(*callback, arg0);
-      }
-    }
-
-    // Cleanup NULL values from Connection container
-    CleanupConnections();
-
-    return returnVal;
-  }
-
-  /**
-   * @brief Emits a signal with 2 parameters.
-   *
-   * @SINCE_1_0.0
-   * @param[in] arg0 The first parameter
-   * @param[in] arg1 The second parameter
-   * @pre Cannot be called from inside the same Signal's Emit methods.
-   */
-  template<typename Arg0, typename Arg1>
-  void Emit(Arg0 arg0, Arg1 arg1)
-  {
-    // Guards against nested Emit() calls
-    EmitGuard guard(mEmittingFlag); // Guards against nested Emit() calls
-    if(guard.ErrorOccurred())
-    {
-      return;
-    }
-
-    // If more connections are added by callbacks, these are ignore until the next Emit()
-    // Note that count cannot be reduced while iterating
-    const std::size_t initialCount(mSignalConnections.Count());
-
-    for(std::size_t i = 0; i < initialCount; ++i)
-    {
-      CallbackBase* callback(GetCallback(i));
-
-      // Note that connections will be set to NULL when disconnected
-      // This is preferable to reducing the connection count while iterating
-      if(callback)
-      {
-        CallbackBase::Execute<Arg0, Arg1>(*callback, arg0, arg1);
-      }
-    }
-
-    // Cleanup NULL values from Connection container
-    CleanupConnections();
-  }
-
-  /**
-   * @brief Emits a signal with 2 parameters.
-   *
-   * @SINCE_1_0.0
-   * @param[in] arg0 The first parameter
-   * @param[in] arg1 The second parameter
-   * @return The value returned by the last callback
-   * @pre Cannot be called from inside the same Signal's Emit methods.
-   */
-  template<typename Ret, typename Arg0, typename Arg1>
-  Ret EmitReturn(Arg0 arg0, Arg1 arg1)
-  {
-    Ret returnVal = Ret();
-
-    // Guards against nested Emit() calls
-    EmitGuard guard(mEmittingFlag); // Guards against nested Emit() calls
-    if(guard.ErrorOccurred())
-    {
-      return returnVal;
-    }
-
-    // If more connections are added by callbacks, these are ignore until the next Emit()
-    // Note that count cannot be reduced while iterating
-    const std::size_t initialCount(mSignalConnections.Count());
+    const std::size_t initialCount(mSignalConnections.size());
 
     for(std::size_t i = 0; i < initialCount; ++i)
     {
@@ -339,7 +181,7 @@ public:
       // This is preferable to reducing the connection count while iterating
       if(callback)
       {
-        returnVal = CallbackBase::ExecuteReturn<Ret, Arg0, Arg1>(*callback, arg0, arg1);
+        returnVal = CallbackBase::ExecuteReturn<Ret, Args...>(*callback, args...);
       }
     }
 
@@ -350,16 +192,14 @@ public:
   }
 
   /**
-   * @brief Emits a signal with 3 parameters.
+   * @brief Emits a signal with  parameter pack.
    *
-   * @SINCE_1_0.0
-   * @param[in] arg0 The first parameter
-   * @param[in] arg1 The second parameter
-   * @param[in] arg2 The third parameter
+   * @SINCE_1_9.33
+   * @param[in] args The parameter pack
    * @pre Cannot be called from inside the same Signal's Emit methods.
    */
-  template<typename Arg0, typename Arg1, typename Arg2>
-  void Emit(Arg0 arg0, Arg1 arg1, Arg2 arg2)
+  template<typename... Args>
+  void Emit(Args... args)
   {
     // Guards against nested Emit() calls
     EmitGuard guard(mEmittingFlag); // Guards against nested Emit() calls
@@ -370,49 +210,7 @@ public:
 
     // If more connections are added by callbacks, these are ignore until the next Emit()
     // Note that count cannot be reduced while iterating
-    const std::size_t initialCount(mSignalConnections.Count());
-
-    for(std::size_t i = 0; i < initialCount; ++i)
-    {
-      CallbackBase* callback(GetCallback(i));
-
-      // Note that connections will be set to NULL when disconnected
-      // This is preferable to reducing the connection count while iterating
-      if(callback)
-      {
-        CallbackBase::Execute<Arg0, Arg1, Arg2>(*callback, arg0, arg1, arg2);
-      }
-    }
-
-    // Cleanup NULL values from Connection container
-    CleanupConnections();
-  }
-
-  /**
-   * @brief Emits a signal with 3 parameters.
-   *
-   * @SINCE_1_0.0
-   * @param[in] arg0 The first parameter
-   * @param[in] arg1 The second parameter
-   * @param[in] arg2 The third parameter
-   * @return The value returned by the last callback
-   * @pre Cannot be called from inside the same Signal's Emit methods.
-   */
-  template<typename Ret, typename Arg0, typename Arg1, typename Arg2>
-  Ret EmitReturn(Arg0 arg0, Arg1 arg1, Arg2 arg2)
-  {
-    Ret returnVal = Ret();
-
-    // Guards against nested Emit() calls
-    EmitGuard guard(mEmittingFlag); // Guards against nested Emit() calls
-    if(guard.ErrorOccurred())
-    {
-      return returnVal;
-    }
-
-    // If more connections are added by callbacks, these are ignore until the next Emit()
-    // Note that count cannot be reduced while iterating
-    const std::size_t initialCount(mSignalConnections.Count());
+    const std::size_t initialCount(mSignalConnections.size());
 
     for(std::size_t i = 0; i < initialCount; ++i)
     {
@@ -422,14 +220,12 @@ public:
       // This is preferable to reducing the connection count while iterating
       if(callback)
       {
-        returnVal = CallbackBase::ExecuteReturn<Ret, Arg0, Arg1, Arg2>(*callback, arg0, arg1, arg2);
+        CallbackBase::Execute<Args...>(*callback, args...);
       }
     }
 
     // Cleanup NULL values from Connection container
     CleanupConnections();
-
-    return returnVal;
   }
 
   // Connect / Disconnect function for use by Signal implementations
@@ -482,7 +278,10 @@ private:
    * @param[in] connectionIndex The index of the callback
    * @return The callback, or NULL if the connection has been deleted
    */
-  CallbackBase* GetCallback(std::size_t connectionIndex) const;
+  CallbackBase* GetCallback(std::size_t connectionIndex) const noexcept
+  {
+    return mSignalConnections[connectionIndex].GetCallback();
+  }
 
   /**
    * @brief Helper to find whether a callback is connected.
@@ -491,7 +290,7 @@ private:
    * @param[in] callback The call back object
    * @return A valid index if the callback is connected
    */
-  int32_t FindCallback(CallbackBase* callback);
+  int32_t FindCallback(CallbackBase* callback) const noexcept;
 
   /**
    * @brief Deletes a connection object from the list of connections.
@@ -514,9 +313,9 @@ private:
   BaseSignal& operator=(BaseSignal&&) = delete;      ///< Deleted move assignment operator. @SINCE_1_9.25
 
 private:
-  Dali::Vector<SignalConnection*> mSignalConnections; ///< Array of connections
-
-  bool mEmittingFlag; ///< Used to guard against nested Emit() calls
+  std::vector<SignalConnection> mSignalConnections; ///< Array of connections
+  uint32_t                      mNullConnections{0}; ///< Empty Connections in the array.
+  bool                          mEmittingFlag{false}; ///< Used to guard against nested Emit() calls
 };
 
 /**
index fd0576b..6e8fb93 100644 (file)
@@ -23,8 +23,7 @@ namespace Dali
 // CallbackBase
 
 CallbackBase::CallbackBase()
-: mImpl(nullptr),
-  mFunction(nullptr)
+: mFunction(nullptr)
 {
 }
 
@@ -34,77 +33,39 @@ CallbackBase::~CallbackBase()
 }
 
 CallbackBase::CallbackBase(Function function)
-: mImpl(nullptr),
-  mFunction(function)
+: mFunction(function)
 {
 }
 
 CallbackBase::CallbackBase(void* object, MemberFunction function, Dispatcher dispatcher)
 : mMemberFunction(function)
 {
-  mImpl = new CallbackBase::Impl;
-  if(mImpl)
-  {
-    mImpl->mObjectPointer            = object;
-    mImpl->mMemberFunctionDispatcher = dispatcher;
-    mImpl->mDestructorDispatcher     = nullptr; // object is not owned
-  }
+    mImpl.mObjectPointer            = object;
+    mImpl.mMemberFunctionDispatcher = dispatcher;
+    mImpl.mDestructorDispatcher     = nullptr; // object is not owned
 }
 
 CallbackBase::CallbackBase(void* object, MemberFunction function, Dispatcher dispatcher, Destructor destructor)
 : mMemberFunction(function)
 {
-  mImpl = new CallbackBase::Impl;
-  if(mImpl)
-  {
-    mImpl->mObjectPointer            = object;
-    mImpl->mMemberFunctionDispatcher = dispatcher;
-    mImpl->mDestructorDispatcher     = destructor; // object is owned
-  }
+    mImpl.mObjectPointer            = object;
+    mImpl.mMemberFunctionDispatcher = dispatcher;
+    mImpl.mDestructorDispatcher     = destructor; // object is owned
 }
 
 void CallbackBase::Reset()
 {
-  if(mImpl)
+  // if destructor function is set it means we own this object
+  if(mImpl.mObjectPointer &&
+     mImpl.mDestructorDispatcher)
   {
-    // if destructor function is set it means we own this object
-    if(mImpl->mObjectPointer &&
-       mImpl->mDestructorDispatcher)
-    {
-      // call the destructor dispatcher
-      (*mImpl->mDestructorDispatcher)(mImpl->mObjectPointer);
-    }
-
-    delete mImpl;
-    mImpl = nullptr;
+    // call the destructor dispatcher
+    (*mImpl.mDestructorDispatcher)(mImpl.mObjectPointer);
   }
 
-  mFunction = nullptr;
-}
-
-// CallbackBase::Impl
-
-CallbackBase::Impl::Impl()
-: mObjectPointer(nullptr),
-  mMemberFunctionDispatcher(nullptr),
-  mDestructorDispatcher(nullptr)
-{
-}
-
-// Non-member equality operator
+  mImpl = {};
 
-bool operator==(const CallbackBase& lhs, const CallbackBase& rhs)
-{
-  if(lhs.mImpl)
-  {
-    // check it's the same member function / object
-    return (lhs.mFunction == rhs.mFunction) && (lhs.mImpl->mObjectPointer == rhs.mImpl->mObjectPointer);
-  }
-  else
-  {
-    // check if it the same C function or a static member function
-    return (lhs.mFunction == rhs.mFunction);
-  }
+  mFunction = nullptr;
 }
 
 } // namespace Dali
index 81d875f..0acc43d 100644 (file)
@@ -62,119 +62,31 @@ public:
   /**
    * @brief Function to call the function or member function dispatcher.
    *
-   * @SINCE_1_0.0
-   * @param[in] callback The callback to call
-   */
-  static void Execute(CallbackBase& callback)
-  {
-    // if we point to a function, we can call it directly
-    // otherwise call the dispatcher function that knows the real type of the object
-    // Note that this template dispatcher lives in client code so the library containing
-    // the code has to be loaded, otherwise we crash boom bang
-    if(callback.mImpl && callback.mImpl->mObjectPointer)
-    {
-      Dispatcher dispatcher = callback.mImpl->mMemberFunctionDispatcher;
-      (*dispatcher)(callback);
-    }
-    // its also possible to have a member function pointer to a CallbackProvider
-    // that has been deleted, so check if we have impl still
-    else if(!callback.mImpl && callback.mFunction)
-    {
-      (*(callback.mFunction))();
-    }
-    else
-    {
-      DALI_ASSERT_ALWAYS(0 && "no function to execute");
-    }
-  }
-
-  /**
-   * @brief Function to call the function or member function dispatcher.
-   *
-   * @SINCE_1_0.0
-   * @param[in] callback The callback to call
-   * @return The value from the function
-   */
-  template<typename R>
-  static R ExecuteReturn(CallbackBase& callback)
-  {
-    R returnVal = R();
-    // if we point to a function, we can call it directly
-    // otherwise call the dispatcher function that knows the real type of the object
-    // Note that this template dispatcher lives in client code so the library containing
-    // the code has to be loaded, otherwise we crash boom bang
-    if(callback.mImpl && callback.mImpl->mObjectPointer)
-    {
-      using Dispatcher      = R (*)(CallbackBase&);
-      Dispatcher dispatcher = reinterpret_cast<Dispatcher>(callback.mImpl->mMemberFunctionDispatcher);
-      returnVal             = (*dispatcher)(callback);
-    }
-    else if(!callback.mImpl && callback.mFunction)
-    {
-      using Function1 = R (*)();
-      returnVal       = (*(reinterpret_cast<Function1>(callback.mFunction)))();
-    }
-
-    return returnVal;
-  }
-
-  /**
-   * @brief Function to call the function or member function dispatcher.
-   *
-   * This function template gets instantiated at the call site.
-   * @SINCE_1_0.0
-   * @param[in] callback The callback to call
-   * @param[in] param1 The first parameter to pass into the function
-   */
-  template<typename P1>
-  static void Execute(CallbackBase& callback, P1 param1)
-  {
-    // if we point to a function, we can call it directly
-    // otherwise call the dispatcher function that knows the real type of the object
-    // Note that this template dispatcher lives in client code (where the callback was created)
-    // so the library containing the code has to be loaded, otherwise we crash boom bang
-    if(callback.mImpl && callback.mImpl->mObjectPointer)
-    {
-      using Dispatcher      = void (*)(CallbackBase&, P1);
-      Dispatcher dispatcher = reinterpret_cast<Dispatcher>(callback.mImpl->mMemberFunctionDispatcher);
-      (*dispatcher)(callback, param1);
-    }
-    else if(!callback.mImpl && callback.mFunction)
-    {
-      // convert function type
-      using Function1 = void (*)(P1);
-      (*(reinterpret_cast<Function1>(callback.mFunction)))(param1);
-    }
-  }
-
-  /**
-   * @brief Function to call the function or member function dispatcher.
-   *
    * This function template gets instantiated at the call site.
-   * @SINCE_1_0.0
+   * @SINCE_1_9.33
    * @param[in] callback The callback to call
-   * @param[in] param1 The first parameter to pass into the function
+   * @param[in] args parameter pack to pass into the function
    * @return The value from the function
    */
-  template<typename R, typename P1>
-  static R ExecuteReturn(CallbackBase& callback, P1 param1)
+  template<typename R, typename... Args>
+  static R ExecuteReturn(CallbackBase& callback, Args... args)
   {
     R returnVal = R();
     // if we point to a function, we can call it directly
     // otherwise call the dispatcher function that knows the real type of the object
     // Note that this template dispatcher lives in client code (where the callback was created)
     // so the library containing the code has to be loaded, otherwise we crash boom bang
-    if(callback.mImpl && callback.mImpl->mObjectPointer)
+    if(callback.mImpl.mObjectPointer)
     {
-      using Dispatcher      = R (*)(CallbackBase&, P1);
-      Dispatcher dispatcher = reinterpret_cast<Dispatcher>(callback.mImpl->mMemberFunctionDispatcher);
-      returnVal             = (*dispatcher)(callback, param1);
+      using Dispatcher      = R (*)(CallbackBase&, Args...);
+      Dispatcher dispatcher = reinterpret_cast<Dispatcher>(callback.mImpl.mMemberFunctionDispatcher);
+      returnVal             = (*dispatcher)(callback, args...);
     }
-    else if(!callback.mImpl && callback.mFunction)
+    else if(callback.mFunction)
     {
       // convert function type
-      using Function1 = R (*)(P1);
-      returnVal       = (*(reinterpret_cast<Function1>(callback.mFunction)))(param1);
+      using Function = R (*)(Args...);
+      returnVal       = (*(reinterpret_cast<Function>(callback.mFunction)))(args...);
     }
 
     return returnVal;
@@ -184,138 +96,48 @@ public:
    * @brief Function to call the function or member function dispatcher.
    *
    * This function template gets instantiated at the call site.
-   * @SINCE_1_0.0
+   * @SINCE_1_9.33
    * @param[in] callback The callback to call
-   * @param[in] param1 The first parameter to pass into the function
-   * @param[in] param2 The second parameter to pass into the function
+   * @param[in] args parameter pack to pass into the function
    */
-  template<typename P1, typename P2>
-  static void Execute(CallbackBase& callback, P1 param1, P2 param2)
+  template<typename... Args>
+  static void Execute(CallbackBase& callback, Args... args)
   {
     // if we point to a function, we can call it directly
     // otherwise call the dispatcher function that knows the real type of the object
     // Note that this template dispatcher lives in client code (where the callback was created)
     // so the library containing the code has to be loaded, otherwise we crash boom bang
-    if(callback.mImpl && callback.mImpl->mObjectPointer)
+    if(callback.mImpl.mObjectPointer)
     {
-      using Dispatcher      = void (*)(CallbackBase&, P1, P2);
-      Dispatcher dispatcher = reinterpret_cast<Dispatcher>(callback.mImpl->mMemberFunctionDispatcher);
-      (*dispatcher)(callback, param1, param2);
+      using Dispatcher      = void (*)(CallbackBase&, Args...);
+      Dispatcher dispatcher = reinterpret_cast<Dispatcher>(callback.mImpl.mMemberFunctionDispatcher);
+      (*dispatcher)(callback, args...);
     }
-    else if(!callback.mImpl && callback.mFunction)
+    else if(callback.mFunction)
     {
       // convert function type
-      using Function2 = void (*)(P1, P2);
-      (*(reinterpret_cast<Function2>(callback.mFunction)))(param1, param2);
+      using Function = void (*)(Args...);
+      (*(reinterpret_cast<Function>(callback.mFunction)))(args...);
     }
   }
 
+public:
   /**
-   * @brief Function to call the function or member function dispatcher.
-   *
-   * This function template gets instantiated at the call site.
-   * @SINCE_1_0.0
-   * @param[in] callback The callback to call
-   * @param[in] param1 The first parameter to pass into the function
-   * @param[in] param2 The second parameter to pass into the function
-   * @return The return value from the function
-   */
-  template<typename R, typename P1, typename P2>
-  static R ExecuteReturn(CallbackBase& callback, P1 param1, P2 param2)
-  {
-    R returnVal = R();
-    // if we point to a function, we can call it directly
-    // otherwise call the dispatcher function that knows the real type of the object
-    // Note that this template dispatcher lives in client code (where the callback was created)
-    // so the library containing the code has to be loaded, otherwise we crash boom bang
-    if(callback.mImpl && callback.mImpl->mObjectPointer)
-    {
-      using Dispatcher      = R (*)(CallbackBase&, P1, P2);
-      Dispatcher dispatcher = reinterpret_cast<Dispatcher>(callback.mImpl->mMemberFunctionDispatcher);
-      returnVal             = (*dispatcher)(callback, param1, param2);
-    }
-    else if(!callback.mImpl && callback.mFunction)
-    {
-      // convert function type
-      using Function2 = R (*)(P1, P2);
-      returnVal       = (*(reinterpret_cast<Function2>(callback.mFunction)))(param1, param2);
-    }
-
-    return returnVal;
-  }
-
-  /**
-   * @brief Function to call the function or member function dispatcher.
-   *
-   * This function template gets instantiated at the call site.
+   * @brief Function with static linkage.
    * @SINCE_1_0.0
-   * @param[in] callback The callback to call
-   * @param[in] param1 The first parameter to pass into the function
-   * @param[in] param2 The second parameter to pass into the function
-   * @param[in] param3 The third parameter to pass into the function
    */
-  template<typename P1, typename P2, typename P3>
-  static void Execute(CallbackBase& callback, P1 param1, P2 param2, P3 param3)
-  {
-    // if we point to a function, we can call it directly
-    // otherwise call the dispatcher function that knows the real type of the object
-    // Note that this template dispatcher lives in client code (where the callback was created)
-    // so the library containing the code has to be loaded, otherwise we crash boom bang
-    if(callback.mImpl && callback.mImpl->mObjectPointer)
-    {
-      using Dispatcher      = void (*)(CallbackBase&, P1, P2, P3);
-      Dispatcher dispatcher = reinterpret_cast<Dispatcher>(callback.mImpl->mMemberFunctionDispatcher);
-      (*dispatcher)(callback, param1, param2, param3);
-    }
-    else if(!callback.mImpl && callback.mFunction)
-    {
-      // convert function type
-      using Function2 = void (*)(P1, P2, P3);
-      (*(reinterpret_cast<Function2>(callback.mFunction)))(param1, param2, param3);
-    }
-  }
+  using Function = void (*)();
 
   /**
-   * @brief Function to call the function or member function dispatcher.
+   * @brief Constructor for function with static linkage.
    *
-   * This function template gets instantiated at the call site.
    * @SINCE_1_0.0
-   * @param[in] callback The callback to call
-   * @param[in] param1 The first parameter to pass into the function
-   * @param[in] param2 The second parameter to pass into the function
-   * @param[in] param3 The third parameter to pass into the function
-   * @return The return value from the function
+   * @param[in] function The function to call
    */
-  template<typename R, typename P1, typename P2, typename P3>
-  static R ExecuteReturn(CallbackBase& callback, P1 param1, P2 param2, P3 param3)
-  {
-    R returnVal = R();
-    // if we point to a function, we can call it directly
-    // otherwise call the dispatcher function that knows the real type of the object
-    // Note that this template dispatcher lives in client code (where the callback was created)
-    // so the library containing the code has to be loaded, otherwise we crash boom bang
-    if(callback.mImpl && callback.mImpl->mObjectPointer)
-    {
-      using Dispatcher      = R (*)(CallbackBase&, P1, P2, P3);
-      Dispatcher dispatcher = reinterpret_cast<Dispatcher>(callback.mImpl->mMemberFunctionDispatcher);
-      returnVal             = (*dispatcher)(callback, param1, param2, param3);
-    }
-    else if(!callback.mImpl && callback.mFunction)
-    {
-      // convert function type
-      using Function2 = R (*)(P1, P2, P3);
-      returnVal       = (*(reinterpret_cast<Function2>(callback.mFunction)))(param1, param2, param3);
-    }
-
-    return returnVal;
-  }
+  CallbackBase(Function function);
 
 protected: // Constructors for deriving classes
-  /**
-   * @brief Function with static linkage.
-   * @SINCE_1_0.0
-   */
-  using Function = void (*)();
+
 
   /**
    * @brief Member function.
@@ -351,14 +173,6 @@ protected: // Constructors for deriving classes
   CallbackBase& operator=(const CallbackBase& rhs);
 
   /**
-   * @brief Constructor for function with static linkage.
-   *
-   * @SINCE_1_0.0
-   * @param[in] function The function to call
-   */
-  CallbackBase(Function function);
-
-  /**
    * @brief Constructor for member function.
    *
    * @SINCE_1_0.0
@@ -386,13 +200,11 @@ public: // Data for deriving classes & Dispatchers
    */
   struct Impl
   {
-    Impl(); ///< Default constructor @SINCE_1_0.0
-
-    void*      mObjectPointer;            ///< Object whose member function will be called. Not owned if mDestructorDispatcher is NULL.
-    Dispatcher mMemberFunctionDispatcher; ///< Dispatcher for member functions
-    Destructor mDestructorDispatcher;     ///< Destructor for owned objects. NULL if mDestructorDispatcher is not owned.
+    void*      mObjectPointer{nullptr};            ///< Object whose member function will be called. Not owned if mDestructorDispatcher is NULL.
+    Dispatcher mMemberFunctionDispatcher{nullptr}; ///< Dispatcher for member functions
+    Destructor mDestructorDispatcher{nullptr};     ///< Destructor for owned objects. NULL if mDestructorDispatcher is not owned.
   };
-  Impl* mImpl; ///< Implementation pointer
+  Impl mImpl;
 
   union
   {
@@ -408,7 +220,15 @@ public: // Data for deriving classes & Dispatchers
  * @param[in] rhs A reference to compare to
  * @return True if lhs is same as rhs
  */
-bool operator==(const CallbackBase& lhs, const CallbackBase& rhs);
+inline bool operator==(const CallbackBase& lhs, const CallbackBase& rhs)
+{
+  if (lhs.mFunction == rhs.mFunction &&
+      lhs.mImpl.mObjectPointer == rhs.mImpl.mObjectPointer)
+  {
+    return true;
+  }
+  return false;
+}
 
 /**
  * @brief Dispatcher to delete an object.
@@ -446,7 +266,7 @@ struct Dispatcher0
   static void Dispatch(CallbackBase& callback)
   {
     // "downcast" the object and function type back to the correct ones
-    T* object               = reinterpret_cast<T*>(callback.mImpl->mObjectPointer);
+    T* object               = reinterpret_cast<T*>(callback.mImpl.mObjectPointer);
     using MemberFunction    = void (T::*)();
     MemberFunction function = reinterpret_cast<MemberFunction>(callback.mMemberFunction);
     (object->*function)();
@@ -470,7 +290,7 @@ struct Dispatcher1
   static void Dispatch(CallbackBase& callback, P1 param1)
   {
     // "downcast" the object and function type back to the correct ones
-    T* object               = reinterpret_cast<T*>(callback.mImpl->mObjectPointer);
+    T* object               = reinterpret_cast<T*>(callback.mImpl.mObjectPointer);
     using MemberFunction    = void (T::*)(P1);
     MemberFunction function = reinterpret_cast<MemberFunction>(callback.mMemberFunction);
     (object->*function)(param1);
@@ -495,7 +315,7 @@ struct Dispatcher2
   static void Dispatch(CallbackBase& callback, P1 param1, P2 param2)
   {
     // "downcast" the object and function type back to the correct ones
-    T* object               = reinterpret_cast<T*>(callback.mImpl->mObjectPointer);
+    T* object               = reinterpret_cast<T*>(callback.mImpl.mObjectPointer);
     using MemberFunction    = void (T::*)(P1, P2);
     MemberFunction function = reinterpret_cast<MemberFunction>(callback.mMemberFunction);
     (object->*function)(param1, param2);
@@ -521,7 +341,7 @@ struct Dispatcher3
   static void Dispatch(CallbackBase& callback, P1 param1, P2 param2, P3 param3)
   {
     // "downcast" the object and function type back to the correct ones
-    T* object               = reinterpret_cast<T*>(callback.mImpl->mObjectPointer);
+    T* object               = reinterpret_cast<T*>(callback.mImpl.mObjectPointer);
     using MemberFunction    = void (T::*)(P1, P2, P3);
     MemberFunction function = reinterpret_cast<MemberFunction>(callback.mMemberFunction);
     (object->*function)(param1, param2, param3);
@@ -545,7 +365,7 @@ struct DispatcherReturn0
   static R Dispatch(CallbackBase& callback)
   {
     // "downcast" the object and function type back to the correct ones
-    T* object               = reinterpret_cast<T*>(callback.mImpl->mObjectPointer);
+    T* object               = reinterpret_cast<T*>(callback.mImpl.mObjectPointer);
     using MemberFunction    = R (T::*)();
     MemberFunction function = reinterpret_cast<MemberFunction>(callback.mMemberFunction);
     return (object->*function)();
@@ -570,7 +390,7 @@ struct DispatcherReturn1
   static R Dispatch(CallbackBase& callback, P1 param1)
   {
     // "downcast" the object and function type back to the correct ones
-    T* object               = reinterpret_cast<T*>(callback.mImpl->mObjectPointer);
+    T* object               = reinterpret_cast<T*>(callback.mImpl.mObjectPointer);
     using MemberFunction    = R (T::*)(P1);
     MemberFunction function = reinterpret_cast<MemberFunction>(callback.mMemberFunction);
     return (object->*function)(param1);
@@ -596,7 +416,7 @@ struct DispatcherReturn2
   static R Dispatch(CallbackBase& callback, P1 param1, P2 param2)
   {
     // "downcast" the object and function type back to the correct ones
-    T* object               = reinterpret_cast<T*>(callback.mImpl->mObjectPointer);
+    T* object               = reinterpret_cast<T*>(callback.mImpl.mObjectPointer);
     using MemberFunction    = R (T::*)(P1, P2);
     MemberFunction function = reinterpret_cast<MemberFunction>(callback.mMemberFunction);
     return (object->*function)(param1, param2);
@@ -623,7 +443,7 @@ struct DispatcherReturn3
   static R Dispatch(CallbackBase& callback, P1 param1, P2 param2, P3 param3)
   {
     // "downcast" the object and function type back to the correct ones
-    T* object               = reinterpret_cast<T*>(callback.mImpl->mObjectPointer);
+    T* object               = reinterpret_cast<T*>(callback.mImpl.mObjectPointer);
     using MemberFunction    = R (T::*)(P1, P2, P3);
     MemberFunction function = reinterpret_cast<MemberFunction>(callback.mMemberFunction);
     return (object->*function)(param1, param2, param3);
@@ -646,7 +466,7 @@ struct FunctorDispatcher0
   static void Dispatch(CallbackBase& callback)
   {
     // "downcast" the object and function type back to the correct ones
-    T* object = reinterpret_cast<T*>(callback.mImpl->mObjectPointer);
+    T* object = reinterpret_cast<T*>(callback.mImpl.mObjectPointer);
     (*object)();
   }
 };
@@ -668,7 +488,7 @@ struct FunctorDispatcher1
   static void Dispatch(CallbackBase& callback, P1 param1)
   {
     // "downcast" the object and function type back to the correct ones
-    T* object = reinterpret_cast<T*>(callback.mImpl->mObjectPointer);
+    T* object = reinterpret_cast<T*>(callback.mImpl.mObjectPointer);
     (*object)(param1);
   }
 };
@@ -691,7 +511,7 @@ struct FunctorDispatcher2
   static void Dispatch(CallbackBase& callback, P1 param1, P2 param2)
   {
     // "downcast" the object and function type back to the correct ones
-    T* object = reinterpret_cast<T*>(callback.mImpl->mObjectPointer);
+    T* object = reinterpret_cast<T*>(callback.mImpl.mObjectPointer);
     (*object)(param1, param2);
   }
 };
@@ -715,7 +535,7 @@ struct FunctorDispatcher3
   static void Dispatch(CallbackBase& callback, P1 param1, P2 param2, P3 param3)
   {
     // "downcast" the object and function type back to the correct ones
-    T* object = reinterpret_cast<T*>(callback.mImpl->mObjectPointer);
+    T* object = reinterpret_cast<T*>(callback.mImpl.mObjectPointer);
     (*object)(param1, param2, param3);
   }
 };
@@ -737,7 +557,7 @@ struct FunctorDispatcherReturn0
   static R Dispatch(CallbackBase& callback)
   {
     // "downcast" the object and function type back to the correct ones
-    T* object = reinterpret_cast<T*>(callback.mImpl->mObjectPointer);
+    T* object = reinterpret_cast<T*>(callback.mImpl.mObjectPointer);
     return (*object)();
   }
 };
@@ -760,7 +580,7 @@ struct FunctorDispatcherReturn1
   static R Dispatch(CallbackBase& callback, P1 param1)
   {
     // "downcast" the object and function type back to the correct ones
-    T* object = reinterpret_cast<T*>(callback.mImpl->mObjectPointer);
+    T* object = reinterpret_cast<T*>(callback.mImpl.mObjectPointer);
     return (*object)(param1);
   }
 };
@@ -784,7 +604,7 @@ struct FunctorDispatcherReturn2
   static R Dispatch(CallbackBase& callback, P1 param1, P2 param2)
   {
     // "downcast" the object and function type back to the correct ones
-    T* object = reinterpret_cast<T*>(callback.mImpl->mObjectPointer);
+    T* object = reinterpret_cast<T*>(callback.mImpl.mObjectPointer);
     return (*object)(param1, param2);
   }
 };
@@ -809,7 +629,7 @@ struct FunctorDispatcherReturn3
   static R Dispatch(CallbackBase& callback, P1 param1, P2 param2, P3 param3)
   {
     // "downcast" the object and function type back to the correct ones
-    T* object = reinterpret_cast<T*>(callback.mImpl->mObjectPointer);
+    T* object = reinterpret_cast<T*>(callback.mImpl.mObjectPointer);
     return (*object)(param1, param2, param3);
   }
 };
@@ -832,7 +652,7 @@ struct VoidFunctorDispatcher0
   static void Dispatch(CallbackBase& callback)
   {
     // "downcast" the object and function type back to the correct ones
-    T* object               = reinterpret_cast<T*>(callback.mImpl->mObjectPointer);
+    T* object               = reinterpret_cast<T*>(callback.mImpl.mObjectPointer);
     using MemberFunction    = void (T::*)();
     MemberFunction function = reinterpret_cast<MemberFunction>(callback.mMemberFunction);
     (object->*function)();
@@ -858,7 +678,7 @@ struct VoidFunctorDispatcher1
   static void Dispatch(CallbackBase& callback, P1 param1)
   {
     // "downcast" the object and function type back to the correct ones
-    T* object               = reinterpret_cast<T*>(callback.mImpl->mObjectPointer);
+    T* object               = reinterpret_cast<T*>(callback.mImpl.mObjectPointer);
     using MemberFunction    = void (T::*)();
     MemberFunction function = reinterpret_cast<MemberFunction>(callback.mMemberFunction);
     (object->*function)(/*ignore params*/);
@@ -885,7 +705,7 @@ struct VoidFunctorDispatcher2
   static void Dispatch(CallbackBase& callback, P1 param1, P2 param2)
   {
     // "downcast" the object and function type back to the correct ones
-    T* object               = reinterpret_cast<T*>(callback.mImpl->mObjectPointer);
+    T* object               = reinterpret_cast<T*>(callback.mImpl.mObjectPointer);
     using MemberFunction    = void (T::*)();
     MemberFunction function = reinterpret_cast<MemberFunction>(callback.mMemberFunction);
     (object->*function)(/*ignore params*/);
@@ -913,7 +733,7 @@ struct VoidFunctorDispatcher3
   static void Dispatch(CallbackBase& callback, P1 param1, P2 param2, P3 param3)
   {
     // "downcast" the object and function type back to the correct ones
-    T* object               = reinterpret_cast<T*>(callback.mImpl->mObjectPointer);
+    T* object               = reinterpret_cast<T*>(callback.mImpl.mObjectPointer);
     using MemberFunction    = void (T::*)();
     MemberFunction function = reinterpret_cast<MemberFunction>(callback.mMemberFunction);
     (object->*function)(/*ignore params*/);
@@ -939,7 +759,7 @@ struct VoidFunctorDispatcherReturn0
   static R Dispatch(CallbackBase& callback)
   {
     // "downcast" the object and function type back to the correct ones
-    T* object               = reinterpret_cast<T*>(callback.mImpl->mObjectPointer);
+    T* object               = reinterpret_cast<T*>(callback.mImpl.mObjectPointer);
     using MemberFunction    = void (T::*)();
     MemberFunction function = reinterpret_cast<MemberFunction>(callback.mMemberFunction);
     (object->*function)(/*ignore params*/);
@@ -967,7 +787,7 @@ struct VoidFunctorDispatcherReturn1
   static R Dispatch(CallbackBase& callback, P1 param1)
   {
     // "downcast" the object and function type back to the correct ones
-    T* object               = reinterpret_cast<T*>(callback.mImpl->mObjectPointer);
+    T* object               = reinterpret_cast<T*>(callback.mImpl.mObjectPointer);
     using MemberFunction    = void (T::*)();
     MemberFunction function = reinterpret_cast<MemberFunction>(callback.mMemberFunction);
     (object->*function)(/*ignore params*/);
@@ -996,7 +816,7 @@ struct VoidFunctorDispatcherReturn2
   static R Dispatch(CallbackBase& callback, P1 param1, P2 param2)
   {
     // "downcast" the object and function type back to the correct ones
-    T* object               = reinterpret_cast<T*>(callback.mImpl->mObjectPointer);
+    T* object               = reinterpret_cast<T*>(callback.mImpl.mObjectPointer);
     using MemberFunction    = void (T::*)();
     MemberFunction function = reinterpret_cast<MemberFunction>(callback.mMemberFunction);
     (object->*function)(/*ignore params*/);
@@ -1026,7 +846,7 @@ struct VoidFunctorDispatcherReturn3
   static R Dispatch(CallbackBase& callback, P1 param1, P2 param2, P3 param3)
   {
     // "downcast" the object and function type back to the correct ones
-    T* object               = reinterpret_cast<T*>(callback.mImpl->mObjectPointer);
+    T* object               = reinterpret_cast<T*>(callback.mImpl.mObjectPointer);
     using MemberFunction    = void (T::*)();
     MemberFunction function = reinterpret_cast<MemberFunction>(callback.mMemberFunction);
     (object->*function)(/*ignore params*/);
@@ -1120,69 +940,6 @@ public:
 };
 
 /**
- * @brief Specializations for static function callbacks.
- * @SINCE_1_0.0
- */
-class CallbackFunction : public CallbackBase
-{
-public:
-  /**
-   * @brief Default constructor.
-   * @SINCE_1_0.0
-   */
-  CallbackFunction()
-  : CallbackBase()
-  {
-  }
-
-  /**
-   * @brief Constructors for functions with static linkage.
-   *
-   * @SINCE_1_0.0
-   * @param[in] function The function to call
-   */
-  CallbackFunction(void (*function)())
-  : CallbackBase(reinterpret_cast<CallbackBase::Function>(function))
-  {
-  }
-  template<typename R>
-  CallbackFunction(R (*function)())
-  : CallbackBase(reinterpret_cast<CallbackBase::Function>(function))
-  {
-  }
-  template<typename P1>
-  CallbackFunction(void (*function)(P1))
-  : CallbackBase(reinterpret_cast<CallbackBase::Function>(function))
-  {
-  }
-  template<typename P1, typename R>
-  CallbackFunction(R (*function)(P1))
-  : CallbackBase(reinterpret_cast<CallbackBase::Function>(function))
-  {
-  }
-  template<typename P1, typename P2>
-  CallbackFunction(void (*function)(P1, P2))
-  : CallbackBase(reinterpret_cast<CallbackBase::Function>(function))
-  {
-  }
-  template<typename P1, typename P2, typename R>
-  CallbackFunction(R (*function)(P1, P2))
-  : CallbackBase(reinterpret_cast<CallbackBase::Function>(function))
-  {
-  }
-  template<typename P1, typename P2, typename P3>
-  CallbackFunction(void (*function)(P1, P2, P3))
-  : CallbackBase(reinterpret_cast<CallbackBase::Function>(function))
-  {
-  }
-  template<typename P1, typename P2, typename P3, typename R>
-  CallbackFunction(R (*function)(P1, P2, P3))
-  : CallbackBase(reinterpret_cast<CallbackBase::Function>(function))
-  {
-  }
-};
-
-/**
  * @brief Specializations for function object callbacks.
  * @SINCE_1_0.0
  */
@@ -1560,106 +1317,16 @@ public:
 // Callback creation thin templates
 
 /**
- * @brief Creates a callback from a C function or static member function with no parameters.
- *
- * @SINCE_1_0.0
- * @param[in] function The function to call
- * @return A newly allocated Callback object, ownership transferred to caller
- */
-inline CallbackBase* MakeCallback(void (*function)(void))
-{
-  return new CallbackFunction(function);
-}
-
-/**
- * @brief Creates a callback from a C function or static member function with one parameter.
- *
- * @SINCE_1_0.0
- * @param[in] function The function to call
- * @return A newly allocated Callback object, ownership transferred to caller
- */
-template<typename P1>
-inline CallbackBase* MakeCallback(void (*function)(P1))
-{
-  return new CallbackFunction(function);
-}
-
-/**
- * @brief Creates a callback from a C function or static member function with no parameters and a return type.
- *
- * @SINCE_1_0.0
- * @param[in] function The function to call
- * @return A newly allocated Callback object, ownership transferred to caller
- */
-template<typename R>
-inline CallbackBase* MakeCallback(R (*function)(void))
-{
-  return new CallbackFunction(function);
-}
-
-/**
- * @brief Creates a callback from a C function or static member function with one parameter and a return type.
+ * @brief Creates a callback from a free function with parameter pack.
  *
- * @SINCE_1_0.0
- * @param[in] function The function to call
- * @return A newly allocated Callback object, ownership transferred to caller
- */
-template<typename R, typename P1>
-inline CallbackBase* MakeCallback(R (*function)(P1))
-{
-  return new CallbackFunction(function);
-}
-
-/**
- * @brief Creates a callback from a C function or static member function with two parameters.
- *
- * @SINCE_1_0.0
- * @param[in] function The function to call
- * @return A newly allocated Callback object, ownership transferred to caller
- */
-template<typename P1, typename P2>
-inline CallbackBase* MakeCallback(void (*function)(P1, P2))
-{
-  return new CallbackFunction(function);
-}
-
-/**
- * @brief Creates a callback from a C function or static member function with two parameters and a return type.
- *
- * @SINCE_1_0.0
- * @param[in] function The function to call
- * @return A newly allocated Callback object, ownership transferred to caller
- */
-template<typename R, typename P1, typename P2>
-inline CallbackBase* MakeCallback(R (*function)(P1, P2))
-{
-  return new CallbackFunction(function);
-}
-
-/**
- * @brief Creates a callback from a C function or static member function with three parameters.
- *
- * @SINCE_1_0.0
- * @param[in] function The function to call
- * @return A newly allocated Callback object, ownership transferred to caller
- */
-template<typename P1, typename P2, typename P3>
-inline CallbackBase* MakeCallback(void (*function)(P1, P2, P3))
-{
-  return new CallbackFunction(function);
-}
-
-/**
- * @brief Creates a callback from a C function or static member function with three parameters and a return type.
- *
- * @SINCE_1_0.0
+ * @SINCE_1_9.33
  * @param[in] function The function to call
  * @return A newly allocated Callback object, ownership transferred to caller
  */
-template<typename R, typename P1, typename P2, typename P3>
-inline CallbackBase* MakeCallback(R (*function)(P1, P2, P3))
+template<typename R, typename... Args>
+inline CallbackBase* MakeCallback(R (*function)(Args... args))
 {
-  return new CallbackFunction(function);
+  return new CallbackBase(reinterpret_cast<CallbackBase::Function>(function));
 }
 
 /**
index fbab2a4..ef7a4c5 100644 (file)
@@ -39,12 +39,11 @@ void ConnectionTracker::DisconnectAll()
 
   for(std::size_t i = 0; i < size; ++i)
   {
-    SlotConnection* connection = mConnections[i];
+    auto& connection = mConnections[i];
 
     // Tell the signal that the slot is disconnected
-    connection->GetSlotObserver()->SlotDisconnected(connection->GetCallback());
+    connection.GetSlotObserver()->SlotDisconnected(connection.GetCallback());
 
-    delete connection;
   }
 
   mConnections.Clear();
@@ -52,8 +51,7 @@ void ConnectionTracker::DisconnectAll()
 
 void ConnectionTracker::SignalConnected(SlotObserver* slotObserver, CallbackBase* callback)
 {
-  SlotConnection* connection = new SlotConnection(slotObserver, callback);
-  mConnections.PushBack(connection);
+  mConnections.PushBack(SlotConnection(slotObserver, callback));
 }
 
 void ConnectionTracker::SignalDisconnected(SlotObserver* signal, CallbackBase* callback)
@@ -62,17 +60,14 @@ void ConnectionTracker::SignalDisconnected(SlotObserver* signal, CallbackBase* c
 
   for(std::size_t i = 0; i < size; ++i)
   {
-    SlotConnection* connection = mConnections[i];
+    auto& connection = mConnections[i];
 
     // Pointer comparison i.e. SignalConnection contains pointer to same callback instance
-    if(connection->GetCallback() == callback)
+    if(connection.GetCallback() == callback)
     {
       // Remove from connection list
       mConnections.Erase(mConnections.Begin() + i);
 
-      // Delete connection
-      delete connection;
-
       // Disconnection complete
       return;
     }
index 2d1538a..d2f6262 100644 (file)
@@ -22,6 +22,7 @@
 #include <dali/public-api/common/dali-common.h>
 #include <dali/public-api/common/dali-vector.h>
 #include <dali/public-api/signals/connection-tracker-interface.h>
+#include <dali/public-api/signals/signal-slot-connections.h>
 
 namespace Dali
 {
@@ -83,7 +84,7 @@ private:
   ConnectionTracker& operator=(ConnectionTracker&&) = delete;      ///< Deleted move assignment operator. @SINCE_1_9.25
 
 private:
-  Dali::Vector<SlotConnection*> mConnections; ///< Vector of connection pointers
+  Dali::Vector<SlotConnection> mConnections; ///< Vector of connection
 };
 
 /**
index 7931c6a..c4fd2ed 100644 (file)
@@ -52,6 +52,9 @@
  * @SINCE_1_0.0
  */
 
+// EXTERNAL_INCLUDES
+#include <memory>
+
 // INTERNAL INCLUDES
 #include <dali/public-api/common/dali-common.h>
 #include <dali/public-api/signals/base-signal.h>
@@ -137,31 +140,10 @@ class Signal
 {
 };
 
-/**
- * @brief A template for Signals with no parameters or return value.
- * @SINCE_1_0.0
- */
-template<>
-class Signal<void()>
+class SignalMixin
 {
 public:
   /**
-   * @brief Default constructor.
-   * @SINCE_1_0.0
-   */
-  Signal()
-  {
-  }
-
-  /**
-   * @brief Non-virtual destructor.
-   * @SINCE_1_0.0
-   */
-  ~Signal()
-  {
-  }
-
-  /**
    * @brief Queries whether there are any connected slots.
    *
    * @SINCE_1_0.0
@@ -169,7 +151,7 @@ public:
    */
   bool Empty() const
   {
-    return mImpl.Empty();
+    return mImpl ? mImpl->Empty() : true;
   }
 
   /**
@@ -180,9 +162,31 @@ public:
    */
   std::size_t GetConnectionCount() const
   {
-    return mImpl.GetConnectionCount();
+    return mImpl ? mImpl->GetConnectionCount() : 0;
   }
 
+protected:
+  BaseSignal& Impl()
+  {
+    if(!mImpl)
+    {
+      mImpl = std::make_unique<BaseSignal>();
+    }
+    return *mImpl;
+  }
+
+private:
+  std::unique_ptr<BaseSignal> mImpl;
+};
+
+/**
+ * @brief A template for Signals with no parameters or return value.
+ * @SINCE_1_0.0
+ */
+template<>
+class Signal<void()> : public SignalMixin
+{
+public:
   /**
    * @brief Connects a function.
    *
@@ -191,7 +195,7 @@ public:
    */
   void Connect(void (*func)())
   {
-    mImpl.OnConnect(MakeCallback(func));
+    Impl().OnConnect(MakeCallback(func));
   }
 
   /**
@@ -202,7 +206,7 @@ public:
    */
   void Disconnect(void (*func)())
   {
-    mImpl.OnDisconnect(MakeCallback(func));
+    Impl().OnDisconnect(MakeCallback(func));
   }
 
   /**
@@ -215,7 +219,7 @@ public:
   template<class X>
   void Connect(X* obj, void (X::*func)())
   {
-    mImpl.OnConnect(obj, MakeCallback(obj, func));
+    Impl().OnConnect(obj, MakeCallback(obj, func));
   }
 
   /**
@@ -228,7 +232,7 @@ public:
   template<class X>
   void Disconnect(X* obj, void (X::*func)())
   {
-    mImpl.OnDisconnect(obj, MakeCallback(obj, func));
+    Impl().OnDisconnect(obj, MakeCallback(obj, func));
   }
 
   /**
@@ -241,7 +245,7 @@ public:
   template<class X>
   void Connect(SlotDelegate<X>& delegate, void (X::*func)())
   {
-    mImpl.OnConnect(delegate.GetConnectionTracker(), MakeCallback(delegate.GetSlot(), func));
+    Impl().OnConnect(delegate.GetConnectionTracker(), MakeCallback(delegate.GetSlot(), func));
   }
 
   /**
@@ -254,7 +258,7 @@ public:
   template<class X>
   void Disconnect(SlotDelegate<X>& delegate, void (X::*func)())
   {
-    mImpl.OnDisconnect(delegate.GetConnectionTracker(), MakeCallback(delegate.GetSlot(), func));
+    Impl().OnDisconnect(delegate.GetConnectionTracker(), MakeCallback(delegate.GetSlot(), func));
   }
 
   /**
@@ -267,7 +271,7 @@ public:
   template<class X>
   void Connect(ConnectionTrackerInterface* connectionTracker, const X& func)
   {
-    mImpl.OnConnect(connectionTracker, new CallbackFunctor0<X>(func));
+    Impl().OnConnect(connectionTracker, new CallbackFunctor0<X>(func));
   }
 
   /**
@@ -279,7 +283,7 @@ public:
    */
   void Connect(ConnectionTrackerInterface* connectionTracker, FunctorDelegate* delegate)
   {
-    mImpl.OnConnect(connectionTracker, new CallbackFunctorDelegate0(delegate));
+    Impl().OnConnect(connectionTracker, new CallbackFunctorDelegate0(delegate));
   }
 
   /**
@@ -288,18 +292,8 @@ public:
    */
   void Emit()
   {
-    mImpl.Emit();
+    Impl().Emit();
   }
-
-private:
-  Signal(const Signal&) = delete;            ///< Deleted copy constructor, signals don't support copying. @SINCE_1_0.0
-  Signal(Signal&&)      = delete;            ///< Deleted move constructor, signals don't support moving. @SINCE_1_9.25
-  Signal& operator=(const Signal&) = delete; ///< Deleted copy assignment operator @SINCE_1_0.0
-  Signal& operator=(Signal&&) = delete;      ///< Deleted move assignment operator @SINCE_1_9.25
-
-private:
-  // Use composition instead of inheritance (virtual methods don't mix well with templates)
-  BaseSignal mImpl; ///< The base signal implementation
 };
 
 /**
@@ -307,47 +301,10 @@ private:
  * @SINCE_1_0.0
  */
 template<typename Ret>
-class Signal<Ret()>
+class Signal<Ret()> : public SignalMixin
 {
 public:
   /**
-   * @brief Default constructor.
-   * @SINCE_1_0.0
-   */
-  Signal()
-  {
-  }
-
-  /**
-   * @brief Non-virtual destructor.
-   * @SINCE_1_0.0
-   */
-  ~Signal()
-  {
-  }
-
-  /**
-   * @brief Queries whether there are any connected slots.
-   *
-   * @SINCE_1_0.0
-   * @return True if there are any slots connected to the signal
-   */
-  bool Empty() const
-  {
-    return mImpl.Empty();
-  }
-
-  /**
-   * @brief Queries the number of slots.
-   *
-   * @SINCE_1_0.0
-   * @return The number of slots connected to this signal
-   */
-  std::size_t GetConnectionCount() const
-  {
-    return mImpl.GetConnectionCount();
-  }
-  /**
    * @brief Connects a function.
    *
    * @SINCE_1_0.0
@@ -355,7 +312,7 @@ public:
    */
   void Connect(Ret (*func)())
   {
-    mImpl.OnConnect(MakeCallback(func));
+    Impl().OnConnect(MakeCallback(func));
   }
 
   /**
@@ -366,7 +323,7 @@ public:
    */
   void Disconnect(Ret (*func)())
   {
-    mImpl.OnDisconnect(MakeCallback(func));
+    Impl().OnDisconnect(MakeCallback(func));
   }
 
   /**
@@ -379,7 +336,7 @@ public:
   template<class X>
   void Connect(X* obj, Ret (X::*func)())
   {
-    mImpl.OnConnect(obj, MakeCallback(obj, func));
+    Impl().OnConnect(obj, MakeCallback(obj, func));
   }
 
   /**
@@ -392,7 +349,7 @@ public:
   template<class X>
   void Disconnect(X* obj, Ret (X::*func)())
   {
-    mImpl.OnDisconnect(obj, MakeCallback(obj, func));
+    Impl().OnDisconnect(obj, MakeCallback(obj, func));
   }
 
   /**
@@ -405,7 +362,7 @@ public:
   template<class X>
   void Connect(SlotDelegate<X>& delegate, Ret (X::*func)())
   {
-    mImpl.OnConnect(delegate.GetConnectionTracker(), MakeCallback(delegate.GetSlot(), func));
+    Impl().OnConnect(delegate.GetConnectionTracker(), MakeCallback(delegate.GetSlot(), func));
   }
 
   /**
@@ -418,7 +375,7 @@ public:
   template<class X>
   void Disconnect(SlotDelegate<X>& delegate, Ret (X::*func)())
   {
-    mImpl.OnDisconnect(delegate.GetConnectionTracker(), MakeCallback(delegate.GetSlot(), func));
+    Impl().OnDisconnect(delegate.GetConnectionTracker(), MakeCallback(delegate.GetSlot(), func));
   }
 
   /**
@@ -431,7 +388,7 @@ public:
   template<class X>
   void Connect(ConnectionTrackerInterface* connectionTracker, const X& func)
   {
-    mImpl.OnConnect(connectionTracker, new CallbackFunctorReturn0<X, Ret>(func));
+    Impl().OnConnect(connectionTracker, new CallbackFunctorReturn0<X, Ret>(func));
   }
 
   /**
@@ -443,7 +400,7 @@ public:
    */
   void Connect(ConnectionTrackerInterface* connectionTracker, FunctorDelegate* delegate)
   {
-    mImpl.OnConnect(connectionTracker, new CallbackFunctorDelegateReturn0<Ret>(delegate));
+    Impl().OnConnect(connectionTracker, new CallbackFunctorDelegateReturn0<Ret>(delegate));
   }
 
   /**
@@ -454,18 +411,8 @@ public:
    */
   Ret Emit()
   {
-    return mImpl.EmitReturn<Ret>();
+    return Impl().template EmitReturn<Ret>();
   }
-
-private:
-  Signal(const Signal&) = delete;            ///< Deleted copy constructor, signals don't support copying. @SINCE_1_0.0
-  Signal(Signal&&)      = delete;            ///< Deleted move constructor, signals don't support moving. @SINCE_1_9.25
-  Signal& operator=(const Signal&) = delete; ///< Deleted copy assignment operator @SINCE_1_0.0
-  Signal& operator=(Signal&&) = delete;      ///< Deleted move assignment operator @SINCE_1_9.25
-
-private:
-  // Use composition instead of inheritance (virtual methods don't mix well with templates)
-  BaseSignal mImpl; ///< Implementation
 };
 
 /**
@@ -473,47 +420,10 @@ private:
  * @SINCE_1_0.0
  */
 template<typename Arg0>
-class Signal<void(Arg0)>
+class Signal<void(Arg0)> : public SignalMixin
 {
 public:
   /**
-   * @brief Default constructor.
-   * @SINCE_1_0.0
-   */
-  Signal()
-  {
-  }
-
-  /**
-   * @brief Non-virtual destructor.
-   * @SINCE_1_0.0
-   */
-  ~Signal()
-  {
-  }
-
-  /**
-   * @brief Queries whether there are any connected slots.
-   *
-   * @SINCE_1_0.0
-   * @return True if there are any slots connected to the signal
-   */
-  bool Empty() const
-  {
-    return mImpl.Empty();
-  }
-
-  /**
-   * @brief Queries the number of slots.
-   *
-   * @SINCE_1_0.0
-   * @return The number of slots connected to this signal
-   */
-  std::size_t GetConnectionCount() const
-  {
-    return mImpl.GetConnectionCount();
-  }
-  /**
    * @brief Connects a function.
    *
    * @SINCE_1_0.0
@@ -521,7 +431,7 @@ public:
    */
   void Connect(void (*func)(Arg0 arg0))
   {
-    mImpl.OnConnect(MakeCallback(func));
+    Impl().OnConnect(MakeCallback(func));
   }
 
   /**
@@ -532,7 +442,7 @@ public:
    */
   void Disconnect(void (*func)(Arg0 arg0))
   {
-    mImpl.OnDisconnect(MakeCallback(func));
+    Impl().OnDisconnect(MakeCallback(func));
   }
 
   /**
@@ -545,7 +455,7 @@ public:
   template<class X>
   void Connect(X* obj, void (X::*func)(Arg0 arg0))
   {
-    mImpl.OnConnect(obj, MakeCallback(obj, func));
+    Impl().OnConnect(obj, MakeCallback(obj, func));
   }
 
   /**
@@ -558,7 +468,7 @@ public:
   template<class X>
   void Disconnect(X* obj, void (X::*func)(Arg0 arg0))
   {
-    mImpl.OnDisconnect(obj, MakeCallback(obj, func));
+    Impl().OnDisconnect(obj, MakeCallback(obj, func));
   }
 
   /**
@@ -571,7 +481,7 @@ public:
   template<class X>
   void Connect(SlotDelegate<X>& delegate, void (X::*func)(Arg0 arg0))
   {
-    mImpl.OnConnect(delegate.GetConnectionTracker(), MakeCallback(delegate.GetSlot(), func));
+    Impl().OnConnect(delegate.GetConnectionTracker(), MakeCallback(delegate.GetSlot(), func));
   }
 
   /**
@@ -584,7 +494,7 @@ public:
   template<class X>
   void Disconnect(SlotDelegate<X>& delegate, void (X::*func)(Arg0 arg0))
   {
-    mImpl.OnDisconnect(delegate.GetConnectionTracker(), MakeCallback(delegate.GetSlot(), func));
+    Impl().OnDisconnect(delegate.GetConnectionTracker(), MakeCallback(delegate.GetSlot(), func));
   }
 
   /**
@@ -597,7 +507,7 @@ public:
   template<class X>
   void Connect(ConnectionTrackerInterface* connectionTracker, const X& func)
   {
-    mImpl.OnConnect(connectionTracker, new CallbackFunctor1<X, Arg0>(func));
+    Impl().OnConnect(connectionTracker, new CallbackFunctor1<X, Arg0>(func));
   }
 
   /**
@@ -609,7 +519,7 @@ public:
    */
   void Connect(ConnectionTrackerInterface* connectionTracker, FunctorDelegate* delegate)
   {
-    mImpl.OnConnect(connectionTracker, new CallbackFunctorDelegate1<Arg0>(delegate));
+    Impl().OnConnect(connectionTracker, new CallbackFunctorDelegate1<Arg0>(delegate));
   }
 
   /**
@@ -620,18 +530,8 @@ public:
    */
   void Emit(Arg0 arg0)
   {
-    mImpl.Emit<Arg0>(arg0);
+    Impl().template Emit<Arg0>(arg0);
   }
-
-private:
-  Signal(const Signal&) = delete;            ///< Deleted copy constructor, signals don't support copying. @SINCE_1_0.0
-  Signal(Signal&&)      = delete;            ///< Deleted move constructor, signals don't support moving. @SINCE_1_9.25
-  Signal& operator=(const Signal&) = delete; ///< Deleted copy assignment operator @SINCE_1_0.0
-  Signal& operator=(Signal&&) = delete;      ///< Deleted move assignment operator @SINCE_1_9.25
-
-private:
-  // Use composition instead of inheritance (virtual methods don't mix well with templates)
-  BaseSignal mImpl; ///< Implementation
 };
 
 /**
@@ -639,47 +539,10 @@ private:
  * @SINCE_1_0.0
  */
 template<typename Ret, typename Arg0>
-class Signal<Ret(Arg0)>
+class Signal<Ret(Arg0)> : public SignalMixin
 {
 public:
   /**
-   * @brief Default constructor.
-   * @SINCE_1_0.0
-   */
-  Signal()
-  {
-  }
-
-  /**
-   * @brief Non-virtual destructor.
-   * @SINCE_1_0.0
-   */
-  ~Signal()
-  {
-  }
-
-  /**
-   * @brief Queries whether there are any connected slots.
-   *
-   * @SINCE_1_0.0
-   * @return True if there are any slots connected to the signal
-   */
-  bool Empty() const
-  {
-    return mImpl.Empty();
-  }
-
-  /**
-   * @brief Queries the number of slots.
-   *
-   * @SINCE_1_0.0
-   * @return The number of slots connected to this signal
-   */
-  std::size_t GetConnectionCount() const
-  {
-    return mImpl.GetConnectionCount();
-  }
-  /**
    * @brief Connects a function.
    *
    * @SINCE_1_0.0
@@ -687,7 +550,7 @@ public:
    */
   void Connect(Ret (*func)(Arg0 arg0))
   {
-    mImpl.OnConnect(MakeCallback(func));
+    Impl().OnConnect(MakeCallback(func));
   }
 
   /**
@@ -698,7 +561,7 @@ public:
    */
   void Disconnect(Ret (*func)(Arg0 arg0))
   {
-    mImpl.OnDisconnect(MakeCallback(func));
+    Impl().OnDisconnect(MakeCallback(func));
   }
 
   /**
@@ -711,7 +574,7 @@ public:
   template<class X>
   void Connect(X* obj, Ret (X::*func)(Arg0 arg0))
   {
-    mImpl.OnConnect(obj, MakeCallback(obj, func));
+    Impl().OnConnect(obj, MakeCallback(obj, func));
   }
 
   /**
@@ -724,7 +587,7 @@ public:
   template<class X>
   void Disconnect(X* obj, Ret (X::*func)(Arg0 arg0))
   {
-    mImpl.OnDisconnect(obj, MakeCallback(obj, func));
+    Impl().OnDisconnect(obj, MakeCallback(obj, func));
   }
 
   /**
@@ -737,7 +600,7 @@ public:
   template<class X>
   void Connect(SlotDelegate<X>& delegate, Ret (X::*func)(Arg0 arg0))
   {
-    mImpl.OnConnect(delegate.GetConnectionTracker(), MakeCallback(delegate.GetSlot(), func));
+    Impl().OnConnect(delegate.GetConnectionTracker(), MakeCallback(delegate.GetSlot(), func));
   }
 
   /**
@@ -750,7 +613,7 @@ public:
   template<class X>
   void Disconnect(SlotDelegate<X>& delegate, Ret (X::*func)(Arg0 arg0))
   {
-    mImpl.OnDisconnect(delegate.GetConnectionTracker(), MakeCallback(delegate.GetSlot(), func));
+    Impl().OnDisconnect(delegate.GetConnectionTracker(), MakeCallback(delegate.GetSlot(), func));
   }
 
   /**
@@ -763,7 +626,7 @@ public:
   template<class X>
   void Connect(ConnectionTrackerInterface* connectionTracker, const X& func)
   {
-    mImpl.OnConnect(connectionTracker, new CallbackFunctorReturn1<X, Arg0, Ret>(func));
+    Impl().OnConnect(connectionTracker, new CallbackFunctorReturn1<X, Arg0, Ret>(func));
   }
 
   /**
@@ -775,7 +638,7 @@ public:
    */
   void Connect(ConnectionTrackerInterface* connectionTracker, FunctorDelegate* delegate)
   {
-    mImpl.OnConnect(connectionTracker, new CallbackFunctorDelegateReturn1<Arg0, Ret>(delegate));
+    Impl().OnConnect(connectionTracker, new CallbackFunctorDelegateReturn1<Arg0, Ret>(delegate));
   }
 
   /**
@@ -787,18 +650,8 @@ public:
    */
   Ret Emit(Arg0 arg0)
   {
-    return mImpl.EmitReturn<Ret, Arg0>(arg0);
+    return Impl().template EmitReturn<Ret, Arg0>(arg0);
   }
-
-private:
-  Signal(const Signal&) = delete;            ///< Deleted copy constructor, signals don't support copying. @SINCE_1_0.0
-  Signal(Signal&&)      = delete;            ///< Deleted move constructor, signals don't support moving. @SINCE_1_9.25
-  Signal& operator=(const Signal&) = delete; ///< Deleted copy assignment operator @SINCE_1_0.0
-  Signal& operator=(Signal&&) = delete;      ///< Deleted move assignment operator @SINCE_1_9.25
-
-private:
-  // Use composition instead of inheritance (virtual methods don't mix well with templates)
-  BaseSignal mImpl; ///< Implementation
 };
 
 /**
@@ -807,49 +660,10 @@ private:
  * @SINCE_1_0.0
  */
 template<typename Arg0, typename Arg1>
-class Signal<void(Arg0, Arg1)>
+class Signal<void(Arg0, Arg1)> : public SignalMixin
 {
 public:
   /**
-   * @brief Default constructor.
-   *
-   * @SINCE_1_0.0
-   */
-  Signal()
-  {
-  }
-
-  /**
-   * @brief Non-virtual destructor.
-   *
-   * @SINCE_1_0.0
-   */
-  ~Signal()
-  {
-  }
-
-  /**
-   * @brief Queries whether there are any connected slots.
-   *
-   * @SINCE_1_0.0
-   * @return True if there are any slots connected to the signal
-   */
-  bool Empty() const
-  {
-    return mImpl.Empty();
-  }
-
-  /**
-   * @brief Queries the number of slots.
-   *
-   * @SINCE_1_0.0
-   * @return The number of slots connected to this signal
-   */
-  std::size_t GetConnectionCount() const
-  {
-    return mImpl.GetConnectionCount();
-  }
-  /**
    * @brief Connects a function.
    *
    * @SINCE_1_0.0
@@ -857,7 +671,7 @@ public:
    */
   void Connect(void (*func)(Arg0 arg0, Arg1 arg1))
   {
-    mImpl.OnConnect(MakeCallback(func));
+    Impl().OnConnect(MakeCallback(func));
   }
 
   /**
@@ -868,7 +682,7 @@ public:
    */
   void Disconnect(void (*func)(Arg0 arg0, Arg1 arg1))
   {
-    mImpl.OnDisconnect(MakeCallback(func));
+    Impl().OnDisconnect(MakeCallback(func));
   }
 
   /**
@@ -881,7 +695,7 @@ public:
   template<class X>
   void Connect(X* obj, void (X::*func)(Arg0 arg0, Arg1 arg1))
   {
-    mImpl.OnConnect(obj, MakeCallback(obj, func));
+    Impl().OnConnect(obj, MakeCallback(obj, func));
   }
 
   /**
@@ -894,7 +708,7 @@ public:
   template<class X>
   void Disconnect(X* obj, void (X::*func)(Arg0 arg0, Arg1 arg1))
   {
-    mImpl.OnDisconnect(obj, MakeCallback(obj, func));
+    Impl().OnDisconnect(obj, MakeCallback(obj, func));
   }
 
   /**
@@ -907,7 +721,7 @@ public:
   template<class X>
   void Connect(SlotDelegate<X>& delegate, void (X::*func)(Arg0 arg0, Arg1 arg1))
   {
-    mImpl.OnConnect(delegate.GetConnectionTracker(), MakeCallback(delegate.GetSlot(), func));
+    Impl().OnConnect(delegate.GetConnectionTracker(), MakeCallback(delegate.GetSlot(), func));
   }
 
   /**
@@ -920,7 +734,7 @@ public:
   template<class X>
   void Disconnect(SlotDelegate<X>& delegate, void (X::*func)(Arg0 arg0, Arg1 arg1))
   {
-    mImpl.OnDisconnect(delegate.GetConnectionTracker(), MakeCallback(delegate.GetSlot(), func));
+    Impl().OnDisconnect(delegate.GetConnectionTracker(), MakeCallback(delegate.GetSlot(), func));
   }
 
   /**
@@ -933,7 +747,7 @@ public:
   template<class X>
   void Connect(ConnectionTrackerInterface* connectionTracker, const X& func)
   {
-    mImpl.OnConnect(connectionTracker, new CallbackFunctor2<X, Arg0, Arg1>(func));
+    Impl().OnConnect(connectionTracker, new CallbackFunctor2<X, Arg0, Arg1>(func));
   }
 
   /**
@@ -945,7 +759,7 @@ public:
    */
   void Connect(ConnectionTrackerInterface* connectionTracker, FunctorDelegate* delegate)
   {
-    mImpl.OnConnect(connectionTracker, new CallbackFunctorDelegate2<Arg0, Arg1>(delegate));
+    Impl().OnConnect(connectionTracker, new CallbackFunctorDelegate2<Arg0, Arg1>(delegate));
   }
 
   /**
@@ -957,18 +771,8 @@ public:
    */
   void Emit(Arg0 arg0, Arg1 arg1)
   {
-    mImpl.Emit<Arg0, Arg1>(arg0, arg1);
+    Impl().template Emit<Arg0, Arg1>(arg0, arg1);
   }
-
-private:
-  Signal(const Signal&) = delete;            ///< Deleted copy constructor, signals don't support copying. @SINCE_1_0.0
-  Signal(Signal&&)      = delete;            ///< Deleted move constructor, signals don't support moving. @SINCE_1_9.25
-  Signal& operator=(const Signal&) = delete; ///< Deleted copy assignment operator @SINCE_1_0.0
-  Signal& operator=(Signal&&) = delete;      ///< Deleted move assignment operator @SINCE_1_9.25
-
-private:
-  // Use composition instead of inheritance (virtual methods don't mix well with templates)
-  BaseSignal mImpl; ///< Implementation
 };
 
 /**
@@ -976,54 +780,17 @@ private:
  * @SINCE_1_0.0
  */
 template<typename Ret, typename Arg0, typename Arg1>
-class Signal<Ret(Arg0, Arg1)>
+class Signal<Ret(Arg0, Arg1)> : public SignalMixin
 {
 public:
   /**
-   * @brief Default constructor.
-   * @SINCE_1_0.0
-   */
-  Signal()
-  {
-  }
-
-  /**
-   * @brief Non-virtual destructor.
-   * @SINCE_1_0.0
-   */
-  ~Signal()
-  {
-  }
-
-  /**
-   * @brief Queries whether there are any connected slots.
-   *
-   * @SINCE_1_0.0
-   * @return True if there are any slots connected to the signal
-   */
-  bool Empty() const
-  {
-    return mImpl.Empty();
-  }
-
-  /**
-   * @brief Queries the number of slots.
-   *
-   * @SINCE_1_0.0
-   * @return The number of slots connected to this signal
-   */
-  std::size_t GetConnectionCount() const
-  {
-    return mImpl.GetConnectionCount();
-  }
-  /**
    * @brief Connects a function.
    * @SINCE_1_0.0
    * @param[in] func The function to connect
    */
   void Connect(Ret (*func)(Arg0 arg0, Arg1 arg1))
   {
-    mImpl.OnConnect(MakeCallback(func));
+    Impl().OnConnect(MakeCallback(func));
   }
 
   /**
@@ -1034,7 +801,7 @@ public:
    */
   void Disconnect(Ret (*func)(Arg0 arg0, Arg1 arg1))
   {
-    mImpl.OnDisconnect(MakeCallback(func));
+    Impl().OnDisconnect(MakeCallback(func));
   }
 
   /**
@@ -1047,7 +814,7 @@ public:
   template<class X>
   void Connect(X* obj, Ret (X::*func)(Arg0 arg0, Arg1 arg1))
   {
-    mImpl.OnConnect(obj, MakeCallback(obj, func));
+    Impl().OnConnect(obj, MakeCallback(obj, func));
   }
 
   /**
@@ -1060,7 +827,7 @@ public:
   template<class X>
   void Disconnect(X* obj, Ret (X::*func)(Arg0 arg0, Arg1 arg1))
   {
-    mImpl.OnDisconnect(obj, MakeCallback(obj, func));
+    Impl().OnDisconnect(obj, MakeCallback(obj, func));
   }
 
   /**
@@ -1073,7 +840,7 @@ public:
   template<class X>
   void Connect(SlotDelegate<X>& delegate, Ret (X::*func)(Arg0 arg0, Arg1 arg1))
   {
-    mImpl.OnConnect(delegate.GetConnectionTracker(), MakeCallback(delegate.GetSlot(), func));
+    Impl().OnConnect(delegate.GetConnectionTracker(), MakeCallback(delegate.GetSlot(), func));
   }
 
   /**
@@ -1086,7 +853,7 @@ public:
   template<class X>
   void Disconnect(SlotDelegate<X>& delegate, Ret (X::*func)(Arg0 arg0, Arg1 arg1))
   {
-    mImpl.OnDisconnect(delegate.GetConnectionTracker(), MakeCallback(delegate.GetSlot(), func));
+    Impl().OnDisconnect(delegate.GetConnectionTracker(), MakeCallback(delegate.GetSlot(), func));
   }
 
   /**
@@ -1099,7 +866,7 @@ public:
   template<class X>
   void Connect(ConnectionTrackerInterface* connectionTracker, const X& func)
   {
-    mImpl.OnConnect(connectionTracker, new CallbackFunctorReturn2<X, Arg0, Arg1, Ret>(func));
+    Impl().OnConnect(connectionTracker, new CallbackFunctorReturn2<X, Arg0, Arg1, Ret>(func));
   }
 
   /**
@@ -1111,7 +878,7 @@ public:
    */
   void Connect(ConnectionTrackerInterface* connectionTracker, FunctorDelegate* delegate)
   {
-    mImpl.OnConnect(connectionTracker, new CallbackFunctorDelegateReturn2<Arg0, Arg1, Ret>(delegate));
+    Impl().OnConnect(connectionTracker, new CallbackFunctorDelegateReturn2<Arg0, Arg1, Ret>(delegate));
   }
 
   /**
@@ -1124,18 +891,8 @@ public:
    */
   Ret Emit(Arg0 arg0, Arg1 arg1)
   {
-    return mImpl.EmitReturn<Ret, Arg0, Arg1>(arg0, arg1);
+    return Impl().template EmitReturn<Ret, Arg0, Arg1>(arg0, arg1);
   }
-
-private:
-  Signal(const Signal&) = delete;            ///< Deleted copy constructor, signals don't support copying. @SINCE_1_0.0
-  Signal(Signal&&)      = delete;            ///< Deleted move constructor, signals don't support moving. @SINCE_1_9.25
-  Signal& operator=(const Signal&) = delete; ///< Deleted copy assignment operator @SINCE_1_0.0
-  Signal& operator=(Signal&&) = delete;      ///< Deleted move assignment operator @SINCE_1_9.25
-
-private:
-  // Use composition instead of inheritance (virtual methods don't mix well with templates)
-  BaseSignal mImpl; ///< Implementation
 };
 
 /**
@@ -1143,47 +900,10 @@ private:
  * @SINCE_1_0.0
  */
 template<typename Arg0, typename Arg1, typename Arg2>
-class Signal<void(Arg0, Arg1, Arg2)>
+class Signal<void(Arg0, Arg1, Arg2)> : public SignalMixin
 {
 public:
   /**
-   * @brief Default constructor.
-   * @SINCE_1_0.0
-   */
-  Signal()
-  {
-  }
-
-  /**
-   * @brief Non-virtual destructor.
-   * @SINCE_1_0.0
-   */
-  ~Signal()
-  {
-  }
-
-  /**
-   * @brief Queries whether there are any connected slots.
-   *
-   * @SINCE_1_0.0
-   * @return True if there are any slots connected to the signal
-   */
-  bool Empty() const
-  {
-    return mImpl.Empty();
-  }
-
-  /**
-   * @brief Queries the number of slots.
-   *
-   * @SINCE_1_0.0
-   * @return The number of slots connected to this signal
-   */
-  std::size_t GetConnectionCount() const
-  {
-    return mImpl.GetConnectionCount();
-  }
-  /**
    * @brief Connects a function.
    *
    * @SINCE_1_0.0
@@ -1191,7 +911,7 @@ public:
    */
   void Connect(void (*func)(Arg0 arg0, Arg1 arg1, Arg2 arg2))
   {
-    mImpl.OnConnect(MakeCallback(func));
+    Impl().OnConnect(MakeCallback(func));
   }
 
   /**
@@ -1202,7 +922,7 @@ public:
    */
   void Disconnect(void (*func)(Arg0 arg0, Arg1 arg1, Arg2 arg2))
   {
-    mImpl.OnDisconnect(MakeCallback(func));
+    Impl().OnDisconnect(MakeCallback(func));
   }
 
   /**
@@ -1215,7 +935,7 @@ public:
   template<class X>
   void Connect(X* obj, void (X::*func)(Arg0 arg0, Arg1 arg1, Arg2 arg2))
   {
-    mImpl.OnConnect(obj, MakeCallback(obj, func));
+    Impl().OnConnect(obj, MakeCallback(obj, func));
   }
 
   /**
@@ -1228,7 +948,7 @@ public:
   template<class X>
   void Disconnect(X* obj, void (X::*func)(Arg0 arg0, Arg1 arg1, Arg2 arg2))
   {
-    mImpl.OnDisconnect(obj, MakeCallback(obj, func));
+    Impl().OnDisconnect(obj, MakeCallback(obj, func));
   }
 
   /**
@@ -1241,7 +961,7 @@ public:
   template<class X>
   void Connect(SlotDelegate<X>& delegate, void (X::*func)(Arg0 arg0, Arg1 arg1, Arg2 arg2))
   {
-    mImpl.OnConnect(delegate.GetConnectionTracker(), MakeCallback(delegate.GetSlot(), func));
+    Impl().OnConnect(delegate.GetConnectionTracker(), MakeCallback(delegate.GetSlot(), func));
   }
 
   /**
@@ -1254,7 +974,7 @@ public:
   template<class X>
   void Disconnect(SlotDelegate<X>& delegate, void (X::*func)(Arg0 arg0, Arg1 arg1, Arg2 arg2))
   {
-    mImpl.OnDisconnect(delegate.GetConnectionTracker(), MakeCallback(delegate.GetSlot(), func));
+    Impl().OnDisconnect(delegate.GetConnectionTracker(), MakeCallback(delegate.GetSlot(), func));
   }
 
   /**
@@ -1267,7 +987,7 @@ public:
   template<class X>
   void Connect(ConnectionTrackerInterface* connectionTracker, const X& func)
   {
-    mImpl.OnConnect(connectionTracker, new CallbackFunctor3<X, Arg0, Arg1, Arg2>(func));
+    Impl().OnConnect(connectionTracker, new CallbackFunctor3<X, Arg0, Arg1, Arg2>(func));
   }
 
   /**
@@ -1279,7 +999,7 @@ public:
    */
   void Connect(ConnectionTrackerInterface* connectionTracker, FunctorDelegate* delegate)
   {
-    mImpl.OnConnect(connectionTracker, new CallbackFunctorDelegate3<Arg0, Arg1, Arg2>(delegate));
+    Impl().OnConnect(connectionTracker, new CallbackFunctorDelegate3<Arg0, Arg1, Arg2>(delegate));
   }
 
   /**
@@ -1292,18 +1012,8 @@ public:
    */
   void Emit(Arg0 arg0, Arg1 arg1, Arg2 arg2)
   {
-    mImpl.Emit<Arg0, Arg1, Arg2>(arg0, arg1, arg2);
+    Impl().template Emit<Arg0, Arg1, Arg2>(arg0, arg1, arg2);
   }
-
-private:
-  Signal(const Signal&) = delete;            ///< Deleted copy constructor, signals don't support copying. @SINCE_1_0.0
-  Signal(Signal&&)      = delete;            ///< Deleted move constructor, signals don't support moving. @SINCE_1_9.25
-  Signal& operator=(const Signal&) = delete; ///< Deleted copy assignment operator @SINCE_1_0.0
-  Signal& operator=(Signal&&) = delete;      ///< Deleted move assignment operator @SINCE_1_9.25
-
-private:
-  // Use composition instead of inheritance (virtual methods don't mix well with templates)
-  BaseSignal mImpl; ///< Implementation
 };
 
 /**
@@ -1311,48 +1021,10 @@ private:
  * @SINCE_1_0.0
  */
 template<typename Ret, typename Arg0, typename Arg1, typename Arg2>
-class Signal<Ret(Arg0, Arg1, Arg2)>
+class Signal<Ret(Arg0, Arg1, Arg2)> : public SignalMixin
 {
 public:
   /**
-   * @brief Default constructor.
-   * @SINCE_1_0.0
-   */
-  Signal()
-  {
-  }
-
-  /**
-   * @brief Non-virtual destructor.
-   * @SINCE_1_0.0
-   */
-  ~Signal()
-  {
-  }
-
-  /**
-   * @brief Queries whether there are any connected slots.
-   *
-   * @SINCE_1_0.0
-   * @return True if there are any slots connected to the signal
-   */
-  bool Empty() const
-  {
-    return mImpl.Empty();
-  }
-
-  /**
-   * @brief Queries the number of slots.
-   *
-   * @SINCE_1_0.0
-   * @return The number of slots connected to this signal
-   */
-  std::size_t GetConnectionCount() const
-  {
-    return mImpl.GetConnectionCount();
-  }
-
-  /**
    * @brief Connects a function.
    *
    * @SINCE_1_0.0
@@ -1360,7 +1032,7 @@ public:
    */
   void Connect(Ret (*func)(Arg0 arg0, Arg1 arg1, Arg2 arg2))
   {
-    mImpl.OnConnect(MakeCallback(func));
+    Impl().OnConnect(MakeCallback(func));
   }
 
   /**
@@ -1371,7 +1043,7 @@ public:
    */
   void Disconnect(Ret (*func)(Arg0 arg0, Arg1 arg1, Arg2 arg2))
   {
-    mImpl.OnDisconnect(MakeCallback(func));
+    Impl().OnDisconnect(MakeCallback(func));
   }
 
   /**
@@ -1384,7 +1056,7 @@ public:
   template<class X>
   void Connect(X* obj, Ret (X::*func)(Arg0 arg0, Arg1 arg1, Arg2 arg2))
   {
-    mImpl.OnConnect(obj, MakeCallback(obj, func));
+    Impl().OnConnect(obj, MakeCallback(obj, func));
   }
 
   /**
@@ -1397,7 +1069,7 @@ public:
   template<class X>
   void Disconnect(X* obj, Ret (X::*func)(Arg0 arg0, Arg1 arg1, Arg2 arg2))
   {
-    mImpl.OnDisconnect(obj, MakeCallback(obj, func));
+    Impl().OnDisconnect(obj, MakeCallback(obj, func));
   }
 
   /**
@@ -1410,7 +1082,7 @@ public:
   template<class X>
   void Connect(SlotDelegate<X>& delegate, Ret (X::*func)(Arg0 arg0, Arg1 arg1, Arg2 arg2))
   {
-    mImpl.OnConnect(delegate.GetConnectionTracker(), MakeCallback(delegate.GetSlot(), func));
+    Impl().OnConnect(delegate.GetConnectionTracker(), MakeCallback(delegate.GetSlot(), func));
   }
 
   /**
@@ -1423,7 +1095,7 @@ public:
   template<class X>
   void Disconnect(SlotDelegate<X>& delegate, Ret (X::*func)(Arg0 arg0, Arg1 arg1, Arg2 arg2))
   {
-    mImpl.OnDisconnect(delegate.GetConnectionTracker(), MakeCallback(delegate.GetSlot(), func));
+    Impl().OnDisconnect(delegate.GetConnectionTracker(), MakeCallback(delegate.GetSlot(), func));
   }
 
   /**
@@ -1436,7 +1108,7 @@ public:
   template<class X>
   void Connect(ConnectionTrackerInterface* connectionTracker, const X& func)
   {
-    mImpl.OnConnect(connectionTracker, new CallbackFunctorReturn3<X, Arg0, Arg1, Arg2, Ret>(func));
+    Impl().OnConnect(connectionTracker, new CallbackFunctorReturn3<X, Arg0, Arg1, Arg2, Ret>(func));
   }
 
   /**
@@ -1448,7 +1120,7 @@ public:
    */
   void Connect(ConnectionTrackerInterface* connectionTracker, FunctorDelegate* delegate)
   {
-    mImpl.OnConnect(connectionTracker, new CallbackFunctorDelegateReturn3<Arg0, Arg1, Arg2, Ret>(delegate));
+    Impl().OnConnect(connectionTracker, new CallbackFunctorDelegateReturn3<Arg0, Arg1, Arg2, Ret>(delegate));
   }
 
   /**
@@ -1462,18 +1134,8 @@ public:
    */
   Ret Emit(Arg0 arg0, Arg1 arg1, Arg2 arg2)
   {
-    return mImpl.EmitReturn<Ret, Arg0, Arg1, Arg2>(arg0, arg1, arg2);
+    return Impl().template EmitReturn<Ret, Arg0, Arg1, Arg2>(arg0, arg1, arg2);
   }
-
-private:
-  Signal(const Signal&) = delete;            ///< Deleted copy constructor, signals don't support copying. @SINCE_1_0.0
-  Signal(Signal&&)      = delete;            ///< Deleted move constructor, signals don't support moving. @SINCE_1_9.25
-  Signal& operator=(const Signal&) = delete; ///< Deleted copy assignment operator @SINCE_1_0.0
-  Signal& operator=(Signal&&) = delete;      ///< Deleted move assignment operator @SINCE_1_9.25
-
-private:
-  // Use composition instead of inheritance (virtual methods don't mix well with templates)
-  BaseSignal mImpl; ///< Implementation
 };
 
 /**
index b03e133..1aef5dc 100644 (file)
 
 // EXTERNAL INCLUDES
 #include <cstddef>
+#include <type_traits>
 
 // INTERNAL INCLUDES
 #include <dali/public-api/signals/callback.h>
 
 namespace Dali
 {
+
 SlotConnection::SlotConnection(SlotObserver* slotObserver, CallbackBase* callback)
 : mSlotObserver(slotObserver),
   mCallback(callback)
 {
 }
 
-SlotConnection::~SlotConnection()
-{
-}
-
-CallbackBase* SlotConnection::GetCallback()
-{
-  return mCallback;
-}
-
-SlotObserver* SlotConnection::GetSlotObserver()
-{
-  return mSlotObserver;
-}
-
-SignalConnection::SignalConnection(CallbackBase* callback)
-: mSignalObserver(nullptr),
-  mCallback(callback)
-{
-}
-
-SignalConnection::SignalConnection(SignalObserver* signalObserver, CallbackBase* callback)
-: mSignalObserver(signalObserver),
-  mCallback(callback)
-{
-}
-
-SignalConnection::~SignalConnection()
-{
-  // signal connections have ownership of the callback.
-  delete mCallback;
-}
-
-void SignalConnection::Disconnect(SlotObserver* slotObserver)
+void SignalConnection::Disconnect(SlotObserver* slotObserver) noexcept
 {
   if(mSignalObserver)
   {
@@ -78,9 +48,10 @@ void SignalConnection::Disconnect(SlotObserver* slotObserver)
   mCallback = nullptr;
 }
 
-CallbackBase* SignalConnection::GetCallback()
-{
-  return mCallback;
-}
+static_assert(std::is_nothrow_move_constructible_v<SignalConnection>);
+static_assert(std::is_nothrow_move_assignable_v<SignalConnection>);
+
+static_assert(std::is_copy_constructible_v<SignalConnection> == false);
+static_assert(std::is_copy_assignable_v<SignalConnection> == false);
 
 } // namespace Dali
index 2a76199..b063616 100644 (file)
@@ -19,6 +19,7 @@
  */
 
 // INTERNAL INCLUDES
+#include <dali/public-api/signals/callback.h>
 #include <dali/public-api/signals/signal-slot-observers.h>
 
 namespace Dali
@@ -28,7 +29,6 @@ namespace Dali
  * @{
  */
 
-class CallbackBase;
 
 /**
  * @brief Slot connection is the connection information held by a connection tracker.
@@ -56,18 +56,15 @@ public:
   SlotConnection(SlotObserver* slotObserver, CallbackBase* callback);
 
   /**
-   * @brief Non-virtual destructor, not intended as a base class.
-   * @SINCE_1_0.0
-   */
-  ~SlotConnection();
-
-  /**
    * @brief Retrieves the callback.
    *
    * @SINCE_1_0.0
    * @return A pointer to the callback
    */
-  CallbackBase* GetCallback();
+  CallbackBase* GetCallback() const
+  {
+    return mCallback;
+  }
 
   /**
    * @brief Retrieves the slot observer.
@@ -75,17 +72,14 @@ public:
    * @SINCE_1_0.0
    * @return A pointer to the slot observer
    */
-  SlotObserver* GetSlotObserver();
-
-private:
-  SlotConnection(const SlotConnection&) = delete;            ///< Deleted copy constructor. @SINCE_1_0.0
-  SlotConnection(SlotConnection&&)      = delete;            ///< Deleted move constructor. @SINCE_1_9.25
-  SlotConnection& operator=(const SlotConnection&) = delete; ///< Deleted copy assignment operator. @SINCE_1_0.0
-  SlotConnection& operator=(SlotConnection&&) = delete;      ///< Deleted move assignment operator. @SINCE_1_9.25
+  SlotObserver* GetSlotObserver() const
+  {
+    return mSlotObserver;
+  }
 
 private:
-  SlotObserver* mSlotObserver; ///< a pointer to the slot observer (not owned)
-  CallbackBase* mCallback;     ///< The callback. This is not owned, the corresponding SignalConnection has ownership.
+  SlotObserver* mSlotObserver{nullptr}; ///< a pointer to the slot observer (not owned)
+  CallbackBase* mCallback{nullptr};     ///< The callback. This is not owned, the corresponding SignalConnection has ownership.
 };
 
 /**
@@ -111,7 +105,10 @@ public:
    * @SINCE_1_0.0
    * @param[in] callback The callback which should be a C function
    */
-  SignalConnection(CallbackBase* callback);
+  SignalConnection(CallbackBase* callback) noexcept
+  : mCallback(callback)
+  {
+  }
 
   /**
    * @brief Constructor.
@@ -120,13 +117,21 @@ public:
    * @param[in] signalObserver The signal observer
    * @param[in] callback Ownership of this callback object is taken
    */
-  SignalConnection(SignalObserver* signalObserver, CallbackBase* callback);
+  SignalConnection(SignalObserver* signalObserver, CallbackBase* callback) noexcept
+  : mSignalObserver(signalObserver),
+    mCallback(callback)
+  {
+  }
 
   /**
    * @brief Non-virtual destructor, not intended as a base class.
    * @SINCE_1_0.0
    */
-  ~SignalConnection();
+  ~SignalConnection() noexcept
+  {
+    // signal connections have ownership of the callback.
+    delete mCallback;
+  }
 
   /**
    * @brief Disconnects the signal from the slot.
@@ -134,7 +139,7 @@ public:
    * @SINCE_1_0.0
    * @param[in] slotObserver The signal disconnecting from the slot
    */
-  void Disconnect(SlotObserver* slotObserver);
+  void Disconnect(SlotObserver* slotObserver) noexcept;
 
   /**
    * @brief Retrieves the callback.
@@ -142,17 +147,60 @@ public:
    * @SINCE_1_0.0
    * @return A pointer to the callback
    */
-  CallbackBase* GetCallback();
+  CallbackBase* GetCallback() const noexcept
+  {
+    return mCallback;
+  }
 
-private:
   SignalConnection(const SignalConnection&) = delete;            ///< Deleted copy constructor. @SINCE_1_0.0
-  SignalConnection(SignalConnection&&)      = delete;            ///< Deleted move constructor. @SINCE_1_9.25
   SignalConnection& operator=(const SignalConnection&) = delete; ///< Deleted copy assignment operator. @SINCE_1_0.0
-  SignalConnection& operator=(SignalConnection&&) = delete;      ///< Deleted move assignment operator. @SINCE_1_9.25
+
+  /**
+   * @brief Move constructor.
+   *
+   * A move constructor enables the resources owned by an rvalue object to be moved into an lvalue without copying.
+   * @SINCE_1_9.38
+   * @param[in] connection The property value to move from
+   */
+  SignalConnection(SignalConnection&& connection) noexcept
+  : mSignalObserver(connection.mSignalObserver),
+    mCallback(connection.mCallback)
+  {
+    connection.mSignalObserver = nullptr;
+    connection.mCallback       = nullptr;
+  }
+
+  /**
+   * @brief Move assignment operator.
+   *
+   * @SINCE_1_9.38
+   * @param[in] connection The connection to move from
+   * @return a reference to this
+   */
+  SignalConnection& operator=(SignalConnection&& connection) noexcept
+  {
+    if(this != &connection)
+    {
+      // release the callback
+      delete mCallback;
+
+      mSignalObserver = connection.mSignalObserver;
+      mCallback       = connection.mCallback;
+
+      connection.mSignalObserver = nullptr;
+      connection.mCallback       = nullptr;
+    }
+    return *this;
+  }
+
+  explicit operator bool() const noexcept
+  {
+    return mCallback ? true : false;
+  }
 
 private:
-  SignalObserver* mSignalObserver; ///< a pointer to the signal observer (not owned)
-  CallbackBase*   mCallback;       ///< The callback, has ownership.
+  SignalObserver* mSignalObserver{nullptr}; ///< a pointer to the signal observer (not owned)
+  CallbackBase*   mCallback{nullptr};       ///< The callback, has ownership.
 };
 
 /**
index 25b5042..0e58a69 100644 (file)
@@ -1,6 +1,6 @@
 Name:       dali2
 Summary:    DALi 3D Engine
-Version:    1.9.32
+Version:    1.9.34
 Release:    1
 Group:      System/Libraries
 License:    Apache-2.0 and BSD-3-Clause and MIT