Merge "If the currently focused actor is hidden or disabled, it should lose focus...
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / public-api / controls / control-impl.cpp
index 62b1079..9b10ffd 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 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.
@@ -37,7 +37,7 @@
 #include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
 #include <dali-toolkit/devel-api/controls/control-devel.h>
 #include <dali-toolkit/devel-api/focus-manager/keyinput-focus-manager.h>
-#include <dali-toolkit/devel-api/visuals/color-visual-actions-devel.h>
+#include <dali-toolkit/devel-api/visuals/visual-actions-devel.h>
 #include <dali-toolkit/devel-api/visuals/color-visual-properties-devel.h>
 #include <dali-toolkit/internal/controls/control/control-data-impl.h>
 #include <dali-toolkit/internal/styling/style-manager-impl.h>
@@ -64,27 +64,6 @@ Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_CON
 #endif
 
 /**
- * @brief Replace the background visual if it's a color visual with the renderIfTransparent property set as required.
- * @param[in] controlImpl The control implementation
- * @param[in] renderIfTransaparent Whether we should render if the color is transparent
- */
-void ChangeBackgroundColorVisual(Control& controlImpl, bool renderIfTransparent)
-{
-  Internal::Control::Impl& controlDataImpl = Internal::Control::Impl::Get(controlImpl);
-
-  Toolkit::Visual::Base backgroundVisual = controlDataImpl.GetVisual(Toolkit::Control::Property::BACKGROUND);
-  if(backgroundVisual && backgroundVisual.GetType() == Toolkit::Visual::COLOR)
-  {
-    Property::Map map;
-    backgroundVisual.CreatePropertyMap(map);
-
-    // Only change it if it's a color visual
-    map[Toolkit::DevelColorVisual::Property::RENDER_IF_TRANSPARENT] = renderIfTransparent;
-    controlImpl.SetBackground(map);
-  }
-}
-
-/**
  * @brief Creates a clipping renderer if required.
  * (EG. If no renders exist and clipping is enabled).
  * @param[in] controlImpl The control implementation.
@@ -96,34 +75,11 @@ void CreateClippingRenderer(Control& controlImpl)
   int   clippingMode = ClippingMode::DISABLED;
   if(self.GetProperty(Actor::Property::CLIPPING_MODE).Get(clippingMode))
   {
-    switch(clippingMode)
-    {
-      case ClippingMode::CLIP_CHILDREN:
-      {
-        if(self.GetRendererCount() == 0u)
-        {
-          Internal::Control::Impl& controlDataImpl = Internal::Control::Impl::Get(controlImpl);
-          if(controlDataImpl.mVisuals.Empty())
-          {
-            controlImpl.SetBackgroundColor(Color::TRANSPARENT);
-          }
-          else
-          {
-            // We have visuals, check if we've set the background and re-create it to
-            // render even if transparent (only if it's a color visual)
-            ChangeBackgroundColorVisual(controlImpl, true);
-          }
-        }
-        break;
-      }
+    Internal::Control::Impl& controlDataImpl = Internal::Control::Impl::Get(controlImpl);
 
-      case ClippingMode::DISABLED:
-      case ClippingMode::CLIP_TO_BOUNDING_BOX:
-      {
-        // If we have a background visual, check if it's a color visual and remove the render if transparent flag
-        ChangeBackgroundColorVisual(controlImpl, false);
-        break;
-      }
+    if(clippingMode == ClippingMode::CLIP_CHILDREN && controlDataImpl.mVisuals.Empty() && self.GetRendererCount() == 0u)
+    {
+      controlImpl.SetBackgroundColor(Color::TRANSPARENT);
     }
   }
 }
@@ -132,8 +88,13 @@ void CreateClippingRenderer(Control& controlImpl)
 
 Toolkit::Control Control::New()
 {
+  return New(ControlBehaviour::CONTROL_BEHAVIOUR_DEFAULT);
+}
+
+Toolkit::Control Control::New(ControlBehaviour additionalBehaviour)
+{
   // Create the implementation, temporarily owned on stack
-  IntrusivePtr<Control> controlImpl = new Control(ControlBehaviour(CONTROL_BEHAVIOUR_DEFAULT));
+  IntrusivePtr<Control> controlImpl = new Control(ControlBehaviour(CONTROL_BEHAVIOUR_DEFAULT | additionalBehaviour));
 
   // Pass ownership to handle
   Toolkit::Control handle(*controlImpl);
@@ -173,33 +134,12 @@ void Control::SetBackgroundColor(const Vector4& color)
   map[Toolkit::Visual::Property::TYPE]           = Toolkit::Visual::COLOR;
   map[Toolkit::ColorVisual::Property::MIX_COLOR] = color;
 
-  bool renderIfTransparent = false;
-  int  clippingMode        = ClippingMode::DISABLED;
-  if((Self().GetProperty(Actor::Property::CLIPPING_MODE).Get(clippingMode)) &&
-     (clippingMode == ClippingMode::CLIP_CHILDREN))
-  {
-    // If clipping-mode is set to CLIP_CHILDREN, then force visual to add the render even if transparent
-    map[Toolkit::DevelColorVisual::Property::RENDER_IF_TRANSPARENT] = true;
-    renderIfTransparent                                             = true;
-  }
-
   Toolkit::Visual::Base visual = mImpl->GetVisual(Toolkit::Control::Property::BACKGROUND);
   if(visual && visual.GetType() == Toolkit::Visual::COLOR)
   {
-    Property::Map visualMap;
-    visual.CreatePropertyMap(visualMap);
-
-    Property::Value* renderValue = visualMap.Find(Toolkit::DevelColorVisual::Property::RENDER_IF_TRANSPARENT);
-    Property::Value* colorValue  = visualMap.Find(Toolkit::ColorVisual::Property::MIX_COLOR);
-    if(renderValue && colorValue)
-    {
-      if((renderValue->Get<bool>() == true || colorValue->Get<Vector4>().a > 0.0f) && (renderIfTransparent || color.a > 0.0f))
-      {
-        // Update background color only
-        mImpl->DoAction(Toolkit::Control::Property::BACKGROUND, DevelColorVisual::Action::UPDATE_PROPERTY, map);
-        return;
-      }
-    }
+    // Update background color only
+    mImpl->DoAction(Toolkit::Control::Property::BACKGROUND, DevelVisual::Action::UPDATE_PROPERTY, map);
+    return;
   }
 
   SetBackground(map);
@@ -227,6 +167,11 @@ void Control::ClearBackground()
   RelayoutRequest();
 }
 
+Toolkit::DevelControl::ControlAccessible* Control::GetAccessibleObject()
+{
+  return mImpl->GetAccessibleObject();
+}
+
 void Control::EnableGestureDetection(GestureType::Value type)
 {
   if((type & GestureType::PINCH) && !mImpl->mPinchGestureDetector)
@@ -400,6 +345,11 @@ bool Control::OnAccessibilityZoom()
   return false; // Accessibility zoom action is not handled by default
 }
 
+DevelControl::ControlAccessible* Control::CreateAccessibleObject()
+{
+  return new DevelControl::ControlAccessible(Self());
+}
+
 Actor Control::GetNextKeyboardFocusableActor(Actor currentFocusedActor, Toolkit::Control::KeyboardFocus::Direction direction, bool loopEnabled)
 {
   return Actor();
@@ -492,11 +442,8 @@ void Control::Initialize()
   if(type)
   {
     auto typeName = type.GetName();
-    DevelControl::AppendAccessibilityAttribute(Self(), "t", typeName);
+    DevelControl::AppendAccessibilityAttribute(Toolkit::Control::DownCast(Self()), "class", typeName);
   }
-
-  if(Accessibility::IsUp())
-    mImpl->AccessibilityRegister();
 }
 
 void Control::OnInitialize()
@@ -547,12 +494,12 @@ void Control::EmitKeyInputFocusSignal(bool focusGained)
 
   if(Accessibility::IsUp())
   {
-    auto self = mImpl->GetAccessibilityObject(Self());
+    auto self = GetAccessibleObject();
     self->EmitFocused(focusGained);
     auto parent = self->GetParent();
     if(parent && !self->GetStates()[Dali::Accessibility::State::MANAGES_DESCENDANTS])
     {
-      parent->EmitActiveDescendantChanged(parent, self);
+      parent->EmitActiveDescendantChanged(self);
     }
   }
 
@@ -592,21 +539,10 @@ void Control::OnSceneConnection(int depth)
 
   // The clipping renderer is only created if required.
   CreateClippingRenderer(*this);
-
-  // Request to be laid out when the control is connected to the Scene.
-  // Signal that a Relayout may be needed
-  if(Accessibility::IsUp())
-  {
-    mImpl->AccessibilityRegister();
-  }
 }
 
 void Control::OnSceneDisconnection()
 {
-  if(Accessibility::IsUp())
-  {
-    mImpl->AccessibilityDeregister(true);
-  }
   mImpl->OnSceneDisconnection();
 }
 
@@ -645,17 +581,30 @@ void Control::OnPropertySet(Property::Index index, const Property::Value& proper
     }
     case Actor::Property::VISIBLE:
     {
-      if(Dali::Accessibility::IsUp())
+      const bool visible = propertyValue.Get<bool>();
+      GetAccessibleObject()->EmitVisible(visible);
+      if(!visible)
       {
-        Dali::Accessibility::Accessible::Get(Self())->EmitVisible(Self().GetProperty(Actor::Property::VISIBLE).Get<bool>());
+        Dali::Actor self = Self();
+        Dali::Actor actor = Dali::Toolkit::KeyboardFocusManager::Get().GetCurrentFocusActor();
+        while(actor)
+        {
+          if(self == actor)
+          {
+            Dali::Toolkit::KeyboardFocusManager::Get().ClearFocus();
+            break;
+          }
+          actor = actor.GetParent();
+        }
       }
       break;
     }
-    case Toolkit::DevelControl::Property::ACCESSIBILITY_ROLE:
+    case DevelActor::Property::USER_INTERACTION_ENABLED:
     {
-      if(Dali::Accessibility::IsUp())
+      const bool enabled = propertyValue.Get<bool>();
+      if (!enabled && Self() == Dali::Toolkit::KeyboardFocusManager::Get().GetCurrentFocusActor())
       {
-        Dali::Accessibility::Accessible::Get(Self())->Emit(Dali::Accessibility::ObjectPropertyChangeEvent::ROLE);
+        Dali::Toolkit::KeyboardFocusManager::Get().ClearFocus();
       }
       break;
     }
@@ -781,6 +730,102 @@ void Control::SignalDisconnected(SlotObserver* slotObserver, CallbackBase* callb
   mImpl->SignalDisconnected(slotObserver, callback);
 }
 
+void Control::MakeVisualTransition(Dali::Property::Map& sourcePropertyMap, Dali::Property::Map& destinationPropertyMap,
+                                   Dali::Toolkit::Control source, Dali::Toolkit::Control destination, Dali::Property::Index visualIndex)
+{
+  sourcePropertyMap.Clear();
+  destinationPropertyMap.Clear();
+
+  Toolkit::Visual::Base sourceVisual      = DevelControl::GetVisual(GetImplementation(source), visualIndex);
+  Toolkit::Visual::Base destinationVisual = DevelControl::GetVisual(GetImplementation(destination), visualIndex);
+
+  // If source or destination doesn't have the visual, do not create transition for the visual.
+  if(!sourceVisual || !destinationVisual)
+  {
+    return;
+  }
+
+  Property::Map sourceMap;
+  Property::Map destinationMap;
+  sourceVisual.CreatePropertyMap(sourceMap);
+  destinationVisual.CreatePropertyMap(destinationMap);
+
+  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 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;
+  };
+
+  Vector4 defaultMixColor(Color::TRANSPARENT);
+  Vector4 defaultCornerRadius(0.0f, 0.0f, 0.0f, 0.0f);
+  float   defaultBorderlineWidth(0.0f);
+  Vector4 defaultBorderlineColor(0.0f, 0.0f, 0.0f, 1.0f);
+  float   defaultBorderlineOffset(0.0f);
+
+  Vector4 sourceMixColor         = findValueVector4(sourceMap, Dali::Toolkit::Visual::Property::MIX_COLOR, defaultMixColor);
+  Vector4 sourceCornerRadius     = findValueVector4(sourceMap, Toolkit::DevelVisual::Property::CORNER_RADIUS, defaultCornerRadius);
+  float   sourceBorderlineWidth  = findValueFloat(sourceMap, Toolkit::DevelVisual::Property::BORDERLINE_WIDTH, defaultBorderlineWidth);
+  Vector4 sourceBorderlineColor  = findValueVector4(sourceMap, Toolkit::DevelVisual::Property::BORDERLINE_COLOR, defaultBorderlineColor);
+  float   sourceBorderlineOffset = findValueFloat(sourceMap, Toolkit::DevelVisual::Property::BORDERLINE_OFFSET, defaultBorderlineOffset);
+
+  Vector4 destinationMixColor         = findValueVector4(destinationMap, Dali::Toolkit::Visual::Property::MIX_COLOR, defaultMixColor);
+  Vector4 destinationCornerRadius     = findValueVector4(destinationMap, Toolkit::DevelVisual::Property::CORNER_RADIUS, defaultCornerRadius);
+  float   destinationBorderlineWidth  = findValueFloat(destinationMap, Toolkit::DevelVisual::Property::BORDERLINE_WIDTH, defaultBorderlineWidth);
+  Vector4 destinationBorderlineColor  = findValueVector4(destinationMap, Toolkit::DevelVisual::Property::BORDERLINE_COLOR, defaultBorderlineColor);
+  float   destinationBorderlineOffset = findValueFloat(destinationMap, Toolkit::DevelVisual::Property::BORDERLINE_OFFSET, defaultBorderlineOffset);
+
+  // If the value of the source Control and that of destination Control is different, the property should be transitioned.
+  if(Vector3(sourceMixColor) != Vector3(destinationMixColor))
+  {
+    sourcePropertyMap.Add(Dali::Toolkit::Visual::Property::MIX_COLOR, Vector3(sourceMixColor));
+    destinationPropertyMap.Add(Dali::Toolkit::Visual::Property::MIX_COLOR, Vector3(destinationMixColor));
+  }
+
+  if(std::abs(sourceMixColor.a - destinationMixColor.a) > Math::MACHINE_EPSILON_1)
+  {
+    sourcePropertyMap.Add(Dali::Toolkit::Visual::Property::OPACITY, sourceMixColor.a);
+    destinationPropertyMap.Add(Dali::Toolkit::Visual::Property::OPACITY, destinationMixColor.a);
+  }
+
+  if(sourceCornerRadius != destinationCornerRadius)
+  {
+    sourcePropertyMap.Add(Dali::Toolkit::DevelVisual::Property::CORNER_RADIUS, sourceCornerRadius);
+    destinationPropertyMap.Add(Dali::Toolkit::DevelVisual::Property::CORNER_RADIUS, destinationCornerRadius);
+  }
+
+  if(sourceBorderlineWidth != destinationBorderlineWidth)
+  {
+    sourcePropertyMap.Add(Dali::Toolkit::DevelVisual::Property::BORDERLINE_WIDTH, sourceBorderlineWidth);
+    destinationPropertyMap.Add(Dali::Toolkit::DevelVisual::Property::BORDERLINE_WIDTH, destinationBorderlineWidth);
+  }
+
+  if(sourceBorderlineColor != destinationBorderlineColor)
+  {
+    sourcePropertyMap.Add(Dali::Toolkit::DevelVisual::Property::BORDERLINE_COLOR, sourceBorderlineColor);
+    destinationPropertyMap.Add(Dali::Toolkit::DevelVisual::Property::BORDERLINE_COLOR, destinationBorderlineColor);
+  }
+
+  if(sourceBorderlineOffset != destinationBorderlineOffset)
+  {
+    sourcePropertyMap.Add(Dali::Toolkit::DevelVisual::Property::BORDERLINE_OFFSET, sourceBorderlineOffset);
+    destinationPropertyMap.Add(Dali::Toolkit::DevelVisual::Property::BORDERLINE_OFFSET, destinationBorderlineOffset);
+  }
+}
+
 Control& GetImplementation(Dali::Toolkit::Control& handle)
 {
   CustomActorImpl& customInterface = handle.GetImplementation();