Program Listing for File slint_window.h

Return to documentation for file (/home/runner/work/slint/slint/api/cpp/include/slint_window.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

#pragma once

#include "slint_internal.h"

#ifndef SLINT_FEATURE_FREESTANDING
#    include <thread>
#    include <iostream>
#endif

namespace slint {
#if !defined(DOXYGEN)
namespace platform {
class SkiaRenderer;
class SoftwareRenderer;
}
#endif

namespace private_api {
inline void assert_main_thread()
{
#ifndef SLINT_FEATURE_FREESTANDING
#    ifndef NDEBUG
    static auto main_thread_id = std::this_thread::get_id();
    if (main_thread_id != std::this_thread::get_id()) {
        std::cerr << "A function that should be only called from the main thread was called from a "
                     "thread."
                  << std::endl;
        std::cerr << "Most API should be called from the main thread. When using thread one must "
                     "use slint::invoke_from_event_loop."
                  << std::endl;
        std::abort();
    }
#    endif
#endif
}

using ItemTreeRc = vtable::VRc<cbindgen_private::ItemTreeVTable>;

class WindowAdapterRc
{
public:
    explicit WindowAdapterRc(cbindgen_private::WindowAdapterRcOpaque adopted_inner)
    {
        assert_main_thread();
        cbindgen_private::slint_windowrc_clone(&adopted_inner, &inner);
    }
    WindowAdapterRc() { cbindgen_private::slint_windowrc_init(&inner); }
    ~WindowAdapterRc() { cbindgen_private::slint_windowrc_drop(&inner); }
    WindowAdapterRc(const WindowAdapterRc &other) : WindowAdapterRc(other.inner) { }
    WindowAdapterRc(WindowAdapterRc &&) = delete;
    WindowAdapterRc &operator=(WindowAdapterRc &&) = delete;
    WindowAdapterRc &operator=(const WindowAdapterRc &other)
    {
        assert_main_thread();
        if (this != &other) {
            cbindgen_private::slint_windowrc_drop(&inner);
            cbindgen_private::slint_windowrc_clone(&other.inner, &inner);
        }
        return *this;
    }

    void show() const { slint_windowrc_show(&inner); }
    void hide() const { slint_windowrc_hide(&inner); }
    bool is_visible() const { return slint_windowrc_is_visible(&inner); }

    float scale_factor() const { return slint_windowrc_get_scale_factor(&inner); }
    void set_scale_factor(float value) const { slint_windowrc_set_scale_factor(&inner, value); }

    cbindgen_private::ColorScheme color_scheme() const
    {
        return slint_windowrc_color_scheme(&inner);
    }

    bool text_input_focused() const { return slint_windowrc_get_text_input_focused(&inner); }
    void set_text_input_focused(bool value) const
    {
        slint_windowrc_set_text_input_focused(&inner, value);
    }

    template<typename Component, typename ItemArray>
    void unregister_item_tree(Component *c, ItemArray items) const
    {
        cbindgen_private::slint_unregister_item_tree(
                vtable::VRef<cbindgen_private::ItemTreeVTable> { &Component::static_vtable, c },
                items, &inner);
    }

    void set_focus_item(const ItemTreeRc &component_rc, uint32_t item_index, bool set_focus)
    {
        cbindgen_private::ItemRc item_rc { component_rc, item_index };
        cbindgen_private::slint_windowrc_set_focus_item(&inner, &item_rc, set_focus);
    }

    void set_component(const cbindgen_private::ItemTreeWeak &weak) const
    {
        auto item_tree_rc = (*weak.lock()).into_dyn();
        slint_windowrc_set_component(&inner, &item_tree_rc);
    }

    template<typename Component, typename Parent, typename PosGetter>
    void show_popup(const Parent *parent_component, PosGetter pos, bool close_on_click,
                    cbindgen_private::ItemRc parent_item) const
    {
        auto popup = Component::create(parent_component);
        cbindgen_private::Point p = pos(popup);
        auto popup_dyn = popup.into_dyn();
        cbindgen_private::slint_windowrc_show_popup(&inner, &popup_dyn, p, close_on_click,
                                                    &parent_item);
    }

    void close_popup() const { cbindgen_private::slint_windowrc_close_popup(&inner); }

    template<std::invocable<RenderingState, GraphicsAPI> F>
    std::optional<SetRenderingNotifierError> set_rendering_notifier(F callback) const
    {
        auto actual_cb = [](RenderingState state, GraphicsAPI graphics_api, void *data) {
            (*reinterpret_cast<F *>(data))(state, graphics_api);
        };
        SetRenderingNotifierError err;
        if (cbindgen_private::slint_windowrc_set_rendering_notifier(
                    &inner, actual_cb,
                    [](void *user_data) { delete reinterpret_cast<F *>(user_data); },
                    new F(std::move(callback)), &err)) {
            return {};
        } else {
            return err;
        }
    }

    // clang-format off
    template<std::invocable F>
        requires(std::is_convertible_v<std::invoke_result_t<F>, CloseRequestResponse>)
    void on_close_requested(F callback) const
    // clang-format on
    {
        auto actual_cb = [](void *data) { return (*reinterpret_cast<F *>(data))(); };
        cbindgen_private::slint_windowrc_on_close_requested(
                &inner, actual_cb, [](void *user_data) { delete reinterpret_cast<F *>(user_data); },
                new F(std::move(callback)));
    }

    void request_redraw() const { cbindgen_private::slint_windowrc_request_redraw(&inner); }

    slint::PhysicalPosition position() const
    {
        slint::PhysicalPosition pos;
        cbindgen_private::slint_windowrc_position(&inner, &pos);
        return pos;
    }

    void set_logical_position(const slint::LogicalPosition &pos)
    {
        cbindgen_private::slint_windowrc_set_logical_position(&inner, &pos);
    }

    void set_physical_position(const slint::PhysicalPosition &pos)
    {
        cbindgen_private::slint_windowrc_set_physical_position(&inner, &pos);
    }

    slint::PhysicalSize size() const
    {
        return slint::PhysicalSize(cbindgen_private::slint_windowrc_size(&inner));
    }

    void set_logical_size(const slint::LogicalSize &size)
    {
        cbindgen_private::slint_windowrc_set_logical_size(&inner, &size);
    }

    void set_physical_size(const slint::PhysicalSize &size)
    {
        cbindgen_private::slint_windowrc_set_physical_size(&inner, &size);
    }

    void dispatch_pointer_event(const cbindgen_private::MouseEvent &event)
    {
        private_api::assert_main_thread();
        cbindgen_private::slint_windowrc_dispatch_pointer_event(&inner, event);
    }

    inline std::optional<SharedString> register_font_from_path(const SharedString &path)
    {
        SharedString maybe_err;
        cbindgen_private::slint_register_font_from_path(&inner, &path, &maybe_err);
        if (!maybe_err.empty()) {
            return maybe_err;
        } else {
            return {};
        }
    }

    inline std::optional<SharedString> register_font_from_data(const uint8_t *data, std::size_t len)
    {
        SharedString maybe_err;
        cbindgen_private::slint_register_font_from_data(
                &inner, { const_cast<uint8_t *>(data), len }, &maybe_err);
        if (!maybe_err.empty()) {
            return maybe_err;
        } else {
            return {};
        }
    }

    inline void register_bitmap_font(const cbindgen_private::BitmapFont &font)
    {
        cbindgen_private::slint_register_bitmap_font(&inner, &font);
    }

    inline float default_font_size() const
    {
        return cbindgen_private::slint_windowrc_default_font_size(&inner);
    }

    const cbindgen_private::WindowAdapterRcOpaque &handle() const { return inner; }

private:
    friend class slint::platform::SkiaRenderer;
    friend class slint::platform::SoftwareRenderer;
    cbindgen_private::WindowAdapterRcOpaque inner;
};

}

class Window
{
public:
    explicit Window(const private_api::WindowAdapterRc &windowrc) : inner(windowrc) { }
    Window(const Window &other) = delete;
    Window &operator=(const Window &other) = delete;
    Window(Window &&other) = delete;
    Window &operator=(Window &&other) = delete;
    ~Window() = default;

    void show()
    {
        private_api::assert_main_thread();
        inner.show();
    }
    void hide()
    {
        private_api::assert_main_thread();
        inner.hide();
    }

    bool is_visible() const
    {
        private_api::assert_main_thread();
        return inner.is_visible();
    }

    template<std::invocable<RenderingState, GraphicsAPI> F>
    std::optional<SetRenderingNotifierError> set_rendering_notifier(F &&callback) const
    {
        private_api::assert_main_thread();
        return inner.set_rendering_notifier(std::forward<F>(callback));
    }

    // clang-format off
    template<std::invocable F>
        requires(std::is_convertible_v<std::invoke_result_t<F>, CloseRequestResponse>)
    void on_close_requested(F &&callback) const
    // clang-format on
    {
        private_api::assert_main_thread();
        return inner.on_close_requested(std::forward<F>(callback));
    }

    void request_redraw() const
    {
        private_api::assert_main_thread();
        inner.request_redraw();
    }

    slint::PhysicalPosition position() const
    {
        private_api::assert_main_thread();
        return inner.position();
    }

    void set_position(const slint::LogicalPosition &pos)
    {
        private_api::assert_main_thread();
        inner.set_logical_position(pos);
    }
    void set_position(const slint::PhysicalPosition &pos)
    {
        private_api::assert_main_thread();
        inner.set_physical_position(pos);
    }

    slint::PhysicalSize size() const
    {
        private_api::assert_main_thread();
        return inner.size();
    }

    void set_size(const slint::LogicalSize &size)
    {
        private_api::assert_main_thread();
        inner.set_logical_size(size);
    }
    void set_size(const slint::PhysicalSize &size)
    {
        private_api::assert_main_thread();
        inner.set_physical_size(size);
    }

    float scale_factor() const
    {
        private_api::assert_main_thread();
        return inner.scale_factor();
    }

    bool is_fullscreen() const
    {
        private_api::assert_main_thread();
        return cbindgen_private::slint_windowrc_is_fullscreen(&inner.handle());
    }
    void set_fullscreen(bool fullscreen)
    {
        private_api::assert_main_thread();
        cbindgen_private::slint_windowrc_set_fullscreen(&inner.handle(), fullscreen);
    }

    bool is_maximized() const
    {
        private_api::assert_main_thread();
        return cbindgen_private::slint_windowrc_is_maximized(&inner.handle());
    }
    void set_maximized(bool maximized)
    {
        private_api::assert_main_thread();
        cbindgen_private::slint_windowrc_set_maximized(&inner.handle(), maximized);
    }

    bool is_minimized() const
    {
        private_api::assert_main_thread();
        return cbindgen_private::slint_windowrc_is_minimized(&inner.handle());
    }
    void set_minimized(bool minimized)
    {
        private_api::assert_main_thread();
        cbindgen_private::slint_windowrc_set_minimized(&inner.handle(), minimized);
    }

    void dispatch_key_press_event(const SharedString &text)
    {
        private_api::assert_main_thread();
        cbindgen_private::slint_windowrc_dispatch_key_event(
                &inner.handle(), cbindgen_private::KeyEventType::KeyPressed, &text, false);
    }

    void dispatch_key_press_repeat_event(const SharedString &text)
    {
        private_api::assert_main_thread();
        cbindgen_private::slint_windowrc_dispatch_key_event(
                &inner.handle(), cbindgen_private::KeyEventType::KeyPressed, &text, true);
    }

    void dispatch_key_release_event(const SharedString &text)
    {
        private_api::assert_main_thread();
        cbindgen_private::slint_windowrc_dispatch_key_event(
                &inner.handle(), cbindgen_private::KeyEventType::KeyReleased, &text, false);
    }

    void dispatch_pointer_press_event(LogicalPosition pos, PointerEventButton button)
    {
        private_api::assert_main_thread();
        using slint::cbindgen_private::MouseEvent;
        MouseEvent event { .tag = MouseEvent::Tag::Pressed,
                           .pressed = MouseEvent::Pressed_Body { .position = { pos.x, pos.y },
                                                                 .button = button,
                                                                 .click_count = 0 } };
        inner.dispatch_pointer_event(event);
    }
    void dispatch_pointer_release_event(LogicalPosition pos, PointerEventButton button)
    {
        private_api::assert_main_thread();
        using slint::cbindgen_private::MouseEvent;
        MouseEvent event { .tag = MouseEvent::Tag::Released,
                           .released = MouseEvent::Released_Body { .position = { pos.x, pos.y },
                                                                   .button = button,
                                                                   .click_count = 0 } };
        inner.dispatch_pointer_event(event);
    }
    void dispatch_pointer_exit_event()
    {
        private_api::assert_main_thread();
        using slint::cbindgen_private::MouseEvent;
        MouseEvent event { .tag = MouseEvent::Tag::Exit, .moved = {} };
        inner.dispatch_pointer_event(event);
    }

    void dispatch_pointer_move_event(LogicalPosition pos)
    {
        private_api::assert_main_thread();
        using slint::cbindgen_private::MouseEvent;
        MouseEvent event { .tag = MouseEvent::Tag::Moved,
                           .moved = MouseEvent::Moved_Body { .position = { pos.x, pos.y } } };
        inner.dispatch_pointer_event(event);
    }

    void dispatch_pointer_scroll_event(LogicalPosition pos, float delta_x, float delta_y)
    {
        private_api::assert_main_thread();
        using slint::cbindgen_private::MouseEvent;
        MouseEvent event { .tag = MouseEvent::Tag::Wheel,
                           .wheel = MouseEvent::Wheel_Body { .position = { pos.x, pos.y },
                                                             .delta_x = delta_x,
                                                             .delta_y = delta_y } };
        inner.dispatch_pointer_event(event);
    }

    void dispatch_resize_event(slint::LogicalSize s)
    {
        private_api::assert_main_thread();
        using slint::cbindgen_private::WindowEvent;
        WindowEvent event { .resized =
                                    WindowEvent::Resized_Body { .tag = WindowEvent::Tag::Resized,
                                                                .size = { s.width, s.height } } };
        cbindgen_private::slint_windowrc_dispatch_event(&inner.handle(), &event);
    }

    void dispatch_scale_factor_change_event(float factor)
    {
        private_api::assert_main_thread();
        using slint::cbindgen_private::WindowEvent;
        WindowEvent event { .scale_factor_changed = WindowEvent::ScaleFactorChanged_Body {
                                    .tag = WindowEvent::Tag::ScaleFactorChanged,
                                    .scale_factor = factor } };
        cbindgen_private::slint_windowrc_dispatch_event(&inner.handle(), &event);
    }

    void dispatch_window_active_changed_event(bool active)
    {
        private_api::assert_main_thread();
        using slint::cbindgen_private::WindowEvent;
        WindowEvent event { .window_active_changed = WindowEvent::WindowActiveChanged_Body {
                                    .tag = WindowEvent::Tag::WindowActiveChanged, ._0 = active } };
        cbindgen_private::slint_windowrc_dispatch_event(&inner.handle(), &event);
    }

    void dispatch_close_requested_event()
    {
        private_api::assert_main_thread();
        using slint::cbindgen_private::WindowEvent;
        WindowEvent event { .tag = WindowEvent::Tag::CloseRequested };
        cbindgen_private::slint_windowrc_dispatch_event(&inner.handle(), &event);
    }

    bool has_active_animations() const
    {
        private_api::assert_main_thread();
        return cbindgen_private::slint_windowrc_has_active_animations(&inner.handle());
    }

    private_api::WindowAdapterRc &window_handle() { return inner; }
    const private_api::WindowAdapterRc &window_handle() const { return inner; }

private:
    private_api::WindowAdapterRc inner;
};

}