2 * Copyright (c) 2022 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 #include <dali/internal/event/actors/layer-impl.h>
24 #include <dali/public-api/actors/layer.h>
25 #include <dali/public-api/common/dali-common.h>
26 #include <dali/public-api/object/type-registry.h>
28 #include <dali/internal/event/actors/layer-list.h>
29 #include <dali/internal/event/common/event-thread-services.h>
30 #include <dali/internal/event/common/property-helper.h>
31 #include <dali/internal/event/common/scene-impl.h>
33 #include <dali/internal/update/manager/update-manager.h>
34 #include <dali/internal/update/nodes/scene-graph-layer.h>
36 using Dali::Internal::SceneGraph::UpdateManager;
42 typedef Layer::Behavior Behavior;
44 DALI_ENUM_TO_STRING_TABLE_BEGIN(BEHAVIOR)
45 DALI_ENUM_TO_STRING_WITH_SCOPE(Layer, LAYER_UI)
46 DALI_ENUM_TO_STRING_WITH_SCOPE(Layer, LAYER_3D)
47 DALI_ENUM_TO_STRING_TABLE_END(BEHAVIOR)
57 // Name Type writable animatable constraint-input enum for index-checking
58 DALI_PROPERTY_TABLE_BEGIN
59 DALI_PROPERTY("clippingEnable", BOOLEAN, true, false, true, Dali::Layer::Property::CLIPPING_ENABLE)
60 DALI_PROPERTY("clippingBox", RECTANGLE, true, false, true, Dali::Layer::Property::CLIPPING_BOX)
61 DALI_PROPERTY("behavior", INTEGER, true, false, false, Dali::Layer::Property::BEHAVIOR)
62 DALI_PROPERTY("depth", INTEGER, false, false, false, Dali::Layer::Property::DEPTH)
63 DALI_PROPERTY("depthTest", BOOLEAN, true, false, false, Dali::Layer::Property::DEPTH_TEST)
64 DALI_PROPERTY("consumesTouch", BOOLEAN, true, false, false, Dali::Layer::Property::CONSUMES_TOUCH)
65 DALI_PROPERTY("consumesHover", BOOLEAN, true, false, false, Dali::Layer::Property::CONSUMES_HOVER)
66 DALI_PROPERTY_TABLE_END(DEFAULT_DERIVED_ACTOR_PROPERTY_START_INDEX, LayerDefaultProperties)
70 static constexpr std::string_view ACTION_RAISE = "raise";
71 static constexpr std::string_view ACTION_LOWER = "lower";
72 static constexpr std::string_view ACTION_RAISE_TO_TOP = "raiseToTop";
73 static constexpr std::string_view ACTION_LOWER_TO_BOTTOM = "lowerToBottom";
77 return Dali::Layer::New();
80 TypeRegistration mType(typeid(Dali::Layer), typeid(Dali::Actor), Create, LayerDefaultProperties);
82 TypeAction a1(mType, std::string(ACTION_RAISE), &Layer::DoAction);
83 TypeAction a2(mType, std::string(ACTION_LOWER), &Layer::DoAction);
84 TypeAction a3(mType, std::string(ACTION_RAISE_TO_TOP), &Layer::DoAction);
85 TypeAction a4(mType, std::string(ACTION_LOWER_TO_BOTTOM), &Layer::DoAction);
87 } // unnamed namespace
91 // create node, nodes are owned by UpdateManager
92 SceneGraph::Layer* layerNode = SceneGraph::Layer::New();
93 OwnerPointer<SceneGraph::Node> transferOwnership(layerNode);
94 AddNodeMessage(EventThreadServices::Get().GetUpdateManager(), transferOwnership);
95 LayerPtr layer(new Layer(Actor::LAYER, *layerNode));
97 // Second-phase construction
103 LayerPtr Layer::NewRoot(LayerList& layerList)
105 // create node, nodes are owned by UpdateManager
106 SceneGraph::Layer* rootLayer = SceneGraph::Layer::New();
107 OwnerPointer<SceneGraph::Layer> transferOwnership(rootLayer);
108 InstallRootMessage(EventThreadServices::Get().GetUpdateManager(), transferOwnership);
110 LayerPtr root(new Layer(Actor::ROOT_LAYER, *rootLayer));
112 // root actor is immediately considered to be on-stage
113 root->mIsOnScene = true;
115 // The root actor will not emit a stage connection signal so set the signalled flag here as well
116 root->mOnSceneSignalled = true;
118 // layer-list must be set for the root layer
119 root->mLayerList = &layerList;
120 layerList.SetRootLayer(&(*root));
121 layerList.RegisterLayer(*root);
126 Layer::Layer(Actor::DerivedType type, const SceneGraph::Layer& layer)
127 : Actor(type, layer),
129 mClippingBox(0, 0, 0, 0),
130 mSortFunction(Layer::ZValue),
131 mBehavior(Dali::Layer::LAYER_UI),
133 mDepthTestDisabled(true),
134 mTouchConsumed(false),
135 mHoverConsumed(false)
139 void Layer::OnInitialize()
147 // Guard to allow handle destruction after Core has been destroyed
148 if(EventThreadServices::IsCoreRunning())
150 UninstallRootMessage(GetEventThreadServices().GetUpdateManager(), &GetSceneGraphLayer());
152 GetEventThreadServices().UnregisterObject(this);
157 unsigned int Layer::GetDepth() const
159 return mLayerList ? mLayerList->GetDepth(this) : 0u;
166 mLayerList->RaiseLayer(*this);
174 mLayerList->LowerLayer(*this);
178 void Layer::RaiseAbove(const Internal::Layer& target)
180 // cannot raise above ourself, both have to be on the scene
181 if((this != &target) && OnScene() && target.OnScene())
183 // get parameters depth
184 const uint32_t targetDepth = target.GetDepth();
185 if(GetDepth() < targetDepth)
192 void Layer::LowerBelow(const Internal::Layer& target)
194 // cannot lower below ourself, both have to be on the scene
195 if((this != &target) && OnScene() && target.OnScene())
197 // get parameters depth
198 const uint32_t targetDepth = target.GetDepth();
199 if(GetDepth() > targetDepth)
206 void Layer::RaiseToTop()
210 mLayerList->RaiseLayerToTop(*this);
214 void Layer::LowerToBottom()
218 mLayerList->LowerLayerToBottom(*this);
222 void Layer::MoveAbove(const Internal::Layer& target)
224 // cannot raise above ourself, both have to be on the scene
225 if((this != &target) && mLayerList && target.OnScene())
227 mLayerList->MoveLayerAbove(*this, target);
231 void Layer::MoveBelow(const Internal::Layer& target)
233 // cannot lower below ourself, both have to be on the scene
234 if((this != &target) && mLayerList && target.OnScene())
236 mLayerList->MoveLayerBelow(*this, target);
240 void Layer::SetBehavior(Dali::Layer::Behavior behavior)
242 if(mBehavior != behavior)
244 mBehavior = behavior;
248 // If current layer is on scene, and it's behavior changed,
249 // Change the mLayer3DParentsCount value recursively.
250 mParentImpl.RecursiveChangeLayer3dCount(mBehavior == Dali::Layer::LAYER_3D ? 1 : -1);
253 // Notify update side object.
254 SetBehaviorMessage(GetEventThreadServices(), GetSceneGraphLayer(), behavior);
255 // By default, disable depth test for LAYER_UI, and enable for LAYER_3D.
256 SetDepthTestDisabled(mBehavior == Dali::Layer::LAYER_UI);
260 void Layer::SetClipping(bool enabled)
262 if(enabled != mIsClipping)
264 mIsClipping = enabled;
266 // layerNode is being used in a separate thread; queue a message to set the value
267 SetClippingMessage(GetEventThreadServices(), GetSceneGraphLayer(), mIsClipping);
271 void Layer::SetClippingBox(int x, int y, int width, int height)
273 if((x != mClippingBox.x) ||
274 (y != mClippingBox.y) ||
275 (width != mClippingBox.width) ||
276 (height != mClippingBox.height))
278 // Clipping box is not animatable; this is the most up-to-date value
279 mClippingBox.Set(x, y, width, height);
281 // Convert mClippingBox to GL based coordinates (from bottom-left)
282 ClippingBox clippingBox(mClippingBox);
286 clippingBox.y = static_cast<int32_t>(mScene->GetSize().height) - clippingBox.y - clippingBox.height;
288 // layerNode is being used in a separate thread; queue a message to set the value
289 SetClippingBoxMessage(GetEventThreadServices(), GetSceneGraphLayer(), clippingBox);
294 void Layer::SetDepthTestDisabled(bool disable)
296 if(disable != mDepthTestDisabled)
298 mDepthTestDisabled = disable;
301 // layerNode is being used in a separate thread; queue a message to set the value
302 SetDepthTestDisabledMessage(GetEventThreadServices(), GetSceneGraphLayer(), mDepthTestDisabled);
306 bool Layer::IsDepthTestDisabled() const
308 return mDepthTestDisabled;
311 void Layer::SetSortFunction(Dali::Layer::SortFunctionType function)
313 if(function != mSortFunction)
315 mSortFunction = function;
317 // layerNode is being used in a separate thread; queue a message to set the value
318 SetSortFunctionMessage(GetEventThreadServices(), GetSceneGraphLayer(), mSortFunction);
322 void Layer::SetTouchConsumed(bool consume)
324 if(mTouchConsumed != consume)
328 this->TouchedSignal().Connect(this, &Layer::OnTouched);
332 this->TouchedSignal().Disconnect(this, &Layer::OnTouched);
335 mTouchConsumed = consume;
338 bool Layer::OnTouched(Dali::Actor actor, const TouchEvent& touch)
340 // This event is only called when mTouchConsumed is true. So touch always consumed.
344 bool Layer::IsTouchConsumed() const
346 return mTouchConsumed;
349 void Layer::SetHoverConsumed(bool consume)
351 mHoverConsumed = consume;
354 bool Layer::IsHoverConsumed() const
356 return mHoverConsumed;
359 void Layer::OnSceneConnectionInternal()
363 DALI_ASSERT_DEBUG(NULL == mLayerList);
365 // Find the ordered layer-list
366 for(Actor* parent = GetParent(); parent != nullptr; parent = parent->GetParent())
368 if(parent->IsLayer())
370 Layer* parentLayer = static_cast<Layer*>(parent); // cheaper than dynamic_cast
371 mLayerList = parentLayer->mLayerList;
376 DALI_ASSERT_DEBUG(NULL != mLayerList);
377 mLayerList->RegisterLayer(*this);
380 void Layer::OnSceneDisconnectionInternal()
382 mLayerList->UnregisterLayer(*this);
384 // mLayerList is only valid when on-stage
385 mLayerList = nullptr;
388 const SceneGraph::Layer& Layer::GetSceneGraphLayer() const
390 return static_cast<const SceneGraph::Layer&>(GetNode()); // we know our node is a layer node
393 void Layer::SetDefaultProperty(Property::Index index, const Property::Value& propertyValue)
395 if(index < DEFAULT_ACTOR_PROPERTY_MAX_COUNT)
397 Actor::SetDefaultProperty(index, propertyValue);
403 case Dali::Layer::Property::CLIPPING_ENABLE:
405 SetClipping(propertyValue.Get<bool>());
408 case Dali::Layer::Property::CLIPPING_BOX:
410 Rect<int32_t> clippingBox(propertyValue.Get<Rect<int32_t> >());
411 SetClippingBox(clippingBox.x, clippingBox.y, clippingBox.width, clippingBox.height);
414 case Dali::Layer::Property::BEHAVIOR:
416 Behavior behavior = mBehavior;
418 Property::Type type = propertyValue.GetType();
419 if(type == Property::STRING)
421 if(Scripting::GetEnumeration<Behavior>(propertyValue.Get<std::string>().c_str(), BEHAVIOR_TABLE, BEHAVIOR_TABLE_COUNT, behavior))
423 SetBehavior(behavior);
426 else if(type == Property::INTEGER)
428 SetBehavior(propertyValue.Get<Dali::Layer::Behavior>());
432 case Dali::Layer::Property::DEPTH_TEST:
434 SetDepthTestDisabled(!propertyValue.Get<bool>());
437 case Dali::Layer::Property::CONSUMES_TOUCH:
439 SetTouchConsumed(propertyValue.Get<bool>());
442 case Dali::Layer::Property::CONSUMES_HOVER:
444 SetHoverConsumed(propertyValue.Get<bool>());
449 DALI_LOG_WARNING("Unknown property (%d)\n", index);
457 Property::Value Layer::GetDefaultProperty(Property::Index index) const
460 if(index < DEFAULT_ACTOR_PROPERTY_MAX_COUNT)
462 ret = Actor::GetDefaultProperty(index);
468 case Dali::Layer::Property::CLIPPING_ENABLE:
473 case Dali::Layer::Property::CLIPPING_BOX:
478 case Dali::Layer::Property::BEHAVIOR:
483 case Dali::Layer::Property::DEPTH:
485 ret = static_cast<int>(GetDepth());
488 case Dali::Layer::Property::DEPTH_TEST:
490 ret = !mDepthTestDisabled;
493 case Dali::Layer::Property::CONSUMES_TOUCH:
495 ret = mTouchConsumed;
498 case Dali::Layer::Property::CONSUMES_HOVER:
500 ret = mHoverConsumed;
505 DALI_LOG_WARNING("Unknown property (%d)\n", index);
514 Property::Value Layer::GetDefaultPropertyCurrentValue(Property::Index index) const
517 if(index < DEFAULT_ACTOR_PROPERTY_MAX_COUNT)
519 ret = Actor::GetDefaultPropertyCurrentValue(index);
523 ret = GetDefaultProperty(index); // Layer only has event-side properties
529 bool Layer::DoAction(BaseObject* object, const std::string& actionName, const Property::Map& /*attributes*/)
532 Layer* layer = dynamic_cast<Layer*>(object);
536 std::string_view name(actionName);
538 if(name == ACTION_RAISE)
543 else if(name == ACTION_LOWER)
548 else if(name == ACTION_RAISE_TO_TOP)
553 else if(name == ACTION_LOWER_TO_BOTTOM)
555 layer->LowerToBottom();
563 } // namespace Internal