[ATSPI] Blocking unwanted emission of "MoveOuted" signal
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / control / control-data-impl.cpp
index 0af44fb..ced845a 100644 (file)
@@ -410,6 +410,40 @@ void SetVisualsOffScene(const RegisteredVisualContainer& container, Actor parent
   }
 }
 
+Dali::Rect<> GetShowingGeometry(Dali::Rect<> rect, Dali::Toolkit::DevelControl::AccessibleImpl* accessibleImpl)
+{
+  Rect<>  parentRect;
+  Vector2 currentPosition;
+  auto    parent = dynamic_cast<Toolkit::DevelControl::AccessibleImpl*>(accessibleImpl->GetParent());
+
+  while(parent)
+  {
+    parentRect = parent->GetExtents(Dali::Accessibility::CoordinateType::WINDOW);
+
+    currentPosition.x = rect.x;
+    currentPosition.y = rect.y;
+
+    rect.x      = rect.x > parentRect.x ? rect.x : parentRect.x;
+    rect.y      = rect.y > parentRect.y ? rect.y : parentRect.y;
+    rect.width  = currentPosition.x + rect.width < parentRect.x + parentRect.width ? currentPosition.x + rect.width - rect.x : parentRect.x + parentRect.width - rect.x;
+    rect.height = currentPosition.y + rect.height < parentRect.y + parentRect.height ? currentPosition.y + rect.height - rect.y : parentRect.y + parentRect.height - rect.y;
+
+    if(rect.width < 0 || rect.height < 0)
+    {
+      return rect;
+    }
+
+    parent = dynamic_cast<Toolkit::DevelControl::AccessibleImpl*>(parent->GetParent());
+  }
+
+  return rect;
+}
+
+static bool IsShowingGeometryOnScreen(Dali::Rect<> rect)
+{
+  return rect.width > 0 && rect.height > 0;
+}
+
 } // unnamed namespace
 
 // clang-format off
@@ -518,6 +552,90 @@ const Control::Impl& Control::Impl::Get(const Internal::Control& internalControl
   return *internalControl.mImpl;
 }
 
