1// Copyright © SixtyFPS GmbH <info@slint.dev>
2// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
3
4#pragma once
5
6#include "slint.h"
7
8#ifndef SLINT_FEATURE_INTERPRETER
9# warning "slint-interpreter.h API only available when SLINT_FEATURE_INTERPRETER is activated"
10#else
11
12# include "slint_interpreter_internal.h"
13
14# include <optional>
15
16# ifdef SLINT_FEATURE_BACKEND_QT
17class QWidget;
18# endif
19
20namespace slint::cbindgen_private {
21// This has to stay opaque, but VRc don't compile if it is just forward declared
22struct ErasedItemTreeBox : vtable::Dyn
23{
24 ~ErasedItemTreeBox() = delete;
25 ErasedItemTreeBox() = delete;
26 ErasedItemTreeBox(ErasedItemTreeBox &) = delete;
27};
28}
29
30/// The types in this namespace allow you to load a .slint file at runtime and show its UI.
31///
32/// You only need to use them if you do not want to use pre-compiled .slint code, which is
33/// the normal way to use Slint.
34///
35/// The entry point for this namespace is the \ref ComponentCompiler, which you can
36/// use to create \ref ComponentDefinition instances with the
37/// \ref ComponentCompiler::build_from_source() or \ref ComponentCompiler::build_from_path()
38/// functions.
39namespace slint::interpreter {
40
41class Value;
42
43/// This type represents a runtime instance of structure in `.slint`.
44///
45/// This can either be an instance of a name structure introduced
46/// with the `struct` keyword in the .slint file, or an anonymous struct
47/// written with the `{ key: value, }` notation.
48///
49/// It can be constructed with the range constructor or initializer lst,
50/// and converted into or from a Value with the Value constructor and
51/// Value::to_struct().
52struct Struct
53{
54public:
55 /// Constructs a new empty struct. You can add fields with set_field() and
56 /// read them with get_field().
57 Struct() { cbindgen_private::slint_interpreter_struct_new(&inner); }
58
59 /// Creates a new Struct as a copy from \a other. All fields are copied as well.
60 Struct(const Struct &other)
61 {
62 cbindgen_private::slint_interpreter_struct_clone(&other.inner, &inner);
63 }
64 /// Creates a new Struct by moving all fields from \a other into this struct.
65 Struct(Struct &&other)
66 {
67 inner = other.inner;
68 cbindgen_private::slint_interpreter_struct_new(&other.inner);
69 }
70 /// Assigns all the fields of \a other to this struct.
71 Struct &operator=(const Struct &other)
72 {
73 if (this == &other)
74 return *this;
75 cbindgen_private::slint_interpreter_struct_destructor(&inner);
76 slint_interpreter_struct_clone(&other.inner, &inner);
77 return *this;
78 }
79 /// Moves all the fields of \a other to this struct.
80 Struct &operator=(Struct &&other)
81 {
82 if (this == &other)
83 return *this;
84 cbindgen_private::slint_interpreter_struct_destructor(&inner);
85 inner = other.inner;
86 cbindgen_private::slint_interpreter_struct_new(&other.inner);
87 return *this;
88 }
89 /// Destroys this struct.
90 ~Struct() { cbindgen_private::slint_interpreter_struct_destructor(&inner); }
91
92 /// Creates a new struct with the fields of the std::initializer_list given by args.
93 inline Struct(std::initializer_list<std::pair<std::string_view, Value>> args);
94
95 /// Creates a new struct with the fields produced by the iterator \a it. \a it is
96 /// advanced until it equals \a end.
97 template<typename InputIterator
98// Doxygen doesn't understand this template wizardry
99# if !defined(DOXYGEN)
100 ,
101 typename std::enable_if_t<
102 std::is_convertible<decltype(std::get<0>(*std::declval<InputIterator>())),
103 std::string_view>::value
104 && std::is_convertible<decltype(std::get<1>(*std::declval<InputIterator>())),
105 Value>::value
106
107 > * = nullptr
108# endif
109 >
110 Struct(InputIterator it, InputIterator end) : Struct()
111 {
112 for (; it != end; ++it) {
113 auto [key, value] = *it;
114 set_field(name: key, value);
115 }
116 }
117
118 // FIXME: this probably miss a lot of iterator api
119 /// The Struct::iterator class implements the typical C++ iterator protocol and conveniently
120 /// provides access to the field names and values of a Struct. It is created by calling either
121 /// Struct::begin() or Struct::end().
122 ///
123 /// Make sure to compare the iterator to the iterator returned by Struct::end() before
124 /// de-referencing it. The value returned when de-referencing is a std::pair that holds a
125 /// std::string_view of the field name as well as a const reference of the value. Both
126 /// references become invalid when the iterator or the Struct is changed, so make sure to make
127 /// copies if you want to retain the name or value.
128 ///
129 /// Note that the order in which the iterator exposes the fields is not defined.
130 ///
131 /// If you're using C++ 17, you can use the convenience destructuring syntax to extract the name
132 /// and value in one go:
133 ///
134 /// ```
135 /// Struct stru = ...;
136 /// auto it = stru.begin();
137 /// ...
138 /// ++it; // advance iterator to the next field
139 /// ...
140 /// // Check iterator before dereferencing it
141 /// if (it != stru.end()) {
142 /// // Extract a view of the name and a const reference to the value in one go.
143 /// auto [field_name, field_value] = *it;
144 /// }
145 /// ```
146 struct iterator
147 {
148 /// A typedef for std::pair<std::string_view, const Value &> that's returned
149 /// when dereferencing the iterator.
150 using value_type = std::pair<std::string_view, const Value &>;
151
152 private:
153 cbindgen_private::StructIteratorOpaque inner;
154 Value *v = nullptr;
155 std::string_view k;
156 friend Struct;
157 explicit iterator(cbindgen_private::StructIteratorOpaque inner) : inner(inner) { next(); }
158 // construct a end iterator
159 iterator() = default;
160 inline void next();
161
162 public:
163 /// Destroys this field iterator.
164 inline ~iterator();
165 // FIXME I believe iterators are supposed to be copy constructible
166 iterator(const iterator &) = delete;
167 iterator &operator=(const iterator &) = delete;
168 /// Move-constructs a new iterator from \a other.
169 iterator(iterator &&other) = default;
170 /// Move-assigns the iterator \a other to this and returns a reference to this.
171 iterator &operator=(iterator &&other) = default;
172 /// The prefix ++ operator advances the iterator to the next entry and returns
173 /// a reference to this.
174 iterator &operator++()
175 {
176 if (v)
177 next();
178 return *this;
179 }
180 /// Dereferences the iterator to return a pair of the key and value.
181 value_type operator*() const { return { k, *v }; }
182 /// Returns true if \a a is pointing to the same entry as \a b; false otherwise.
183 friend bool operator==(const iterator &a, const iterator &b) { return a.v == b.v; }
184 /// Returns false if \a a is pointing to the same entry as \a b; true otherwise.
185 friend bool operator!=(const iterator &a, const iterator &b) { return a.v != b.v; }
186 };
187
188 /// Returns an iterator over the fields of the struct.
189 iterator begin() const
190 {
191 return iterator(cbindgen_private::slint_interpreter_struct_make_iter(&inner));
192 }
193 /// Returns an iterator that when compared with an iterator returned by begin() can be
194 /// used to detect when all fields have been visited.
195 iterator end() const { return iterator(); }
196
197 /// Returns the value of the field with the given \a name; Returns an std::optional without
198 /// value if the field does not exist.
199 inline std::optional<Value> get_field(std::string_view name) const;
200 /// Sets the value of the field with the given \a name to the specified \a value. If the field
201 /// does not exist yet, it is created; otherwise the existing field is updated to hold the new
202 /// value.
203 inline void set_field(std::string_view name, const Value &value);
204
205 /// \private
206 Struct(const slint::cbindgen_private::StructOpaque &other)
207 {
208 cbindgen_private::slint_interpreter_struct_clone(&other, &inner);
209 }
210
211private:
212 using StructOpaque = slint::cbindgen_private::StructOpaque;
213 StructOpaque inner;
214 friend class Value;
215};
216
217/// This is a dynamically typed value used in the Slint interpreter.
218/// It can hold a value of different types, and you should use the
219/// different overloaded constructors and the to_xxx() functions to access the
220//// value within.
221///
222/// It is also possible to query the type the value holds by calling the Value::type()
223/// function.
224///
225/// Note that models are only represented in one direction: You can create a slint::Model<Value>
226/// in C++, store it in a std::shared_ptr and construct Value from it. Then you can set it on a
227/// property in your .slint code that was declared to be either an array (`property <[sometype]>
228/// foo;`) or an object literal (`property <{foo: string, bar: int}> my_prop;`). Such properties are
229/// dynamic and accept models implemented in C++.
230///
231/// ```
232/// Value v(42.0); // Creates a value that holds a double with the value 42.
233///
234/// Value some_value = ...;
235/// // Check if the value has a string
236/// if (std::optional<slint::SharedString> string_value = some_value.to_string())
237/// do_something(*string_value); // Extract the string by de-referencing
238/// ```
239class Value
240{
241public:
242 /// Constructs a new value of type Value::Type::Void.
243 Value() : inner(cbindgen_private::slint_interpreter_value_new()) { }
244
245 /// Constructs a new value by copying \a other.
246 Value(const Value &other) : inner(slint_interpreter_value_clone(other.inner)) { }
247 /// Constructs a new value by moving \a other to this.
248 Value(Value &&other)
249 {
250 inner = other.inner;
251 other.inner = cbindgen_private::slint_interpreter_value_new();
252 }
253 /// Assigns the value \a other to this.
254 Value &operator=(const Value &other)
255 {
256 if (this == &other)
257 return *this;
258 cbindgen_private::slint_interpreter_value_destructor(inner);
259 inner = slint_interpreter_value_clone(other.inner);
260 return *this;
261 }
262 /// Moves the value \a other to this.
263 Value &operator=(Value &&other)
264 {
265 if (this == &other)
266 return *this;
267 cbindgen_private::slint_interpreter_value_destructor(inner);
268 inner = other.inner;
269 other.inner = cbindgen_private::slint_interpreter_value_new();
270 return *this;
271 }
272 /// Destroys the value.
273 ~Value() { cbindgen_private::slint_interpreter_value_destructor(inner); }
274
275 /// A convenience alias for the value type enum.
276 using Type = ValueType;
277
278 // optional<int> to_int() const;
279 // optional<float> to_float() const;
280 /// Returns a std::optional that contains a double if the type of this Value is
281 /// Type::Double, otherwise an empty optional is returned.
282 std::optional<double> to_number() const
283 {
284 if (auto *number = cbindgen_private::slint_interpreter_value_to_number(inner)) {
285 return *number;
286 } else {
287 return {};
288 }
289 }
290
291 /// Returns a std::optional that contains a string if the type of this Value is
292 /// Type::String, otherwise an empty optional is returned.
293 std::optional<slint::SharedString> to_string() const
294 {
295 if (auto *str = cbindgen_private::slint_interpreter_value_to_string(inner)) {
296 return *str;
297 } else {
298 return {};
299 }
300 }
301
302 /// Returns a std::optional that contains a bool if the type of this Value is
303 /// Type::Bool, otherwise an empty optional is returned.
304 std::optional<bool> to_bool() const
305 {
306 if (auto *b = cbindgen_private::slint_interpreter_value_to_bool(inner)) {
307 return *b;
308 } else {
309 return {};
310 }
311 }
312
313 /// Returns a std::optional that contains a vector of values if the type of this Value is
314 /// Type::Model, otherwise an empty optional is returned.
315 ///
316 /// The vector will be constructed by serializing all the elements of the model.
317 inline std::optional<slint::SharedVector<Value>> to_array() const;
318
319 /// Returns a std::optional that contains a brush if the type of this Value is
320 /// Type::Brush, otherwise an empty optional is returned.
321 std::optional<slint::Brush> to_brush() const
322 {
323 if (auto *brush = cbindgen_private::slint_interpreter_value_to_brush(inner)) {
324 return *brush;
325 } else {
326 return {};
327 }
328 }
329
330 /// Returns a std::optional that contains a Struct if the type of this Value is
331 /// Type::Struct, otherwise an empty optional is returned.
332 std::optional<Struct> to_struct() const
333 {
334 if (auto *opaque_struct = cbindgen_private::slint_interpreter_value_to_struct(inner)) {
335 return Struct(*opaque_struct);
336 } else {
337 return {};
338 }
339 }
340
341 /// Returns a std::optional that contains an Image if the type of this Value is
342 /// Type::Image, otherwise an empty optional is returned.
343 std::optional<Image> to_image() const
344 {
345 if (auto *img = cbindgen_private::slint_interpreter_value_to_image(inner)) {
346 return *reinterpret_cast<const Image *>(img);
347 } else {
348 return {};
349 }
350 }
351
352 // template<typename T> std::optional<T> get() const;
353
354 /// Constructs a new Value that holds the double \a value.
355 Value(double value) : inner(cbindgen_private::slint_interpreter_value_new_double(value)) { }
356 /// Constructs a new Value that holds the int \a value.
357 /// Internally this is stored as a double and Value::type() will return Value::Type::Number.
358 Value(int value) : Value(static_cast<double>(value)) { }
359 /// Constructs a new Value that holds the string \a str.
360 Value(const SharedString &str)
361 : inner(cbindgen_private::slint_interpreter_value_new_string(&str))
362 {
363 }
364 /// Constructs a new Value that holds the boolean \a b.
365 Value(bool b) : inner(cbindgen_private::slint_interpreter_value_new_bool(b)) { }
366 /// Constructs a new Value that holds the value vector \a v as a model.
367 inline Value(const SharedVector<Value> &v);
368 /// Constructs a new Value that holds the value model \a m.
369 Value(const std::shared_ptr<slint::Model<Value>> &m);
370 /// Constructs a new Value that holds the brush \a b.
371 Value(const slint::Brush &brush)
372 : inner(cbindgen_private::slint_interpreter_value_new_brush(&brush))
373 {
374 }
375 /// Constructs a new Value that holds the Struct \a struc.
376 Value(const Struct &struc)
377 : inner(cbindgen_private::slint_interpreter_value_new_struct(&struc.inner))
378 {
379 }
380
381 /// Constructs a new Value that holds the Image \a img.
382 Value(const Image &img) : inner(cbindgen_private::slint_interpreter_value_new_image(&img)) { }
383
384 /// Returns the type the variant holds.
385 Type type() const { return cbindgen_private::slint_interpreter_value_type(inner); }
386
387 /// Returns true if \a a and \a b hold values of the same type and the underlying vales are
388 /// equal.
389 friend bool operator==(const Value &a, const Value &b)
390 {
391 return cbindgen_private::slint_interpreter_value_eq(a.inner, b.inner);
392 }
393
394private:
395 inline Value(const void *) = delete; // Avoid that for example Value("foo") turns to Value(bool)
396 slint::cbindgen_private::Value *inner;
397 friend struct Struct;
398 friend class ComponentInstance;
399 // Internal constructor that takes ownership of the value
400 explicit Value(slint::cbindgen_private::Value *&&inner) : inner(inner) { }
401};
402
403inline Value::Value(const slint::SharedVector<Value> &array)
404 : inner(cbindgen_private::slint_interpreter_value_new_array_model(
405 reinterpret_cast<const slint::SharedVector<slint::cbindgen_private::Value *> *>(
406 &array)))
407{
408}
409
410inline std::optional<slint::SharedVector<Value>> Value::to_array() const
411{
412 slint::SharedVector<Value> array;
413 if (cbindgen_private::slint_interpreter_value_to_array(
414 &inner,
415 reinterpret_cast<slint::SharedVector<slint::cbindgen_private::Value *> *>(
416 &array))) {
417 return array;
418 } else {
419 return {};
420 }
421}
422inline Value::Value(const std::shared_ptr<slint::Model<Value>> &model)
423{
424 using cbindgen_private::ModelAdaptorVTable;
425 using vtable::VRef;
426 struct ModelWrapper : private_api::ModelChangeListener
427 {
428 std::shared_ptr<slint::Model<Value>> model;
429 cbindgen_private::ModelNotifyOpaque notify;
430 // This kind of mean that the rust code has ownership of "this" until the drop function is
431 // called
432 std::shared_ptr<ModelChangeListener> self;
433 ~ModelWrapper() { cbindgen_private::slint_interpreter_model_notify_destructor(&notify); }
434
435 void row_added(size_t index, size_t count) override
436 {
437 cbindgen_private::slint_interpreter_model_notify_row_added(&notify, index, count);
438 }
439 void row_changed(size_t index) override
440 {
441 cbindgen_private::slint_interpreter_model_notify_row_changed(&notify, index);
442 }
443 void row_removed(size_t index, size_t count) override
444 {
445 cbindgen_private::slint_interpreter_model_notify_row_removed(&notify, index, count);
446 }
447 void reset() override { cbindgen_private::slint_interpreter_model_notify_reset(&notify); }
448 };
449
450 auto wrapper = std::make_shared<ModelWrapper>();
451 wrapper->model = model;
452 wrapper->self = wrapper;
453 cbindgen_private::slint_interpreter_model_notify_new(&wrapper->notify);
454 model->attach_peer(wrapper);
455
456 auto row_count = [](VRef<ModelAdaptorVTable> self) -> uintptr_t {
457 return reinterpret_cast<ModelWrapper *>(self.instance)->model->row_count();
458 };
459 auto row_data = [](VRef<ModelAdaptorVTable> self,
460 uintptr_t row) -> slint::cbindgen_private::Value * {
461 std::optional<Value> v =
462 reinterpret_cast<ModelWrapper *>(self.instance)->model->row_data(int(row));
463 if (v.has_value()) {
464 slint::cbindgen_private::Value *rval = v->inner;
465 v->inner = cbindgen_private::slint_interpreter_value_new();
466 return rval;
467 } else {
468 return nullptr;
469 }
470 };
471 auto set_row_data = [](VRef<ModelAdaptorVTable> self, uintptr_t row,
472 slint::cbindgen_private::Value *value) {
473 Value v(std::move(value));
474 reinterpret_cast<ModelWrapper *>(self.instance)->model->set_row_data(int(row), v);
475 };
476 auto get_notify =
477 [](VRef<ModelAdaptorVTable> self) -> const cbindgen_private::ModelNotifyOpaque * {
478 return &reinterpret_cast<ModelWrapper *>(self.instance)->notify;
479 };
480 auto drop = [](vtable::VRefMut<ModelAdaptorVTable> self) {
481 reinterpret_cast<ModelWrapper *>(self.instance)->self = nullptr;
482 };
483
484 static const ModelAdaptorVTable vt { row_count, row_data, set_row_data, get_notify, drop };
485 inner = cbindgen_private::slint_interpreter_value_new_model(
486 reinterpret_cast<uint8_t *>(wrapper.get()), &vt);
487}
488
489inline Struct::Struct(std::initializer_list<std::pair<std::string_view, Value>> args)
490 : Struct(args.begin(), args.end())
491{
492}
493
494inline std::optional<Value> Struct::get_field(std::string_view name) const
495{
496 using namespace cbindgen_private;
497 cbindgen_private::Slice<uint8_t> name_view {
498 const_cast<unsigned char *>(reinterpret_cast<const unsigned char *>(name.data())),
499 name.size()
500 };
501 if (cbindgen_private::Value *field_val =
502 cbindgen_private::slint_interpreter_struct_get_field(&inner, name_view)) {
503 return Value(std::move(field_val));
504 } else {
505 return {};
506 }
507}
508inline void Struct::set_field(std::string_view name, const Value &value)
509{
510 cbindgen_private::Slice<uint8_t> name_view {
511 const_cast<unsigned char *>(reinterpret_cast<const unsigned char *>(name.data())),
512 name.size()
513 };
514 cbindgen_private::slint_interpreter_struct_set_field(&inner, name_view, value.inner);
515}
516
517inline void Struct::iterator::next()
518{
519 cbindgen_private::Slice<uint8_t> name_slice;
520
521 if (cbindgen_private::Value *nextval_inner =
522 cbindgen_private::slint_interpreter_struct_iterator_next(&inner, &name_slice)) {
523 k = std::string_view(reinterpret_cast<char *>(name_slice.ptr), name_slice.len);
524 if (!v)
525 v = new Value();
526 *v = Value(std::move(nextval_inner));
527 } else {
528 cbindgen_private::slint_interpreter_struct_iterator_destructor(&inner);
529 delete v;
530 v = nullptr;
531 }
532}
533
534inline Struct::iterator::~iterator()
535{
536 if (v) {
537 cbindgen_private::slint_interpreter_struct_iterator_destructor(&inner);
538 delete v;
539 }
540}
541
542class ComponentDefinition;
543
544/// The ComponentInstance represents a running instance of a component.
545///
546/// You can create an instance with the ComponentDefinition::create() function.
547///
548/// Properties and callback can be accessed using the associated functions.
549///
550/// An instance can be put on screen with the ComponentInstance::show() or the
551/// ComponentInstance::run()
552class ComponentInstance : vtable::Dyn
553{
554 ComponentInstance() = delete;
555 ComponentInstance(ComponentInstance &) = delete;
556 ComponentInstance &operator=(ComponentInstance &) = delete;
557 friend class ComponentDefinition;
558
559 // ComponentHandle<ComponentInstance> is in fact a VRc<ItemTreeVTable, ErasedItemTreeBox>
560 const cbindgen_private::ErasedItemTreeBox *inner() const
561 {
562 slint::private_api::assert_main_thread();
563 return reinterpret_cast<const cbindgen_private::ErasedItemTreeBox *>(this);
564 }
565
566public:
567 /// Marks the window of this component to be shown on the screen. This registers
568 /// the window with the windowing system. In order to react to events from the windowing system,
569 /// such as draw requests or mouse/touch input, it is still necessary to spin the event loop,
570 /// using slint::run_event_loop().
571 void show() const
572 {
573 cbindgen_private::slint_interpreter_component_instance_show(inner(), true);
574 }
575 /// Marks the window of this component to be hidden on the screen. This de-registers
576 /// the window from the windowing system and it will not receive any further events.
577 void hide() const
578 {
579 cbindgen_private::slint_interpreter_component_instance_show(inner(), false);
580 }
581 /// Returns the Window associated with this component. The window API can be used
582 /// to control different aspects of the integration into the windowing system,
583 /// such as the position on the screen.
584 const slint::Window &window()
585 {
586 const cbindgen_private::WindowAdapterRcOpaque *win_ptr = nullptr;
587 cbindgen_private::slint_interpreter_component_instance_window(inner(), &win_ptr);
588 return *reinterpret_cast<const slint::Window *>(win_ptr);
589 }
590 /// This is a convenience function that first calls show(), followed by
591 /// slint::run_event_loop() and hide().
592 void run() const
593 {
594 show();
595 slint::run_event_loop();
596 hide();
597 }
598# if defined(SLINT_FEATURE_BACKEND_QT) || defined(DOXYGEN)
599 /// Return a QWidget for this instance.
600 /// This function is only available if the qt graphical backend was compiled in, and
601 /// it may return nullptr if the Qt backend is not used at runtime.
602 QWidget *qwidget() const
603 {
604 const cbindgen_private::WindowAdapterRcOpaque *win_ptr = nullptr;
605 cbindgen_private::slint_interpreter_component_instance_window(inner(), &win_ptr);
606 auto wid = reinterpret_cast<QWidget *>(cbindgen_private::slint_qt_get_widget(
607 reinterpret_cast<const cbindgen_private::WindowAdapterRc *>(win_ptr)));
608 return wid;
609 }
610# endif
611
612 /// Set the value for a public property of this component
613 ///
614 /// For example, if the component has a `property <string> hello;`,
615 /// we can set this property
616 /// ```
617 /// instance->set_property("hello", slint::SharedString("world"));
618 /// ```
619 ///
620 /// Returns true if the property was correctly set. Returns false if the property
621 /// could not be set because it either do not exist (was not declared in .slint) or if
622 /// the value is not of the proper type for the property's type.
623 bool set_property(std::string_view name, const Value &value) const
624 {
625 using namespace cbindgen_private;
626 return slint_interpreter_component_instance_set_property(
627 inner(), slint::private_api::string_to_slice(str: name), value.inner);
628 }
629 /// Returns the value behind a property declared in .slint.
630 std::optional<Value> get_property(std::string_view name) const
631 {
632 using namespace cbindgen_private;
633 if (cbindgen_private::Value *prop_inner = slint_interpreter_component_instance_get_property(
634 inner(), slint::private_api::string_to_slice(name))) {
635 return Value(std::move(prop_inner));
636 } else {
637 return {};
638 }
639 }
640 /// Invoke the specified callback or function declared in .slint with the given arguments
641 ///
642 /// Example: imagine the .slint file contains the given callback declaration:
643 /// ```
644 /// callback foo(string, int) -> string;
645 /// ```
646 /// Then one can call it with this function
647 /// ```
648 /// slint::Value args[] = { SharedString("Hello"), 42. };
649 /// instance->invoke("foo", { args, 2 });
650 /// ```
651 ///
652 /// Returns an null optional if the callback don't exist or if the argument don't match
653 /// Otherwise return the returned value from the callback, which may be an empty Value if
654 /// the callback did not return a value.
655 std::optional<Value> invoke(std::string_view name, std::span<const Value> args) const
656 {
657 using namespace cbindgen_private;
658 Slice<Box<cbindgen_private::Value>> args_view {
659 const_cast<Box<cbindgen_private::Value> *>(
660 reinterpret_cast<const Box<cbindgen_private::Value> *>(args.data())),
661 args.size()
662 };
663 if (cbindgen_private::Value *rval_inner = slint_interpreter_component_instance_invoke(
664 inner(), slint::private_api::string_to_slice(name), args_view)) {
665 return Value(std::move(rval_inner));
666 } else {
667 return {};
668 }
669 }
670
671 /// Set a handler for the callback with the given name.
672 ///
673 /// A callback with that name must be defined in the document otherwise the function
674 /// returns false.
675 ///
676 /// The \a callback parameter is a functor which takes as argument a slice of Value
677 /// and must return a Value.
678 ///
679 /// Example: imagine the .slint file contains the given callback declaration:
680 /// ```
681 /// callback foo(string, int) -> string;
682 /// ```
683 /// Then one can set the callback handler with this function
684 /// ```
685 /// instance->set_callback("foo", [](auto args) {
686 /// std::cout << "foo(" << *args[0].to_string() << ", " << *args[1].to_number() << ")\n";
687 /// });
688 /// ```
689 ///
690 /// Note: Since the ComponentInstance holds the handler, the handler itself should not
691 /// capture a strong reference to the instance.
692 template<std::invocable<std::span<const Value>> F>
693 requires(std::is_convertible_v<std::invoke_result_t<F, std::span<const Value>>, Value>)
694 auto set_callback(std::string_view name, F callback) const -> bool
695 {
696 using namespace cbindgen_private;
697 auto actual_cb =
698 [](void *data,
699 cbindgen_private::Slice<cbindgen_private::Box<cbindgen_private::Value>> arg) {
700 std::span<const Value> args_view { reinterpret_cast<const Value *>(arg.ptr),
701 arg.len };
702 Value r = (*reinterpret_cast<F *>(data))(args_view);
703 auto inner = r.inner;
704 r.inner = cbindgen_private::slint_interpreter_value_new();
705 return inner;
706 };
707 return cbindgen_private::slint_interpreter_component_instance_set_callback(
708 inner(), slint::private_api::string_to_slice(name), actual_cb,
709 new F(std::move(callback)), [](void *data) { delete reinterpret_cast<F *>(data); });
710 }
711
712 /// Set the value for a property within an exported global singleton.
713 ///
714 /// For example, if the main file has an exported global `TheGlobal` with a
715 /// `property <int> hello`, we can set this property
716 /// ```
717 /// instance->set_global_property("TheGlobal", "hello", 42);
718 /// ```
719 ///
720 /// Returns true if the property was correctly set. Returns false if the property
721 /// could not be set because it either does not exist (was not declared in .slint) or if
722 /// the value is not of the correct type for the property's type.
723 ///
724 /// **Note:** Only globals that are exported or re-exported from the main .slint file will
725 /// be accessible
726 bool set_global_property(std::string_view global, std::string_view prop_name,
727 const Value &value) const
728 {
729 using namespace cbindgen_private;
730 return slint_interpreter_component_instance_set_global_property(
731 inner(), slint::private_api::string_to_slice(str: global),
732 slint::private_api::string_to_slice(str: prop_name), value.inner);
733 }
734 /// Returns the value behind a property in an exported global singleton.
735 std::optional<Value> get_global_property(std::string_view global,
736 std::string_view prop_name) const
737 {
738 using namespace cbindgen_private;
739 if (cbindgen_private::Value *rval_inner =
740 slint_interpreter_component_instance_get_global_property(
741 inner(), slint::private_api::string_to_slice(global),
742 slint::private_api::string_to_slice(prop_name))) {
743 return Value(std::move(rval_inner));
744 } else {
745 return {};
746 }
747 }
748
749 /// Like `set_callback()` but on a callback in the specified exported global singleton.
750 ///
751 /// Example: imagine the .slint file contains the given global:
752 /// ```slint,no-preview
753 /// export global Logic {
754 /// pure callback to_uppercase(string) -> string;
755 /// }
756 /// ```
757 /// Then you can set the callback handler
758 /// ```cpp
759 /// instance->set_global_callback("Logic", "to_uppercase", [](auto args) {
760 /// std::string arg1(*args[0].to_string());
761 /// std::transform(arg1.begin(), arg1.end(), arg1.begin(), toupper);
762 /// return SharedString(arg1);
763 /// })
764 /// ```
765 ///
766 /// **Note:** Only globals that are exported or re-exported from the main .slint file will
767 /// be accessible
768 template<std::invocable<std::span<const Value>> F>
769 bool set_global_callback(std::string_view global, std::string_view name, F callback) const
770 {
771 using namespace cbindgen_private;
772 auto actual_cb =
773 [](void *data,
774 cbindgen_private::Slice<cbindgen_private::Box<cbindgen_private::Value>> arg) {
775 std::span<const Value> args_view { reinterpret_cast<const Value *>(arg.ptr),
776 arg.len };
777 Value r = (*reinterpret_cast<F *>(data))(args_view);
778 auto inner = r.inner;
779 r.inner = cbindgen_private::slint_interpreter_value_new();
780 return inner;
781 };
782 return cbindgen_private::slint_interpreter_component_instance_set_global_callback(
783 inner(), slint::private_api::string_to_slice(global),
784 slint::private_api::string_to_slice(name), actual_cb, new F(std::move(callback)),
785 [](void *data) { delete reinterpret_cast<F *>(data); });
786 }
787
788 /// Invoke the specified callback or function declared in an exported global singleton
789 std::optional<Value> invoke_global(std::string_view global, std::string_view callable_name,
790 std::span<const Value> args) const
791 {
792 using namespace cbindgen_private;
793 Slice<cbindgen_private::Box<cbindgen_private::Value>> args_view {
794 const_cast<cbindgen_private::Box<cbindgen_private::Value> *>(
795 reinterpret_cast<const cbindgen_private::Box<cbindgen_private::Value> *>(
796 args.data())),
797 args.size()
798 };
799 if (cbindgen_private::Value *rval_inner =
800 slint_interpreter_component_instance_invoke_global(
801 inner(), slint::private_api::string_to_slice(global),
802 slint::private_api::string_to_slice(callable_name), args_view)) {
803 return Value(std::move(rval_inner));
804 } else {
805 return {};
806 }
807 }
808
809 /// Return the ComponentDefinition that was used to create this instance.
810 inline ComponentDefinition definition() const;
811};
812
813/// ComponentDefinition is a representation of a compiled component from .slint markup.
814///
815/// It can be constructed from a .slint file using the ComponentCompiler::build_from_path() or
816/// ComponentCompiler::build_from_source() functions. And then it can be instantiated with the
817/// create() function.
818///
819/// The ComponentDefinition acts as a factory to create new instances. When you've finished
820/// creating the instances it is safe to destroy the ComponentDefinition.
821class ComponentDefinition
822{
823 friend class ComponentCompiler;
824 friend class ComponentInstance;
825
826 using ComponentDefinitionOpaque = slint::cbindgen_private::ComponentDefinitionOpaque;
827 ComponentDefinitionOpaque inner;
828
829 ComponentDefinition() = delete;
830 // Internal constructor that takes ownership of the component definition
831 explicit ComponentDefinition(ComponentDefinitionOpaque &inner) : inner(inner) { }
832
833public:
834 /// Constructs a new ComponentDefinition as a copy of \a other.
835 ComponentDefinition(const ComponentDefinition &other)
836 {
837 slint_interpreter_component_definition_clone(&other.inner, &inner);
838 }
839 /// Assigns \a other to this ComponentDefinition.
840 ComponentDefinition &operator=(const ComponentDefinition &other)
841 {
842 using namespace slint::cbindgen_private;
843
844 if (this == &other)
845 return *this;
846
847 slint_interpreter_component_definition_destructor(&inner);
848 slint_interpreter_component_definition_clone(&other.inner, &inner);
849
850 return *this;
851 }
852 /// Destroys this ComponentDefinition.
853 ~ComponentDefinition() { slint_interpreter_component_definition_destructor(&inner); }
854 /// Creates a new instance of the component and returns a shared handle to it.
855 ComponentHandle<ComponentInstance> create() const
856 {
857 union CI {
858 cbindgen_private::ComponentInstance i;
859 ComponentHandle<ComponentInstance> result;
860 ~CI() { result.~ComponentHandle(); }
861 CI() { }
862 } u;
863 cbindgen_private::slint_interpreter_component_instance_create(&inner, &u.i);
864 return u.result;
865 }
866
867 /// Returns a vector of PropertyDescriptor instances that describe the list of
868 /// public properties that can be read and written using ComponentInstance::set_property and
869 /// ComponentInstance::get_property.
870 slint::SharedVector<PropertyDescriptor> properties() const
871 {
872 slint::SharedVector<PropertyDescriptor> props;
873 cbindgen_private::slint_interpreter_component_definition_properties(&inner, &props);
874 return props;
875 }
876
877 /// Returns a vector of strings that describe the list of public callbacks that can be invoked
878 /// using ComponentInstance::invoke and set using ComponentInstance::set_callback.
879 slint::SharedVector<slint::SharedString> callbacks() const
880 {
881 slint::SharedVector<slint::SharedString> callbacks;
882 cbindgen_private::slint_interpreter_component_definition_callbacks(&inner, &callbacks);
883 return callbacks;
884 }
885
886 /// Returns a vector of strings that describe the list of public functions that can be invoked
887 /// using ComponentInstance::invoke.
888 slint::SharedVector<slint::SharedString> functions() const
889 {
890 slint::SharedVector<slint::SharedString> functions;
891 cbindgen_private::slint_interpreter_component_definition_functions(&inner, &functions);
892 return functions;
893 }
894
895 /// Returns the name of this Component as written in the .slint file
896 slint::SharedString name() const
897 {
898 slint::SharedString name;
899 cbindgen_private::slint_interpreter_component_definition_name(&inner, &name);
900 return name;
901 }
902
903 /// Returns a vector of strings with the names of all exported global singletons.
904 slint::SharedVector<slint::SharedString> globals() const
905 {
906 slint::SharedVector<slint::SharedString> names;
907 cbindgen_private::slint_interpreter_component_definition_globals(&inner, &names);
908 return names;
909 }
910
911 /// Returns a vector of the property descriptors of the properties of the specified
912 /// publicly exported global singleton. An empty optional is returned if there exists no
913 /// exported global singleton under the specified name.
914 std::optional<slint::SharedVector<PropertyDescriptor>>
915 global_properties(std::string_view global_name) const
916 {
917 slint::SharedVector<PropertyDescriptor> properties;
918 if (cbindgen_private::slint_interpreter_component_definition_global_properties(
919 &inner, slint::private_api::string_to_slice(global_name), &properties)) {
920 return properties;
921 }
922 return {};
923 }
924
925 /// Returns a vector of the names of the callbacks of the specified publicly exported global
926 /// singleton. An empty optional is returned if there exists no exported global singleton
927 /// under the specified name.
928 std::optional<slint::SharedVector<slint::SharedString>>
929 global_callbacks(std::string_view global_name) const
930 {
931 slint::SharedVector<slint::SharedString> names;
932 if (cbindgen_private::slint_interpreter_component_definition_global_callbacks(
933 &inner, slint::private_api::string_to_slice(global_name), &names)) {
934 return names;
935 }
936 return {};
937 }
938
939 /// Returns a vector of the names of the functions of the specified publicly exported global
940 /// singleton. An empty optional is returned if there exists no exported global singleton
941 /// under the specified name.
942 std::optional<slint::SharedVector<slint::SharedString>>
943 global_functions(std::string_view global_name) const
944 {
945 slint::SharedVector<slint::SharedString> names;
946 if (cbindgen_private::slint_interpreter_component_definition_global_functions(
947 &inner, slint::private_api::string_to_slice(global_name), &names)) {
948 return names;
949 }
950 return {};
951 }
952};
953
954inline ComponentDefinition ComponentInstance::definition() const
955{
956 cbindgen_private::ComponentDefinitionOpaque result;
957 cbindgen_private::slint_interpreter_component_instance_component_definition(inner(), &result);
958 return ComponentDefinition(result);
959}
960
961/// ComponentCompiler is the entry point to the Slint interpreter that can be used
962/// to load .slint files or compile them on-the-fly from a string
963/// (using build_from_source()) or from a path (using build_from_source())
964class ComponentCompiler
965{
966 cbindgen_private::ComponentCompilerOpaque inner;
967
968 ComponentCompiler(ComponentCompiler &) = delete;
969 ComponentCompiler &operator=(ComponentCompiler &) = delete;
970
971public:
972 /// Constructs a new ComponentCompiler instance.
973 ComponentCompiler() { cbindgen_private::slint_interpreter_component_compiler_new(&inner); }
974
975 /// Destroys this ComponentCompiler.
976 ~ComponentCompiler()
977 {
978 cbindgen_private::slint_interpreter_component_compiler_destructor(&inner);
979 }
980
981 /// Sets the include paths used for looking up `.slint` imports to the specified vector of
982 /// paths.
983 void set_include_paths(const slint::SharedVector<slint::SharedString> &paths)
984 {
985 cbindgen_private::slint_interpreter_component_compiler_set_include_paths(&inner, &paths);
986 }
987
988 /// Sets the style to be used for widgets.
989 void set_style(std::string_view style)
990 {
991 cbindgen_private::slint_interpreter_component_compiler_set_style(
992 &inner, slint::private_api::string_to_slice(style));
993 }
994
995 /// Returns the widget style the compiler is currently using when compiling .slint files.
996 slint::SharedString style() const
997 {
998 slint::SharedString s;
999 cbindgen_private::slint_interpreter_component_compiler_get_style(&inner, &s);
1000 return s;
1001 }
1002
1003 /// Sets the domain used for translations.
1004 void set_translation_domain(std::string_view domain)
1005 {
1006 cbindgen_private::slint_interpreter_component_compiler_set_translation_domain(
1007 &inner, slint::private_api::string_to_slice(domain));
1008 }
1009
1010 /// Returns the include paths the component compiler is currently configured with.
1011 slint::SharedVector<slint::SharedString> include_paths() const
1012 {
1013 slint::SharedVector<slint::SharedString> paths;
1014 cbindgen_private::slint_interpreter_component_compiler_get_include_paths(&inner, &paths);
1015 return paths;
1016 }
1017
1018 /// Returns the diagnostics that were produced in the last call to build_from_path() or
1019 /// build_from_source().
1020 slint::SharedVector<Diagnostic> diagnostics() const
1021 {
1022 slint::SharedVector<Diagnostic> result;
1023 cbindgen_private::slint_interpreter_component_compiler_get_diagnostics(&inner, &result);
1024 return result;
1025 }
1026
1027 /// Compile a .slint file into a ComponentDefinition
1028 ///
1029 /// Returns the compiled `ComponentDefinition` if there were no errors.
1030 ///
1031 /// Any diagnostics produced during the compilation, such as warnings or errors, are collected
1032 /// in this ComponentCompiler and can be retrieved after the call using the diagnostics()
1033 /// function.
1034 ///
1035 /// Diagnostics from previous calls are cleared when calling this function.
1036 std::optional<ComponentDefinition> build_from_source(std::string_view source_code,
1037 std::string_view path)
1038 {
1039 cbindgen_private::ComponentDefinitionOpaque result;
1040 if (cbindgen_private::slint_interpreter_component_compiler_build_from_source(
1041 &inner, slint::private_api::string_to_slice(source_code),
1042 slint::private_api::string_to_slice(path), &result)) {
1043
1044 return ComponentDefinition(result);
1045 } else {
1046 return {};
1047 }
1048 }
1049
1050 /// Compile some .slint code into a ComponentDefinition
1051 ///
1052 /// The `path` argument will be used for diagnostics and to compute relative
1053 /// paths while importing.
1054 ///
1055 /// Any diagnostics produced during the compilation, such as warnings or errors, are collected
1056 /// in this ComponentCompiler and can be retrieved after the call using the
1057 /// Self::diagnostics() function.
1058 ///
1059 /// Diagnostics from previous calls are cleared when calling this function.
1060 std::optional<ComponentDefinition> build_from_path(std::string_view path)
1061 {
1062 cbindgen_private::ComponentDefinitionOpaque result;
1063 if (cbindgen_private::slint_interpreter_component_compiler_build_from_path(
1064 &inner, slint::private_api::string_to_slice(path), &result)) {
1065
1066 return ComponentDefinition(result);
1067 } else {
1068 return {};
1069 }
1070 }
1071};
1072}
1073
1074namespace slint::private_api::testing {
1075/// Send a key events to the given component instance
1076inline void send_keyboard_string_sequence(const slint::interpreter::ComponentInstance *component,
1077 const slint::SharedString &str)
1078{
1079 const cbindgen_private::WindowAdapterRcOpaque *win_ptr = nullptr;
1080 cbindgen_private::slint_interpreter_component_instance_window(
1081 reinterpret_cast<const cbindgen_private::ErasedItemTreeBox *>(component), &win_ptr);
1082 cbindgen_private::send_keyboard_string_sequence(
1083 sequence: &str, window_adapter: reinterpret_cast<const cbindgen_private::WindowAdapterRc *>(win_ptr));
1084}
1085}
1086
1087#endif
1088

source code of slint/api/cpp/include/slint-interpreter.h