Program Listing for File slint-testing.h

Return to documentation for file (/home/runner/work/slint/slint/api/cpp/include/slint-testing.h)

// Copyright © SixtyFPS GmbH <info@slint.dev>
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0

#include "slint.h"
#include "slint_testing_internal.h"
#include <optional>
#include <string_view>
#include <type_traits>

#ifdef SLINT_FEATURE_TESTING
#    ifdef SLINT_FEATURE_EXPERIMENTAL

namespace slint::testing {

using slint::cbindgen_private::AccessibleRole;

inline void init()
{
    cbindgen_private::slint_testing_init_backend();
}

class ElementHandle
{
    cbindgen_private::ElementHandle inner;

    explicit ElementHandle(const cbindgen_private::ElementHandle *inner) : inner(*inner) { }

public:
    template<typename T, std::invocable<ElementHandle> Visitor,
             typename R = std::invoke_result_t<Visitor, ElementHandle>>
        requires((std::is_constructible_v<bool, R> && std::is_default_constructible_v<R>)
                 || std::is_void_v<R>)
    static auto visit_elements(const ComponentHandle<T> &component,
                               Visitor visitor) -> std::invoke_result_t<Visitor, ElementHandle>
    {
        // using R = std::invoke_result_t<Visitor, ElementHandle>;
        auto vrc = component.into_dyn();
        if constexpr (std::is_void_v<R>) {
            cbindgen_private::slint_testing_element_visit_elements(
                    &vrc, &visitor,
                    [](void *visitor, const cbindgen_private::ElementHandle *element) {
                        (*reinterpret_cast<Visitor *>(visitor))(ElementHandle(element));
                        return false;
                    });
            return;
        } else {
            struct VisitorAndResult
            {
                Visitor &visitor;
                R result;
            } visitor_and_result { visitor, R {} };
            cbindgen_private::slint_testing_element_visit_elements(
                    &vrc, &visitor_and_result,
                    [](void *user_data, const cbindgen_private::ElementHandle *element) {
                        auto visitor_and_result = reinterpret_cast<VisitorAndResult *>(user_data);
                        if (auto r = visitor_and_result->visitor(ElementHandle(element))) {
                            visitor_and_result->result = std::move(r);
                            return true;
                        };
                        return false;
                    });
            return visitor_and_result.result;
        }
    }

    template<typename T>
    static SharedVector<ElementHandle> find_by_accessible_label(const ComponentHandle<T> &component,
                                                                std::string_view label)
    {
        cbindgen_private::Slice<uint8_t> label_view {
            const_cast<unsigned char *>(reinterpret_cast<const unsigned char *>(label.data())),
            label.size()
        };
        auto vrc = component.into_dyn();
        SharedVector<ElementHandle> result;
        cbindgen_private::slint_testing_element_find_by_accessible_label(
                &vrc, &label_view,
                reinterpret_cast<SharedVector<cbindgen_private::ElementHandle> *>(&result));
        return result;
    }

    template<typename T>
    static SharedVector<ElementHandle> find_by_element_id(const ComponentHandle<T> &component,
                                                          std::string_view element_id)
    {
        cbindgen_private::Slice<uint8_t> element_id_view {
            const_cast<unsigned char *>(reinterpret_cast<const unsigned char *>(element_id.data())),
            element_id.size()
        };
        auto vrc = component.into_dyn();
        SharedVector<ElementHandle> result;
        cbindgen_private::slint_testing_element_find_by_element_id(
                &vrc, &element_id_view,
                reinterpret_cast<SharedVector<cbindgen_private::ElementHandle> *>(&result));
        return result;
    }

    template<typename T>
    static SharedVector<ElementHandle>
    find_by_element_type_name(const ComponentHandle<T> &component, std::string_view type_name)
    {
        cbindgen_private::Slice<uint8_t> element_type_name_view {
            const_cast<unsigned char *>(reinterpret_cast<const unsigned char *>(type_name.data())),
            type_name.size()
        };
        auto vrc = component.into_dyn();
        SharedVector<ElementHandle> result;
        cbindgen_private::slint_testing_element_find_by_element_type_name(
                &vrc, &element_type_name_view,
                reinterpret_cast<SharedVector<cbindgen_private::ElementHandle> *>(&result));
        return result;
    }

    bool is_valid() const { return private_api::upgrade_item_weak(inner.item).has_value(); }

    std::optional<SharedString> id() const
    {
        SharedString id;
        if (cbindgen_private::slint_testing_element_id(&inner, &id)) {
            return id;
        } else {
            return std::nullopt;
        }
    }

    std::optional<SharedString> type_name() const
    {
        SharedString type_name;
        if (cbindgen_private::slint_testing_element_type_name(&inner, &type_name)) {
            return type_name;
        } else {
            return std::nullopt;
        }
    }

    std::optional<SharedVector<SharedString>> bases() const
    {
        SharedVector<SharedString> bases;
        if (cbindgen_private::slint_testing_element_bases(&inner, &bases)) {
            return bases;
        } else {
            return std::nullopt;
        }
    }

    std::optional<slint::testing::AccessibleRole> accessible_role() const
    {
        if (inner.element_index != 0)
            return std::nullopt;
        if (auto item = private_api::upgrade_item_weak(inner.item)) {
            return item->item_tree.vtable()->accessible_role(item->item_tree.borrow(), item->index);
        }
        return std::nullopt;
    }

    std::optional<SharedString> accessible_label() const
    {
        return get_accessible_string_property(cbindgen_private::AccessibleStringProperty::Label);
    }

    std::optional<SharedString> accessible_value() const
    {
        return get_accessible_string_property(cbindgen_private::AccessibleStringProperty::Value);
    }

