Replies: 4 comments 6 replies
-
To be honest, I still don't quite understand how this is even done in plain GTK. As far as I can tell, they use We may also want to have a look at Personally, I'm still figuring out how to even structure my woab application – especially the state handling part – in non-trivial use cases. My current approach is to simply try things out and see how well they go. If one pattern emerges as a "winner" (for some situations), one may then ask how to encode it into a supporting library. |
Beta Was this translation helpful? Give feedback.
-
I'm pondering about how to store the state: 1. As a plain field in the actor#[derive(woab::stateful)]
#[stateful(state=state, widgets=widgets)]
struct MyActor {
state: MyState,
widgets: MyWidgets,
} This one is the most obvious but is has a flaw - the user must actively initiate a sync whenever they change the state. 2. As a wrapped field in the actor#[derive(woab::StateActor)]
#[stateful(state=state, widgets=widgets)]
struct MyActor {
state: woab::State<MyState>,
widgets: MyWidgets,
}
// Read the state:
self.do_something_with_the_state(self.state().field_1);
// Modify the state:
self.mutate_state(|state| {
state.field_2 = 12;
});
// or even (no sure how I like this option...):
self.state_mut().field_3 = "hi";
// `state_mut()` d'tor kicks in to sync the state 3. Inside its own actorstruct MyActor {
state: woab::StateActor<MyState, MyWidgets>,
widgets: MyWidgets,
} Here let field_5 = self.state.with(|state| {
state.field_4 = true;
state.field_5.to_owned()
}).await; There is some elegance here, but it greatly limits the usability and has a big overhead. 4. Like option 2, but with generated methods#[derive(woab::State)]
#[state(actor=MyActor, field=state)]
struct MyState {
#[state(describing how to connect it to the widget)]
field_6: f64,
}
struct MyActor {
state: woab::State<MyState>,
widgets: MyWidgets,
}
let field_6_value = self.state().field_6;
self.set_field_6(field_6_value + 2); I think this is my favorite, as it allows updating individual fields (all the other methods require updating all the fields at once) |
Beta Was this translation helpful? Give feedback.
-
5. Generate intermediate struct and use it manually#[derive(woab::WidgetsFromBuilder, woab::SyncData)]
struct MyWidgets {
#[sync_data(text: String)]
field_1: gtk::Entry,
#[sync_data(text: i64)]
field_2: gtk::Entry,
}
struct MyWidgetsData {
field_1: String,
field_2: i64,
} And then I could set it with: self.widgets.set_data(MyWidgetsData {
field_1: "Hello".to_owned(),
field_1: 123,
}); And get it with: let MyWidgetsData {
field_1,
field_2,
} = self.widgets.get_data(); Now, this may look like very little sugar over operating the widgets manually, but it has one big advantage - Rust's typechecker will verify that you are not neglecting any field. |
Beta Was this translation helpful? Give feedback.
-
I may have misjudged the requirements a bit. I was focused on my current specific usecase, where all the data widgets are input widgets with With this design, the same fields are used for both setting the widgets and getting the data from them. But in many scenarios this is not the case - some of these fields are labels or never-editable text entries, and there is no point in including them in the getter. This can be worked around by using |
Beta Was this translation helpful? Give feedback.
-
Many modern GUI frameworks are data-oriented - they render their widgets based on the same application state the business logic uses. They can do so because they implement the widgets themselves (or at least heavily wrap them), so WoAB - which allows direct usage of GTK components - can't do that.
But maybe instead WoAB can somehow assist in syncing the application data with the widgets?
This is a discussion instead of an issue because I don't really know how I want to do it yet. I'm also not sure it should go in the main WoAB crate - maybe it should go in a separate crate (
woab-model
or something like that?)Beta Was this translation helpful? Give feedback.
All reactions