2 * Copyright (c) 2021 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/devel-api/adaptor-framework/actor-accessible.h>
22 #include <dali/devel-api/actors/actor-devel.h>
23 #include <dali/public-api/object/type-info.h>
26 #include <dali/devel-api/adaptor-framework/window-devel.h>
28 namespace Dali::Accessibility
30 ActorAccessible::ActorAccessible(Actor actor)
32 mChildrenDirty{true} // to trigger the initial UpdateChildren()
34 // Select the right overload manually because Connect(this, &OnChildrenChanged) is ambiguous.
35 void (ActorAccessible::*handler)(Dali::Actor) = &ActorAccessible::OnChildrenChanged;
37 Dali::DevelActor::ChildAddedSignal(actor).Connect(this, handler);
38 Dali::DevelActor::ChildRemovedSignal(actor).Connect(this, handler);
39 Dali::DevelActor::ChildOrderChangedSignal(actor).Connect(this, handler);
42 std::string ActorAccessible::GetName() const
44 return Self().GetProperty<std::string>(Dali::Actor::Property::NAME);
47 std::string ActorAccessible::GetDescription() const
52 Accessible* ActorAccessible::GetParent()
56 auto data = GetBridgeData();
57 return data->mBridge->GetApplication();
60 return Get(Self().GetParent());
63 std::size_t ActorAccessible::GetChildCount() const
65 // ActorAccessible is never stored in const memory and it is an implementation detail that
66 // children are recalculated lazily.
67 const_cast<ActorAccessible*>(this)->UpdateChildren();
69 return mChildren.size();
72 std::vector<Accessible*> ActorAccessible::GetChildren()
79 Accessible* ActorAccessible::GetChildAtIndex(std::size_t index)
81 auto childCount = GetChildCount(); // calls UpdateChildren()
82 if(DALI_UNLIKELY(index >= childCount))
84 throw std::domain_error{"invalid index " + std::to_string(index) + " for object with " + std::to_string(childCount) + " children"};
87 return mChildren[index];
90 std::size_t ActorAccessible::GetIndexInParent()
92 auto* parent = GetParent();
94 if(DALI_UNLIKELY(!parent))
96 throw std::domain_error{"can't call GetIndexInParent on object without parent"};
99 // Avoid calling parent->GetChildren() in order not to make an unnecessary copy
100 auto childCount = parent->GetChildCount();
101 for(auto i = 0u; i < childCount; ++i)
103 if(parent->GetChildAtIndex(i) == this)
109 throw std::domain_error{"actor is not a child of its parent"};
112 Dali::Actor ActorAccessible::GetInternalActor()
117 ComponentLayer ActorAccessible::GetLayer() const
119 return ComponentLayer::WINDOW;
122 std::int16_t ActorAccessible::GetMdiZOrder() const
127 double ActorAccessible::GetAlpha() const
132 bool ActorAccessible::IsScrollable() const
137 Dali::Rect<> ActorAccessible::GetExtents(CoordinateType type) const
139 Dali::Actor actor = Self();
140 Vector2 screenPosition = actor.GetProperty<Vector2>(Actor::Property::SCREEN_POSITION);
141 Vector3 size = actor.GetCurrentProperty<Vector3>(Actor::Property::SIZE) * actor.GetCurrentProperty<Vector3>(Actor::Property::WORLD_SCALE);
142 bool positionUsesAnchorPoint = actor.GetProperty<bool>(Actor::Property::POSITION_USES_ANCHOR_POINT);
143 Vector3 anchorPointOffSet = size * (positionUsesAnchorPoint ? actor.GetCurrentProperty<Vector3>(Actor::Property::ANCHOR_POINT) : AnchorPoint::TOP_LEFT);
144 Vector2 position = Vector2(screenPosition.x - anchorPointOffSet.x, screenPosition.y - anchorPointOffSet.y);
146 if(type == CoordinateType::WINDOW)
148 return {position.x, position.y, size.x, size.y};
150 else // CoordinateType::SCREEN
152 auto window = Dali::DevelWindow::Get(actor);
153 auto windowPosition = window.GetPosition();
154 return {position.x + windowPosition.GetX(), position.y + windowPosition.GetY(), size.x, size.y};
158 void ActorAccessible::OnChildrenChanged()
160 mChildrenDirty = true;
163 void ActorAccessible::OnChildrenChanged(Dali::Actor)
168 void ActorAccessible::DoGetChildren(std::vector<Accessible*>& children)
171 auto childCount = self.GetChildCount();
173 children.reserve(childCount);
175 for(auto i = 0u; i < childCount; ++i)
177 children.push_back(Accessible::Get(self.GetChildAt(i)));
181 void ActorAccessible::UpdateAttributes(Attributes& attributes) const
183 static const std::string classKey = "class";
185 Accessible::UpdateAttributes(attributes);
187 if(attributes.find(classKey) == attributes.end())
189 Dali::TypeInfo typeInfo;
190 Self().GetTypeInfo(typeInfo);
193 attributes.emplace(classKey, typeInfo.GetName());
198 void ActorAccessible::UpdateChildren()
205 // Set to false before DoGetChildren() to prevent recursion
206 // in case DoGetChildren() does something strange.
207 mChildrenDirty = false;
210 DoGetChildren(mChildren);
212 // Erase-remove idiom
213 // TODO (C++20): Replace with std::erase_if
214 auto it = std::remove_if(mChildren.begin(), mChildren.end(), [](const Accessible* child) {
215 return !child || child->IsHidden();
217 mChildren.erase(it, mChildren.end());
218 mChildren.shrink_to_fit();
221 } // namespace Dali::Accessibility