    std::optional<SharedString> accessible_placeholder_text() const
    {
        return get_accessible_string_property(
                cbindgen_private::AccessibleStringProperty::PlaceholderText);
    }

    std::optional<SharedString> accessible_description() const
    {
        return get_accessible_string_property(
                cbindgen_private::AccessibleStringProperty::Description);
    }

    std::optional<float> accessible_value_maximum() const
    {
        if (auto result = get_accessible_string_property(
                    cbindgen_private::AccessibleStringProperty::ValueMaximum)) {
            float value = 0.0;
            if (cbindgen_private::slint_string_to_float(&*result, &value)) {
                return value;
            }
        }
        return std::nullopt;
    }

    std::optional<float> accessible_value_minimum() const
    {
        if (auto result = get_accessible_string_property(
                    cbindgen_private::AccessibleStringProperty::ValueMinimum)) {
            float value = 0.0;
            if (cbindgen_private::slint_string_to_float(&*result, &value)) {
                return value;
            }
        }
        return std::nullopt;
    }

    std::optional<float> accessible_value_step() const
    {
        if (auto result = get_accessible_string_property(
                    cbindgen_private::AccessibleStringProperty::ValueStep)) {
            float value = 0.0;
            if (cbindgen_private::slint_string_to_float(&*result, &value)) {
                return value;
            }
        }
        return std::nullopt;
    }

    std::optional<bool> accessible_checked() const
    {
        if (auto result = get_accessible_string_property(
                    cbindgen_private::AccessibleStringProperty::Checked)) {
            if (*result == "true")
                return true;
            else if (*result == "false")
                return false;
        }
        return std::nullopt;
    }

    std::optional<bool> accessible_checkable() const
    {
        if (auto result = get_accessible_string_property(
                    cbindgen_private::AccessibleStringProperty::Checkable)) {
            if (*result == "true")
                return true;
            else if (*result == "false")
                return false;
        }
        return std::nullopt;
    }

    void set_accessible_value(SharedString value) const
    {
        if (inner.element_index != 0)
            return;
        if (auto item = private_api::upgrade_item_weak(inner.item)) {
            union SetValueHelper {
                cbindgen_private::AccessibilityAction action;
                SetValueHelper(SharedString value)
                {
                    new (&action.set_value) cbindgen_private::AccessibilityAction::SetValue_Body {
                        cbindgen_private::AccessibilityAction::Tag::SetValue, std::move(value)
                    };
                }
                ~SetValueHelper() { action.set_value.~SetValue_Body(); }

            } action(std::move(value));
            item->item_tree.vtable()->accessibility_action(item->item_tree.borrow(), item->index,
                                                           &action.action);
        }
    }

    void invoke_accessible_increment_action() const
    {
        if (inner.element_index != 0)
            return;
        if (auto item = private_api::upgrade_item_weak(inner.item)) {
            union IncreaseActionHelper {
                cbindgen_private::AccessibilityAction action;
                IncreaseActionHelper()
                {
                    action.tag = cbindgen_private::AccessibilityAction::Tag::Increment;
                }
                ~IncreaseActionHelper() { }

            } action;
            item->item_tree.vtable()->accessibility_action(item->item_tree.borrow(), item->index,
                                                           &action.action);
        }
    }

    void invoke_accessible_decrement_action() const
    {
        if (inner.element_index != 0)
            return;
        if (auto item = private_api::upgrade_item_weak(inner.item)) {
            union DecreaseActionHelper {
                cbindgen_private::AccessibilityAction action;
                DecreaseActionHelper()
                {
                    action.tag = cbindgen_private::AccessibilityAction::Tag::Decrement;
                }
                ~DecreaseActionHelper() { }

            } action;
            item->item_tree.vtable()->accessibility_action(item->item_tree.borrow(), item->index,
                                                           &action.action);
        }
    }

    void invoke_accessible_default_action() const
    {
        if (inner.element_index != 0)
            return;
        if (auto item = private_api::upgrade_item_weak(inner.item)) {
            union DefaultActionHelper {
                cbindgen_private::AccessibilityAction action;
                DefaultActionHelper()
                {
                    action.tag = cbindgen_private::AccessibilityAction::Tag::Default;
                }
                ~DefaultActionHelper() { }

            } action;
            item->item_tree.vtable()->accessibility_action(item->item_tree.borrow(), item->index,
                                                           &action.action);
        }
    }

    LogicalSize size() const
    {
        if (auto item = private_api::upgrade_item_weak(inner.item)) {
            auto rect =
                    item->item_tree.vtable()->item_geometry(item->item_tree.borrow(), item->index);
            return LogicalSize({ rect.width, rect.height });
        }
        return LogicalSize({ 0, 0 });
    }

    LogicalPosition absolute_position() const
    {
        if (auto item = private_api::upgrade_item_weak(inner.item)) {
            cbindgen_private::LogicalRect rect =
                    item->item_tree.vtable()->item_geometry(item->item_tree.borrow(), item->index);
            cbindgen_private::LogicalPoint abs =
                    slint::cbindgen_private::slint_item_absolute_position(&item->item_tree,
                                                                          item->index);
            return LogicalPosition({ abs.x + rect.x, abs.y + rect.y });
        }
        return LogicalPosition({ 0, 0 });
    }

private:
    std::optional<SharedString>
    get_accessible_string_property(cbindgen_private::AccessibleStringProperty what) const
    {
        if (inner.element_index != 0)
            return std::nullopt;
        if (auto item = private_api::upgrade_item_weak(inner.item)) {
            SharedString result;
            if (item->item_tree.vtable()->accessible_string_property(item->item_tree.borrow(),
                                                                     item->index, what, &result)) {
                return result;
            }
        }
        return std::nullopt;
    }
};
}

#    endif // SLINT_FEATURE_EXPERIMENTAL
#endif // SLINT_FEATURE_TESTING