This patch allows setting arbitrary attributes on the Accessible level.
Previously this was only possible for Control, and thus application-side
customization of the attributes was unavailable for some other classes (most
notably Layer, which stands in for Window in the AT-SPI tree).
Change-Id: Iccdf65eb0b078f1962b31fbf3f6091d7e7d3f07d
#include <dali/public-api/object/type-info.h>
#include <dali/public-api/object/type-registry-helper.h>
#include <map>
+#include <sstream>
#include <string_view>
// INTERNAL INCLUDES
return std::string{it->second};
}
+void Accessible::UpdateAttributes(Attributes& attributes) const
+{
+ using MapType = std::map<ReadingInfoType, std::string_view>;
+
+ static const std::string readingInfoTypeKey = "reading_info_type";
+ static const char separator = '|';
+ static const MapType readingInfoTypeMap{
+ {ReadingInfoType::NAME, "name"},
+ {ReadingInfoType::ROLE, "role"},
+ {ReadingInfoType::DESCRIPTION, "description"},
+ {ReadingInfoType::STATE, "state"},
+ };
+
+ bool allEnabled = mReadingInfoTypes[ReadingInfoType::NAME]
+ && mReadingInfoTypes[ReadingInfoType::ROLE]
+ && mReadingInfoTypes[ReadingInfoType::DESCRIPTION]
+ && mReadingInfoTypes[ReadingInfoType::STATE];
+
+ if(DALI_LIKELY(allEnabled))
+ {
+ attributes.erase(readingInfoTypeKey);
+ return;
+ }
+
+ std::stringstream buf;
+ for(auto& item : readingInfoTypeMap)
+ {
+ if(mReadingInfoTypes[item.first])
+ {
+ if(buf.tellp()) // non-empty
+ {
+ buf << separator;
+ }
+
+ buf << item.second;
+ }
+ }
+
+ attributes.insert_or_assign(readingInfoTypeKey, buf.str());
+}
+
+const Attributes& Accessible::GetAttributes() const
+{
+ UpdateAttributes(mAttributes);
+
+ return mAttributes;
+}
+
+bool Accessible::SetAttribute(const std::string& key, const std::string& value)
+{
+ return mAttributes.insert_or_assign(key, value).second;
+}
+
+bool Accessible::UnsetAttribute(const std::string& key)
+{
+ return (mAttributes.erase(key) > 0);
+}
+
+void Accessible::ClearAttributes()
+{
+ mAttributes.clear();
+}
+
+ReadingInfoTypes Accessible::GetReadingInfoTypes() const
+{
+ return mReadingInfoTypes;
+}
+
+void Accessible::SetReadingInfoTypes(ReadingInfoTypes types)
+{
+ mReadingInfoTypes = types;
+}
+
AtspiInterfaces Accessible::GetInterfaces() const
{
if(!mInterfaces)
return state;
}
- Attributes GetAttributes() const override
+ void UpdateAttributes(Attributes& attributes) const override
{
- Attributes attributes;
+ static const std::string resIDKey = "resID";
- if(mRoot)
+ ActorAccessible::UpdateAttributes(attributes);
+
+ if(mRoot && attributes.find(resIDKey) == attributes.end())
{
Dali::Window window = Dali::DevelWindow::Get(Self());
Dali::Internal::Adaptor::Window& windowImpl = Dali::GetImplementation(window);
- attributes["resID"] = windowImpl.GetNativeResourceId();
- }
- Dali::TypeInfo type;
- Self().GetTypeInfo(type);
- attributes["class"] = type.GetName();
-
- return attributes;
+ attributes.emplace(resIDKey, windowImpl.GetNativeResourceId());
+ }
}
bool DoGesture(const GestureInfo& gestureInfo) override
// EXTERNAL INCLUDES
#include <dali/devel-api/actors/actor-devel.h>
+#include <dali/public-api/object/type-info.h>
// INTERNAL INCLUDES
#include <dali/devel-api/adaptor-framework/window-devel.h>
}
}
+void ActorAccessible::UpdateAttributes(Attributes& attributes) const
+{
+ static const std::string classKey = "class";
+
+ Accessible::UpdateAttributes(attributes);
+
+ if(attributes.find(classKey) == attributes.end())
+ {
+ Dali::TypeInfo typeInfo;
+ Self().GetTypeInfo(typeInfo);
+ if(typeInfo)
+ {
+ attributes.emplace(classKey, typeInfo.GetName());
+ }
+ }
+}
+
void ActorAccessible::UpdateChildren()
{
if(!mChildrenDirty)
*/
virtual void DoGetChildren(std::vector<Accessible*>& children);
+ /**
+ * @copydoc Dali::Accessibility::Accessible::UpdateAttributes()
+ */
+ void UpdateAttributes(Attributes& attributes) const override;
+
private:
// Extra overload for OnChildrenChanged() to connect to signals directly
void OnChildrenChanged(Dali::Actor);
return {};
}
- Attributes GetAttributes() const override
- {
- return {};
- }
-
bool IsProxy() const override
{
return true;
/**
* @brief Gets accessibility attributes.
*
+ * Attributes are key-value string pairs which can be used to transfer arbitrary
+ * information from the application to a client such as a screen reader or an
+ * automation framework.
+ *
+ * Typically, attributes are used when the data does not fit any other category
+ * with a dedicated API (name, description, states etc.).
+ *
+ * @see Accessible::SetAttribute()
+ * @see Accessible::UnsetAttribute()
+ * @see Accessible::ClearAttributes()
+ * @see Accessible::UpdateAttributes()
+ *
* @return The map of attributes and their values
*/
- virtual Attributes GetAttributes() const = 0;
+ const Attributes& GetAttributes() const;
+
+ /**
+ * @brief Sets an attribute
+ *
+ * The key will be created if necessary and the old attribute value (if any) will be replaced.
+ *
+ * @param[in] key Attribute key
+ * @param[in] value Attribute value
+ *
+ * @return True if the key was created, false otherwise (only value was updated)
+ */
+ bool SetAttribute(const std::string& key, const std::string& value);
+
+ /**
+ * @brief Unsets an attribute
+ *
+ * The key-value pair is removed from the attribute collection.
+ *
+ * @param[in] key Attribute key
+ *
+ * @return True if there was such a key, false otherwise
+ */
+ bool UnsetAttribute(const std::string& key);
+
+ /**
+ * @brief Unsets all attributes
+ *
+ * @see Accessible::UnsetAttribute()
+ */
+ void ClearAttributes();
+
+ /**
+ * @brief Gets the reading info types
+ *
+ * @return Reading info types bitmask
+ * @see Accessible::SetReadingInfoTypes()
+ */
+ ReadingInfoTypes GetReadingInfoTypes() const;
+
+ /**
+ * @brief Sets the reading info types
+ *
+ * The reading info types are individual pieces of information (name, role etc.)
+ * that can be read by the screen reader. This method can be used to enable and
+ * disable reading specific pieces.
+ *
+ * @param[in] types Reading info types bitmask
+ *
+ * @note The types will appear in GetAttributes() under the "reading_info_type" key.
+ * @see Accessible::GetAttributes()
+ */
+ void SetReadingInfoTypes(ReadingInfoTypes types);
/**
* @brief Checks if this is hidden.
*/
virtual AtspiInterfaces DoGetInterfaces() const;
+ /**
+ * @brief Updates the attribute collection
+ *
+ * This method, which is always called by GetAttributes(), can be overriden to
+ * provide lazily-calculated or dynamically-calculated (i.e. non-constant)
+ * attributes. When overriding, make sure to call the base class implementation
+ * first.
+ *
+ * @note The attribute collection is non-empty on entry
+ * @see Accessible::GetAttributes()
+ *
+ * @param[inout] attributes The attribute collection to update
+ */
+ virtual void UpdateAttributes(Attributes& attributes) const;
+
public:
/**
* @brief Gets the highlight actor.
mutable std::weak_ptr<Bridge::Data> mBridgeData;
mutable AtspiInterfaces mInterfaces;
+ mutable Attributes mAttributes;
+ ReadingInfoTypes mReadingInfoTypes = ~ReadingInfoTypes(); // all set
AtspiEvents mSuppressedEvents;
bool mIsOnRootLevel = false;
-
}; // Accessible class
namespace Internal
return result;
}
- Dali::Accessibility::Attributes GetAttributes() const override
- {
- return {};
- }
-
/**
* @brief Gets the Accessible object from the window.
*