+void Control::Impl::CheckHighlightedObjectGeometry()
+{
+  auto accessibleImpl = dynamic_cast<Dali::Toolkit::DevelControl::AccessibleImpl*>(mAccessibilityObject.get());
+  if(!accessibleImpl)
+  {
+    DALI_LOG_ERROR("accessibleImpl is not a pointer to a DevelControl::AccessibleImpl type");
+    return;
+  }
+
+  auto lastPosition   = accessibleImpl->GetLastPosition();
+  auto accessibleRect = accessibleImpl->GetExtents(Dali::Accessibility::CoordinateType::WINDOW);
+  auto rect = GetShowingGeometry(accessibleRect, accessibleImpl);
+
+  switch(mAccessibilityLastScreenRelativeMoveType)
+  {
+    case Dali::Accessibility::ScreenRelativeMoveType::OUTSIDE:
+    {
+      if(IsShowingGeometryOnScreen(rect))
+      {
+        mAccessibilityLastScreenRelativeMoveType = Dali::Accessibility::ScreenRelativeMoveType::INSIDE;
+      }
+      break;
+    }
+    case Dali::Accessibility::ScreenRelativeMoveType::INSIDE:
+    {
+      if(rect.width < 0 && accessibleRect.x != lastPosition.x)
+      {
+        mAccessibilityLastScreenRelativeMoveType = (accessibleRect.x < lastPosition.x) ? Dali::Accessibility::ScreenRelativeMoveType::OUTGOING_TOP_LEFT : Dali::Accessibility::ScreenRelativeMoveType::OUTGOING_BOTTOM_RIGHT;
+      }
+      if(rect.height < 0 && accessibleRect.y != lastPosition.y)
+      {
+        mAccessibilityLastScreenRelativeMoveType = (accessibleRect.y < lastPosition.y) ? Dali::Accessibility::ScreenRelativeMoveType::OUTGOING_TOP_LEFT : Dali::Accessibility::ScreenRelativeMoveType::OUTGOING_BOTTOM_RIGHT;
+      }
+      // notify AT-clients on outgoing moves only
+      if(mAccessibilityLastScreenRelativeMoveType != Dali::Accessibility::ScreenRelativeMoveType::INSIDE)
+      {
+        mAccessibilityObject.get()->EmitMovedOutOfScreen(mAccessibilityLastScreenRelativeMoveType);
+      }
+      break;
+    }
+    case Dali::Accessibility::ScreenRelativeMoveType::OUTGOING_TOP_LEFT:
+    case Dali::Accessibility::ScreenRelativeMoveType::OUTGOING_BOTTOM_RIGHT:
+    {
+      if(IsShowingGeometryOnScreen(rect))
+      {
+        mAccessibilityLastScreenRelativeMoveType = Dali::Accessibility::ScreenRelativeMoveType::INSIDE;
+      }
+      else
+      {
+        mAccessibilityLastScreenRelativeMoveType = Dali::Accessibility::ScreenRelativeMoveType::OUTSIDE;
+      }
+      break;
+    }
+    default:
+    {
+      break;
+    }
+  }
+
+  accessibleImpl->SetLastPosition(Vector2(accessibleRect.x, accessibleRect.y));
+}
+
+void Control::Impl::RegisterAccessibilityPositionPropertyNotification()
+{
+  if(mIsAccessibilityPositionPropertyNotificationSet)
+  {
+    return;
+  }
+  // set default value until first move of object is detected
+  mAccessibilityLastScreenRelativeMoveType = Dali::Accessibility::ScreenRelativeMoveType::OUTSIDE;
+  // recalculate mAccessibilityLastScreenRelativeMoveType accordingly to the initial position
+  CheckHighlightedObjectGeometry();
+  mAccessibilityPositionNotification       = mControlImpl.Self().AddPropertyNotification(Actor::Property::WORLD_POSITION, StepCondition(1.0f, 1.0f));
+  mAccessibilityPositionNotification.SetNotifyMode(PropertyNotification::NOTIFY_ON_CHANGED);
+  mAccessibilityPositionNotification.NotifySignal().Connect(this, [this](PropertyNotification&){ CheckHighlightedObjectGeometry(); });
+  mIsAccessibilityPositionPropertyNotificationSet = true;
+}
+
+void Control::Impl::UnregisterAccessibilityPositionPropertyNotification()
+{
+  mControlImpl.Self().RemovePropertyNotification(mAccessibilityPositionNotification);
+  mIsAccessibilityPositionPropertyNotificationSet = false;
+}
+
 // Gesture Detection Methods
 void Control::Impl::PinchDetected(Actor actor, const PinchGesture& pinch)
 {
@@ -1843,30 +1961,51 @@ void Control::Impl::MakeVisualTransition(Dali::Animation& animation, Dali::Toolk
 
   Vector4 mixColor(1.0f, 1.0f, 1.0f, 1.0f);
   Vector4 cornerRadius(0.0f, 0.0f, 0.0f, 0.0f);
+  float   borderlineWidth(0.0f);
+  Vector4 borderlineColor(0.0f, 0.0f, 0.0f, 1.0f);
+  float   borderlineOffset(0.0f);
 
   if(!destinationMap.Empty())
   {
-    static auto findValue = [](const Property::Map& map, Property::Index index) -> Vector4 {
+    static auto findValueVector4 = [](const Property::Map& map, Property::Index index, const Vector4& defaultValue = Vector4()) -> Vector4 {
       Property::Value* propertyValue = map.Find(index);
       if(propertyValue)
       {
         return propertyValue->Get<Vector4>();
       }
-      return Vector4{};
+      return defaultValue;
+    };
+
+    static auto findValueFloat = [](const Property::Map& map, Property::Index index, const float& defaultValue = 0.0f) -> float {
+      Property::Value* propertyValue = map.Find(index);
+      if(propertyValue)
+      {
+        return propertyValue->Get<float>();
+      }
+      return defaultValue;
     };
 
-    mixColor     = findValue(destinationMap, Dali::Toolkit::Visual::Property::MIX_COLOR);
-    cornerRadius = findValue(destinationMap, Toolkit::DevelVisual::Property::CORNER_RADIUS);
+    mixColor         = findValueVector4(destinationMap, Dali::Toolkit::Visual::Property::MIX_COLOR, mixColor);
+    cornerRadius     = findValueVector4(destinationMap, Toolkit::DevelVisual::Property::CORNER_RADIUS, cornerRadius);
+    borderlineWidth  = findValueFloat(destinationMap, Toolkit::DevelVisual::Property::BORDERLINE_WIDTH, borderlineWidth);
+    borderlineColor  = findValueVector4(destinationMap, Toolkit::DevelVisual::Property::BORDERLINE_COLOR, borderlineColor);
+    borderlineOffset = findValueFloat(destinationMap, Toolkit::DevelVisual::Property::BORDERLINE_OFFSET, borderlineOffset);
 
     if(sourceMap.Empty())
     {
       sourceMap.Insert(Toolkit::Visual::Property::TYPE, Toolkit::Visual::COLOR);
       sourceMap.Insert(Dali::Toolkit::Visual::Property::MIX_COLOR, Color::TRANSPARENT);
       sourceMap.Insert(Toolkit::DevelVisual::Property::CORNER_RADIUS, cornerRadius);
+      sourceMap.Insert(Toolkit::DevelVisual::Property::BORDERLINE_WIDTH, borderlineWidth);
+      sourceMap.Insert(Toolkit::DevelVisual::Property::BORDERLINE_COLOR, borderlineColor);
+      sourceMap.Insert(Toolkit::DevelVisual::Property::BORDERLINE_OFFSET, borderlineOffset);
     }
 
-    Vector4 sourceMixColor     = findValue(sourceMap, Dali::Toolkit::Visual::Property::MIX_COLOR);
-    Vector4 sourceCornerRadius = findValue(sourceMap, Toolkit::DevelVisual::Property::CORNER_RADIUS);
+    Vector4 sourceMixColor         = findValueVector4(sourceMap, Dali::Toolkit::Visual::Property::MIX_COLOR, mixColor);
+    Vector4 sourceCornerRadius     = findValueVector4(sourceMap, Toolkit::DevelVisual::Property::CORNER_RADIUS, cornerRadius);
+    float   sourceBorderlineWidth  = findValueFloat(sourceMap, Toolkit::DevelVisual::Property::BORDERLINE_WIDTH, borderlineWidth);
+    Vector4 sourceBorderlineColor  = findValueVector4(sourceMap, Toolkit::DevelVisual::Property::BORDERLINE_COLOR, borderlineColor);
+    float   sourceBorderlineOffset = findValueFloat(sourceMap, Toolkit::DevelVisual::Property::BORDERLINE_OFFSET, borderlineOffset);
 
     std::vector<Dali::Property>                              properties;
     std::vector<std::pair<Property::Value, Property::Value>> values;
@@ -1889,6 +2028,24 @@ void Control::Impl::MakeVisualTransition(Dali::Animation& animation, Dali::Toolk
       values.push_back(std::make_pair(sourceCornerRadius, cornerRadius));
     }
 
+    if(sourceBorderlineWidth != borderlineWidth)
+    {
+      properties.push_back(GetVisualProperty(visualIndex, Dali::Toolkit::DevelVisual::Property::BORDERLINE_WIDTH));
+      values.push_back(std::make_pair(sourceBorderlineWidth, borderlineWidth));
+    }
+
+    if(sourceBorderlineColor != borderlineColor)
+    {
+      properties.push_back(GetVisualProperty(visualIndex, Dali::Toolkit::DevelVisual::Property::BORDERLINE_COLOR));
+      values.push_back(std::make_pair(sourceBorderlineColor, borderlineColor));
+    }
+
+    if(sourceBorderlineOffset != borderlineOffset)
+    {
+      properties.push_back(GetVisualProperty(visualIndex, Dali::Toolkit::DevelVisual::Property::BORDERLINE_OFFSET));
+      values.push_back(std::make_pair(sourceBorderlineOffset, borderlineOffset));
+    }
+
     for(uint32_t i = 0; i < properties.size(); ++i)
     {
       if(timePeriod.delaySeconds > 0.0f)