Open ogoffart opened 3 years ago
The use of setter and getter like other property don't really make sense as one can't really set a reference to an object.
For my use-case, a getter (without a setter) would be sufficient. My main window has this code:
MainWindow := Window {
login := LoginScreen {
visible: root.selected-screen == 0;
}
main := MainScreen {
visible: root.selected-screen == 1;
}
}
and I would like to access properties and further inner containers in main
from Rust, e.g.
let menu_items = main.menubar.items;
As for the types, I think for this use-case it would be sufficient to export them with same base type that the root element has.
Is that really the best solution to the problem or is there a better way?
I could see CSS-style selectors filling this niche, although that still implies the export types being decided upon.
let menu_items = slint::select(&mainwindow, "#menuitems");
// or
let menu_items = slint::select(&mainwindow, "#main > #menubar > #items");
Now that we don't inline everything anymore, I wonder if components could be supported as property types:
export Button := TouchArea { ... }
export App := Window {
property <Button> button: b;
VerticalLayout {
b := Button {}
}
}
and then (in the example of Rust) we would generate a public wrapper for Button
that - similar to App
wraps around VRc
(except that it's VRcMapped
in that case). We would also need to find a way to be able to use slint::Weak
with this (or use a new type), but in principle the property would be a weak reference and exposed as such.
The application code could obtain it and selectively upgrade it.
At least we do have the building blocks for that now.
This is not a complete picture though, and the questions asked earlier ("is this really the best solution to the problem?") remain valid.
This keeps coming up and is closely related to the question how to attach native code more easily to sub-components of a bigger UI, without routing every single callback and property through the root.
Do I understand correctly that until this issue is solved, I can very well declare multiple windows, but I cannot access them from Rust? In any case, how can I declare and open two different windows?
What about generating new objects for all exported types?
Objects reimplemented by the user would provide a clear API separation
Internally, the impl could contain a pointer to a possibly user implemented version. Like this:
if(user_impl && user_impl->cb) [return] user_impl->cb()
export MyType := Rectangle {
callback cb;
}
On the user side:
auto myType = ..
auto ui = ...
ui->set_mytype(myType)
MyType could, possibly, be generated in the exact same way that Window does
Not sure how this would work for types used as delegates in repeaters... I guess the slint-defined version should have priority... somehow
I think this is basically what Global objects are: https://slint-ui.com/releases/0.3.1/docs/cpp/markdown/recipes/recipes.html#global-callbacks
Except that it would be "global" per object type, and not application wide. I chose main window as an example, but it would be the same for all exported types.
Is there progress on this issue? I am just starting out with slint, but even with a simple UI I immediately noticed how cumbersome it is to bind every subsubproperty in the root component for interactions with native code.
I am sure you already considered it, but what I intuitively think makes sense would be to access elements as nested structs from rust:
let ui = App::new();
let button = ui.get_tile().get_button();
let button_state = button.get_button_state();
In this example I would envision button_state
to also be of reference type like ui
itself.
The problem we're trying to solve here is to forward many properties from an inner component, to the root, so they can be set by the business logic. Currently the work around is to do something like that:
This is a lot of boiler plate, especially for callbacks. (See issue #111 for a callback forarding issue).
This can be a bit simplified by using use a global singleton to set all the properties in the singleton, and the page can read that singleton. Unfortunately, it is not yet possible to set property from singleton from native code (issue #96) so for now one still need boiler plate code to forward everything. And this only work if there is a single instance of that page.
Also we can pack all the property in a single sutructure. This remove some of the forwarding boilerplate, but is less efficient because we always need to read and write the whole struct. Also that does not work with callbacks
So is the solution to expose inner elements in the public api, for example using a
public
keywordBut we also need to somehow re-export from deeper hierarchy:
This raises several question:
What types are then generated in C++ and Rust for these element properties. The use of setter and getter like other property don't really make sense as one can't really set a reference to an object. What would the lifetime of the reference be? What properties are exposed, does that imply we can also export builtin elements (Image/ListView), and these needs to be in the public Rust / C++ API? (Maybe we can make it play nice with something like #191 which allow to change access.) Do we care about items in repeater?
Is that really the best solution to the problem or is there a better way? (For example, extend the Model API for smarter property based model)