Program Listing for File slint.h
↰ Return to documentation for file (/home/runner/work/slint/slint/api/cpp/include/slint.h
)
// Copyright © SixtyFPS GmbH <info@slint-ui.com>
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-commercial
#pragma once
#if defined(__GNUC__) || defined(__clang__)
// In C++17, it is conditionally supported, but still valid for all compiler we care
# pragma GCC diagnostic ignored "-Winvalid-offsetof"
#endif
#include <vector>
#include <memory>
#include <algorithm>
#include <iostream> // FIXME: remove: iostream always bring it lots of code so we should not have it in this header
#include <chrono>
#include <optional>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <span>
namespace slint::cbindgen_private {
// Workaround https://github.com/eqrion/cbindgen/issues/43
struct ComponentVTable;
struct ItemVTable;
}
#include "slint_internal.h"
#include "slint_size.h"
#include "slint_point.h"
#include "slint_backend_internal.h"
#include "slint_qt_internal.h"
#include "slint_selector_internal.h"
namespace slint {
// Bring opaque structure in scope
namespace private_api {
using cbindgen_private::ComponentVTable;
using cbindgen_private::ItemVTable;
using ComponentRc = vtable::VRc<private_api::ComponentVTable>;
using ComponentRef = vtable::VRef<private_api::ComponentVTable>;
using IndexRange = cbindgen_private::IndexRange;
using ItemRef = vtable::VRef<private_api::ItemVTable>;
using ItemVisitorRefMut = vtable::VRefMut<cbindgen_private::ItemVisitorVTable>;
using cbindgen_private::ComponentWeak;
using cbindgen_private::ItemWeak;
using cbindgen_private::TraversalOrder;
}
namespace private_api {
using ItemTreeNode = cbindgen_private::ItemTreeNode;
using ItemArrayEntry =
vtable::VOffset<uint8_t, slint::cbindgen_private::ItemVTable, vtable::AllowPin>;
using ItemArray = slint::cbindgen_private::Slice<ItemArrayEntry>;
using cbindgen_private::KeyboardModifiers;
using cbindgen_private::KeyEvent;
using cbindgen_private::PointerEvent;
using cbindgen_private::StandardListViewItem;
inline void assert_main_thread()
{
#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
}
class WindowAdapterRc
{
public:
explicit WindowAdapterRc(cbindgen_private::WindowAdapterRcOpaque adopted_inner)
: inner(adopted_inner)
{
}
WindowAdapterRc() { cbindgen_private::slint_windowrc_init(&inner); }
~WindowAdapterRc() { cbindgen_private::slint_windowrc_drop(&inner); }
WindowAdapterRc(const WindowAdapterRc &other)
{
assert_main_thread();
cbindgen_private::slint_windowrc_clone(&other.inner, &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); }
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); }
template<typename Component, typename ItemArray>
void unregister_component(Component *c, ItemArray items) const
{
cbindgen_private::slint_unregister_component(
vtable::VRef<ComponentVTable> { &Component::static_vtable, c }, items, &inner);
}
void set_focus_item(const ComponentRc &component_rc, uintptr_t item_index)
{
cbindgen_private::ItemRc item_rc { component_rc, item_index };
cbindgen_private::slint_windowrc_set_focus_item(&inner, &item_rc);
}
template<typename Component, typename ItemArray>
void register_component(Component *c, ItemArray items) const
{
cbindgen_private::slint_register_component(
vtable::VRef<ComponentVTable> { &Component::static_vtable, c }, items, &inner);
}
template<typename Component>
void set_component(const Component &c) const
{
auto self_rc = c.self_weak.lock().value().into_dyn();
slint_windowrc_set_component(&inner, &self_rc);
}
template<typename Component, typename Parent>
void show_popup(const Parent *parent_component, cbindgen_private::Point p,
cbindgen_private::ItemRc parent_item) const
{
auto popup = Component::create(parent_component).into_dyn();
cbindgen_private::slint_windowrc_show_popup(&inner, &popup, p, &parent_item);
}
template<typename 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;
}
}
template<typename F>
void on_close_requested(F callback) const
{
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);
}
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 {};
}
}
private:
cbindgen_private::WindowAdapterRcOpaque inner;
};
constexpr inline ItemTreeNode make_item_node(uint32_t child_count, uint32_t child_index,
uint32_t parent_index, uint32_t item_array_index,
bool is_accessible)
{
return ItemTreeNode { ItemTreeNode::Item_Body { ItemTreeNode::Tag::Item, is_accessible,
child_count, child_index, parent_index,
item_array_index } };
}
constexpr inline ItemTreeNode make_dyn_node(std::uintptr_t offset, std::uint32_t parent_index)
{
return ItemTreeNode { ItemTreeNode::DynamicTree_Body { ItemTreeNode::Tag::DynamicTree, offset,
parent_index } };
}
inline ItemRef get_item_ref(ComponentRef component,
const cbindgen_private::Slice<ItemTreeNode> item_tree,
const private_api::ItemArray item_array, int index)
{
const auto item_array_index = item_tree.ptr[index].item.item_array_index;
const auto item = item_array[item_array_index];
return ItemRef { item.vtable, reinterpret_cast<char *>(component.instance) + item.offset };
}
inline void dealloc(const ComponentVTable *, uint8_t *ptr, vtable::Layout layout)
{
#ifdef __cpp_sized_deallocation
::operator delete(reinterpret_cast<void *>(ptr), layout.size,
static_cast<std::align_val_t>(layout.align));
#else
::operator delete(reinterpret_cast<void *>(ptr), static_cast<std::align_val_t>(layout.align));
#endif
}
template<typename T>
inline vtable::Layout drop_in_place(ComponentRef component)
{
reinterpret_cast<T *>(component.instance)->~T();
return vtable::Layout { sizeof(T), alignof(T) };
}
#if !defined(DOXYGEN)
# if defined(_WIN32) || defined(_WIN64)
// On Windows cross-dll data relocations are not supported:
// https://docs.microsoft.com/en-us/cpp/c-language/rules-and-limitations-for-dllimport-dllexport?view=msvc-160
// so we have a relocation to a function that returns the address we seek. That
// relocation will be resolved to the locally linked stub library, the implementation of
// which will be patched.
# define SLINT_GET_ITEM_VTABLE(VTableName) slint::private_api::slint_get_##VTableName()
# else
# define SLINT_GET_ITEM_VTABLE(VTableName) (&slint::private_api::VTableName)
# endif
#endif // !defined(DOXYGEN)
template<typename T>
struct ReturnWrapper
{
ReturnWrapper(T val) : value(std::move(val)) { }
T value;
};
template<>
struct ReturnWrapper<void>
{
};
} // namespace private_api
template<typename T>
class ComponentWeakHandle;
template<typename T>
class ComponentHandle
{
vtable::VRc<private_api::ComponentVTable, T> inner;
friend class ComponentWeakHandle<T>;
public:
ComponentHandle(const vtable::VRc<private_api::ComponentVTable, T> &inner) : inner(inner) { }
const T *operator->() const
{
private_api::assert_main_thread();
return inner.operator->();
}
const T &operator*() const
{
private_api::assert_main_thread();
return inner.operator*();
}
T *operator->()
{
private_api::assert_main_thread();
return inner.operator->();
}
T &operator*()
{
private_api::assert_main_thread();
return inner.operator*();
}
vtable::VRc<private_api::ComponentVTable> into_dyn() const { return inner.into_dyn(); }
};
template<typename T>
class ComponentWeakHandle
{
vtable::VWeak<private_api::ComponentVTable, T> inner;
public:
ComponentWeakHandle() = default;
ComponentWeakHandle(const ComponentHandle<T> &other) : inner(other.inner) { }
std::optional<ComponentHandle<T>> lock() const
{
private_api::assert_main_thread();
if (auto l = inner.lock()) {
return { ComponentHandle(*l) };
} else {
return {};
}
}
};
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() { inner.show(); }
void hide() { inner.hide(); }
template<typename F>
std::optional<SetRenderingNotifierError> set_rendering_notifier(F &&callback) const
{
return inner.set_rendering_notifier(std::forward<F>(callback));
}
template<typename F>
void on_close_requested(F &&callback) const
{
static_assert(std::is_invocable_v<F>, "Functor callback must be callable");
static_assert(std::is_same_v<std::invoke_result_t<F>, CloseRequestResponse>,
"Functor callback must return CloseRequestResponse");
return inner.on_close_requested(std::forward<F>(callback));
}
void request_redraw() const { inner.request_redraw(); }
slint::PhysicalPosition position() const { return inner.position(); }
void set_position(const slint::LogicalPosition &pos) { inner.set_logical_position(pos); }
void set_position(const slint::PhysicalPosition &pos) { inner.set_physical_position(pos); }
slint::PhysicalSize size() const { return inner.size(); }
void set_size(const slint::LogicalSize &size) { inner.set_logical_size(size); }
void set_size(const slint::PhysicalSize &size) { inner.set_physical_size(size); }
private_api::WindowAdapterRc &window_handle() { return inner; }
const private_api::WindowAdapterRc &window_handle() const { return inner; }
private:
private_api::WindowAdapterRc inner;
};
struct Timer
{
Timer() : id(-1) { }
template<typename F>
Timer(std::chrono::milliseconds interval, F callback)
: id(cbindgen_private::slint_timer_start(
-1, TimerMode::Repeated, interval.count(),
[](void *data) { (*reinterpret_cast<F *>(data))(); }, new F(std::move(callback)),
[](void *data) { delete reinterpret_cast<F *>(data); }))
{
}
Timer(const Timer &) = delete;
Timer &operator=(const Timer &) = delete;
~Timer() { cbindgen_private::slint_timer_destroy(id); }
template<typename F>
void start(TimerMode mode, std::chrono::milliseconds interval, F callback)
{
id = cbindgen_private::slint_timer_start(
id, mode, interval.count(), [](void *data) { (*reinterpret_cast<F *>(data))(); },
new F(std::move(callback)), [](void *data) { delete reinterpret_cast<F *>(data); });
}
void stop() { cbindgen_private::slint_timer_stop(id); }
void restart() { cbindgen_private::slint_timer_restart(id); }
bool running() const { return cbindgen_private::slint_timer_running(id); }
template<typename F>
static void single_shot(std::chrono::milliseconds duration, F callback)
{
cbindgen_private::slint_timer_singleshot(
duration.count(), [](void *data) { (*reinterpret_cast<F *>(data))(); },
new F(std::move(callback)), [](void *data) { delete reinterpret_cast<F *>(data); });
}
private:
int64_t id;
};
namespace cbindgen_private {
inline LayoutInfo LayoutInfo::merge(const LayoutInfo &other) const
{
// Note: This "logic" is duplicated from LayoutInfo::merge in layout.rs.
return LayoutInfo { std::min(max, other.max),
std::min(max_percent, other.max_percent),
std::max(min, other.min),
std::max(min_percent, other.min_percent),
std::max(preferred, other.preferred),
std::min(stretch, other.stretch) };
}
}
namespace private_api {
inline SharedVector<float> solve_box_layout(const cbindgen_private::BoxLayoutData &data,
cbindgen_private::Slice<int> repeater_indexes)
{
SharedVector<float> result;
cbindgen_private::Slice<uint32_t> ri { reinterpret_cast<uint32_t *>(repeater_indexes.ptr),
repeater_indexes.len };
cbindgen_private::slint_solve_box_layout(&data, ri, &result);
return result;
}
inline SharedVector<float> solve_grid_layout(const cbindgen_private::GridLayoutData &data)
{
SharedVector<float> result;
cbindgen_private::slint_solve_grid_layout(&data, &result);
return result;
}
inline cbindgen_private::LayoutInfo
grid_layout_info(cbindgen_private::Slice<cbindgen_private::GridLayoutCellData> cells, float spacing,
const cbindgen_private::Padding &padding)
{
return cbindgen_private::slint_grid_layout_info(cells, spacing, &padding);
}
inline cbindgen_private::LayoutInfo
box_layout_info(cbindgen_private::Slice<cbindgen_private::BoxLayoutCellData> cells, float spacing,
const cbindgen_private::Padding &padding,
cbindgen_private::LayoutAlignment alignment)
{
return cbindgen_private::slint_box_layout_info(cells, spacing, &padding, alignment);
}
inline cbindgen_private::LayoutInfo
box_layout_info_ortho(cbindgen_private::Slice<cbindgen_private::BoxLayoutCellData> cells,
const cbindgen_private::Padding &padding)
{
return cbindgen_private::slint_box_layout_info_ortho(cells, &padding);
}
inline SharedVector<float> solve_path_layout(const cbindgen_private::PathLayoutData &data,
cbindgen_private::Slice<int> repeater_indexes)
{
SharedVector<float> result;
cbindgen_private::Slice<uint32_t> ri { reinterpret_cast<uint32_t *>(repeater_indexes.ptr),
repeater_indexes.len };
cbindgen_private::slint_solve_path_layout(&data, ri, &result);
return result;
}
inline float layout_cache_access(const SharedVector<float> &cache, int offset, int repeater_index)
{
size_t idx = size_t(cache[offset]) + repeater_index * 2;
return idx < cache.size() ? cache[idx] : 0;
}
// models
struct AbstractRepeaterView
{
virtual ~AbstractRepeaterView() = default;
virtual void row_added(int index, int count) = 0;
virtual void row_removed(int index, int count) = 0;
virtual void row_changed(int index) = 0;
virtual void reset() = 0;
};
using ModelPeer = std::weak_ptr<AbstractRepeaterView>;
template<typename M>
auto access_array_index(const M &model, int index)
{
if (const auto v = model->row_data_tracked(index)) {
return *v;
} else {
return decltype(*v) {};
}
}
} // namespace private_api
template<typename ModelData>
class Model
{
public:
virtual ~Model() = default;
Model() = default;
Model(const Model &) = delete;
Model &operator=(const Model &) = delete;
virtual int row_count() const = 0;
virtual std::optional<ModelData> row_data(int i) const = 0;
virtual void set_row_data(int, const ModelData &)
{
std::cerr << "Model::set_row_data was called on a read-only model" << std::endl;
};
void attach_peer(private_api::ModelPeer p) { peers.push_back(std::move(p)); }
void track_row_count_changes() const { model_row_count_dirty_property.get(); }
void track_row_data_changes(int row) const
{
auto it = std::lower_bound(tracked_rows.begin(), tracked_rows.end(), row);
if (it == tracked_rows.end() || row < *it) {
tracked_rows.insert(it, row);
}
model_row_data_dirty_property.get();
}
std::optional<ModelData> row_data_tracked(int row) const
{
track_row_data_changes(row);
return row_data(row);
}
protected:
void row_changed(int row)
{
if (std::binary_search(tracked_rows.begin(), tracked_rows.end(), row)) {
model_row_data_dirty_property.mark_dirty();
}
for_each_peers([=](auto peer) { peer->row_changed(row); });
}
void row_added(int index, int count)
{
model_row_count_dirty_property.mark_dirty();
tracked_rows.clear();
model_row_data_dirty_property.mark_dirty();
for_each_peers([=](auto peer) { peer->row_added(index, count); });
}
void row_removed(int index, int count)
{
model_row_count_dirty_property.mark_dirty();
tracked_rows.clear();
model_row_data_dirty_property.mark_dirty();
for_each_peers([=](auto peer) { peer->row_removed(index, count); });
}
void reset()
{
model_row_count_dirty_property.mark_dirty();
tracked_rows.clear();
model_row_data_dirty_property.mark_dirty();
for_each_peers([=](auto peer) { peer->reset(); });
}
private:
template<typename F>
void for_each_peers(const F &f)
{
private_api::assert_main_thread();
peers.erase(std::remove_if(peers.begin(), peers.end(),
[&](const auto &p) {
if (auto pp = p.lock()) {
f(pp);
return false;
}
return true;
}),
peers.end());
}
std::vector<private_api::ModelPeer> peers;
private_api::Property<bool> model_row_count_dirty_property;
private_api::Property<bool> model_row_data_dirty_property;
mutable std::vector<int> tracked_rows;
};
namespace private_api {
template<int Count, typename ModelData>
class ArrayModel : public Model<ModelData>
{
std::array<ModelData, Count> data;
public:
template<typename... A>
ArrayModel(A &&...a) : data { std::forward<A>(a)... }
{
}
int row_count() const override { return Count; }
std::optional<ModelData> row_data(int i) const override
{
if (i >= row_count())
return {};
return data[i];
}
void set_row_data(int i, const ModelData &value) override
{
if (i < row_count()) {
data[i] = value;
this->row_changed(i);
}
}
};
struct IntModel : Model<int>
{
IntModel(int d) : data(d) { }
int data;
int row_count() const override { return data; }
std::optional<int> row_data(int value) const override
{
if (value >= row_count())
return {};
return value;
}
};
} // namespace private_api
template<typename ModelData>
class VectorModel : public Model<ModelData>
{
std::vector<ModelData> data;
public:
VectorModel() = default;
VectorModel(std::vector<ModelData> array) : data(std::move(array)) { }
int row_count() const override { return int(data.size()); }
std::optional<ModelData> row_data(int i) const override
{
if (i >= row_count())
return {};
return std::optional<ModelData> { data[i] };
}
void set_row_data(int i, const ModelData &value) override
{
if (i < row_count()) {
data[i] = value;
this->row_changed(i);
}
}
void push_back(const ModelData &value)
{
data.push_back(value);
this->row_added(int(data.size()) - 1, 1);
}
void erase(int index)
{
data.erase(data.begin() + index);
this->row_removed(index, 1);
}
void insert(size_t index, const ModelData &value)
{
data.insert(data.begin() + index, value);
this->row_added(int(index), 1);
}
};
namespace private_api {
template<typename C, typename ModelData>
class Repeater
{
private_api::Property<std::shared_ptr<Model<ModelData>>> model;
struct RepeaterInner : AbstractRepeaterView
{
enum class State { Clean, Dirty };
struct ComponentWithState
{
State state = State::Dirty;
std::optional<ComponentHandle<C>> ptr;
};
std::vector<ComponentWithState> data;
private_api::Property<bool> is_dirty { true };
void row_added(int index, int count) override
{
is_dirty.set(true);
data.resize(data.size() + count);
std::rotate(data.begin() + index, data.end() - count, data.end());
}
void row_changed(int index) override
{
is_dirty.set(true);
data[index].state = State::Dirty;
}
void row_removed(int index, int count) override
{
is_dirty.set(true);
data.erase(data.begin() + index, data.begin() + index + count);
for (std::size_t i = index; i < data.size(); ++i) {
// all the indexes are dirty
data[i].state = State::Dirty;
}
}
void reset() override
{
is_dirty.set(true);
data.clear();
}
};
public:
// FIXME: should be private, but layouting code uses it.
mutable std::shared_ptr<RepeaterInner> inner;
template<typename F>
void set_model_binding(F &&binding) const
{
model.set_binding(std::forward<F>(binding));
}
template<typename Parent>
void ensure_updated(const Parent *parent) const
{
if (model.is_dirty()) {
inner = std::make_shared<RepeaterInner>();
if (auto m = model.get()) {
m->attach_peer(inner);
}
}
if (inner && inner->is_dirty.get()) {
inner->is_dirty.set(false);
if (auto m = model.get()) {
int count = m->row_count();
inner->data.resize(count);
for (int i = 0; i < count; ++i) {
auto &c = inner->data[i];
if (!c.ptr) {
c.ptr = C::create(parent);
}
if (c.state == RepeaterInner::State::Dirty) {
(*c.ptr)->update_data(i, *m->row_data(i));
}
}
} else {
inner->data.clear();
}
} else {
// just do a get() on the model to register dependencies so that, for example, the
// layout property tracker becomes dirty.
model.get();
}
}
template<typename Parent>
void ensure_updated_listview(const Parent *parent,
const private_api::Property<float> *viewport_width,
const private_api::Property<float> *viewport_height,
[[maybe_unused]] const private_api::Property<float> *viewport_y,
float listview_width, [[maybe_unused]] float listview_height) const
{
// TODO: the rust code in model.rs try to only allocate as many items as visible items
ensure_updated(parent);
float h = compute_layout_listview(viewport_width, listview_width);
viewport_height->set(h);
}
uintptr_t visit(TraversalOrder order, private_api::ItemVisitorRefMut visitor) const
{
for (std::size_t i = 0; i < inner->data.size(); ++i) {
int index = order == TraversalOrder::BackToFront ? i : inner->data.size() - 1 - i;
auto ref = item_at(index);
if (ref.vtable->visit_children_item(ref, -1, order, visitor)
!= std::numeric_limits<uint64_t>::max()) {
return index;
}
}
return std::numeric_limits<uint64_t>::max();
}
vtable::VRef<private_api::ComponentVTable> item_at(int i) const
{
const auto &x = inner->data.at(i);
return { &C::static_vtable, const_cast<C *>(&(**x.ptr)) };
}
vtable::VWeak<private_api::ComponentVTable> component_at(int i) const
{
const auto &x = inner->data.at(i);
return vtable::VWeak<private_api::ComponentVTable> { x.ptr->into_dyn() };
}
private_api::IndexRange index_range() const
{
return private_api::IndexRange { 0, inner->data.size() };
}
float compute_layout_listview(const private_api::Property<float> *viewport_width,
float listview_width) const
{
float offset = 0;
viewport_width->set(listview_width);
if (!inner)
return offset;
for (auto &x : inner->data) {
(*x.ptr)->listview_layout(&offset, viewport_width);
}
return offset;
}
void model_set_row_data(int row, const ModelData &data) const
{
if (model.is_dirty()) {
std::abort();
}
if (auto m = model.get()) {
if (row < m->row_count()) {
m->set_row_data(row, data);
if (inner && inner->is_dirty.get()) {
auto &c = inner->data[row];
if (c.state == RepeaterInner::State::Dirty && c.ptr) {
(*c.ptr)->update_data(row, *m->row_data(row));
}
}
}
}
}
};
} // namespace private_api
#if !defined(DOXYGEN)
cbindgen_private::Flickable::Flickable()
{
slint_flickable_data_init(&data);
}
cbindgen_private::Flickable::~Flickable()
{
slint_flickable_data_free(&data);
}
cbindgen_private::NativeStyleMetrics::NativeStyleMetrics(void *)
{
slint_native_style_metrics_init(this);
}
cbindgen_private::NativeStyleMetrics::~NativeStyleMetrics()
{
slint_native_style_metrics_deinit(this);
}
#endif // !defined(DOXYGEN)
namespace private_api {
// Code generated by Slint <= 0.1.5 uses this enum with VersionCheckHelper
enum class [[deprecated]] VersionCheck { Major = SLINT_VERSION_MAJOR, Minor = SLINT_VERSION_MINOR,
Patch = SLINT_VERSION_PATCH };
template<int Major, int Minor, int Patch>
struct VersionCheckHelper
{
};
}
inline void run_event_loop()
{
private_api::assert_main_thread();
cbindgen_private::slint_run_event_loop();
}
inline void quit_event_loop()
{
cbindgen_private::slint_quit_event_loop();
}
template<typename Functor>
void invoke_from_event_loop(Functor f)
{
cbindgen_private::slint_post_event(
[](void *data) { (*reinterpret_cast<Functor *>(data))(); }, new Functor(std::move(f)),
[](void *data) { delete reinterpret_cast<Functor *>(data); });
}
template<typename Functor,
typename = std::enable_if_t<!std::is_void_v<std::invoke_result_t<Functor>>>>
auto blocking_invoke_from_event_loop(Functor f) -> std::invoke_result_t<Functor>
{
std::optional<std::invoke_result_t<Functor>> result;
std::mutex mtx;
std::condition_variable cv;
invoke_from_event_loop([&] {
auto r = f();
std::unique_lock lock(mtx);
result = std::move(r);
cv.notify_one();
});
std::unique_lock lock(mtx);
cv.wait(lock, [&] { return result.has_value(); });
return std::move(*result);
}
template<typename Functor,
typename = std::enable_if_t<std::is_void_v<std::invoke_result_t<Functor>>>>
auto blocking_invoke_from_event_loop(Functor f) -> void
{
std::mutex mtx;
std::condition_variable cv;
bool ok = false;
invoke_from_event_loop([&] {
f();
std::unique_lock lock(mtx);
ok = true;
cv.notify_one();
});
std::unique_lock lock(mtx);
cv.wait(lock, [&] { return ok; });
}
} // namespace slint