6f940a77666ecad7cbb7c580e9ddc01c42912a28
[platform/core/uifw/dali-adaptor.git] / dali / devel-api / adaptor-framework / actor-accessible.cpp
1 /*
2  * Copyright (c) 2021 Samsung Electronics Co., Ltd.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali/devel-api/adaptor-framework/actor-accessible.h>
20
21 // EXTERNAL INCLUDES
22 #include <dali/devel-api/actors/actor-devel.h>
23
24 // INTERNAL INCLUDES
25 #include <dali/devel-api/adaptor-framework/window-devel.h>
26
27 namespace Dali::Accessibility
28 {
29 ActorAccessible::ActorAccessible(Actor actor)
30 : mSelf(actor),
31   mChildrenDirty{true} // to trigger the initial UpdateChildren()
32 {
33   // Select the right overload manually because Connect(this, &OnChildrenChanged) is ambiguous.
34   void (ActorAccessible::*handler)(Dali::Actor) = &ActorAccessible::OnChildrenChanged;
35
36   Dali::DevelActor::ChildAddedSignal(actor).Connect(this, handler);
37   Dali::DevelActor::ChildRemovedSignal(actor).Connect(this, handler);
38   Dali::DevelActor::ChildOrderChangedSignal(actor).Connect(this, handler);
39 }
40
41 std::string ActorAccessible::GetName() const
42 {
43   return Self().GetProperty<std::string>(Dali::Actor::Property::NAME);
44 }
45
46 std::string ActorAccessible::GetDescription() const
47 {
48   return {};
49 }
50
51 Accessible* ActorAccessible::GetParent()
52 {
53   if(IsOnRootLevel())
54   {
55     auto data = GetBridgeData();
56     return data->mBridge->GetApplication();
57   }
58
59   return Get(Self().GetParent());
60 }
61
62 std::size_t ActorAccessible::GetChildCount() const
63 {
64   // ActorAccessible is never stored in const memory and it is an implementation detail that
65   // children are recalculated lazily.
66   const_cast<ActorAccessible*>(this)->UpdateChildren();
67
68   return mChildren.size();
69 }
70
71 std::vector<Accessible*> ActorAccessible::GetChildren()
72 {
73   UpdateChildren();
74
75   return mChildren;
76 }
77
78 Accessible* ActorAccessible::GetChildAtIndex(std::size_t index)
79 {
80   auto childCount = GetChildCount(); // calls UpdateChildren()
81   if(DALI_UNLIKELY(index >= childCount))
82   {
83     throw std::domain_error{"invalid index " + std::to_string(index) + " for object with " + std::to_string(childCount) + " children"};
84   }
85
86   return mChildren[index];
87 }
88
89 std::size_t ActorAccessible::GetIndexInParent()
90 {
91   auto* parent = GetParent();
92
93   if(DALI_UNLIKELY(!parent))
94   {
95     throw std::domain_error{"can't call GetIndexInParent on object without parent"};
96   }
97
98   // Avoid calling parent->GetChildren() in order not to make an unnecessary copy
99   auto childCount = parent->GetChildCount();
100   for(auto i = 0u; i < childCount; ++i)
101   {
102     if(parent->GetChildAtIndex(i) == this)
103     {
104       return i;
105     }
106   }
107
108   throw std::domain_error{"actor is not a child of its parent"};
109 }
110
111 Dali::Actor ActorAccessible::GetInternalActor()
112 {
113   return Self();
114 }
115
116 ComponentLayer ActorAccessible::GetLayer() const
117 {
118   return ComponentLayer::WINDOW;
119 }
120
121 std::int16_t ActorAccessible::GetMdiZOrder() const
122 {
123   return 0;
124 }
125
126 double ActorAccessible::GetAlpha() const
127 {
128   return 0;
129 }
130
131 bool ActorAccessible::IsScrollable() const
132 {
133   return false;
134 }
135
136 Dali::Rect<> ActorAccessible::GetExtents(CoordinateType type) const
137 {
138   Dali::Actor actor                   = Self();
139   Vector2     screenPosition          = actor.GetProperty<Vector2>(Actor::Property::SCREEN_POSITION);
140   Vector3     size                    = actor.GetCurrentProperty<Vector3>(Actor::Property::SIZE) * actor.GetCurrentProperty<Vector3>(Actor::Property::WORLD_SCALE);
141   bool        positionUsesAnchorPoint = actor.GetProperty<bool>(Actor::Property::POSITION_USES_ANCHOR_POINT);
142   Vector3     anchorPointOffSet       = size * (positionUsesAnchorPoint ? actor.GetCurrentProperty<Vector3>(Actor::Property::ANCHOR_POINT) : AnchorPoint::TOP_LEFT);
143   Vector2     position                = Vector2(screenPosition.x - anchorPointOffSet.x, screenPosition.y - anchorPointOffSet.y);
144
145   if(type == CoordinateType::WINDOW)
146   {
147     return {position.x, position.y, size.x, size.y};
148   }
149   else // CoordinateType::SCREEN
150   {
151     auto window         = Dali::DevelWindow::Get(actor);
152     auto windowPosition = window.GetPosition();
153     return {position.x + windowPosition.GetX(), position.y + windowPosition.GetY(), size.x, size.y};
154   }
155 }
156
157 void ActorAccessible::OnChildrenChanged()
158 {
159   mChildrenDirty = true;
160 }
161
162 void ActorAccessible::OnChildrenChanged(Dali::Actor)
163 {
164   OnChildrenChanged();
165 }
166
167 void ActorAccessible::DoGetChildren(std::vector<Accessible*>& children)
168 {
169   auto self       = Self();
170   auto childCount = self.GetChildCount();
171
172   children.reserve(childCount);
173
174   for(auto i = 0u; i < childCount; ++i)
175   {
176     children.push_back(Accessible::Get(self.GetChildAt(i)));
177   }
178 }
179
180 void ActorAccessible::UpdateChildren()
181 {
182   if(!mChildrenDirty)
183   {
184     return;
185   }
186
187   // Set to false before DoGetChildren() to prevent recursion
188   // in case DoGetChildren() does something strange.
189   mChildrenDirty = false;
190
191   mChildren.clear();
192   DoGetChildren(mChildren);
193
194   // Erase-remove idiom
195   // TODO (C++20): Replace with std::erase_if
196   auto it = std::remove_if(mChildren.begin(), mChildren.end(), [](const Accessible* child) {
197     return !child || child->IsHidden();
198   });
199   mChildren.erase(it, mChildren.end());
200   mChildren.shrink_to_fit();
201 }
202
203 } // namespace Dali::Accessibility