Conceptual Clarification on Sharing Data with Tab Type and Tab Renderer #210
-
tl;dr: What's the "right way" to share data from my app struct between tabs? Hi, all. I'm having a little trouble grokking the "why" of the TabViewer and DockState. I'm making this thread to try and set out what my understanding of the tooling is in the hopes that perhaps others can either correct me or reference it for the "why". I've read through the documentation (which is much appreciated, btw) but I'm still a bit fuzzy on what the expectations are. Excerpting and paraphrasing simple.rs for future reference, in case it changes: struct MyApp {
// Driving data for the app state is in MyApp, but ExampleTabType also has information for rendering layout.
tree: DockState<ExampleTabType>,
}
struct ExampleTabType { /* Data for showing the tab, right? In the docs, this is String, but my data is more complicated. */ }
struct TabViewer {}
impl egui_dock::TabViewer for TabViewer {
type Tab = ExampleTabType;
fn title(&mut self, tab: &mut Self::Tab) -> egui::WidgetText { // tab is &mut ExampleTabType
(&*tab).into()
}
fn ui(&mut self, ui: &mut egui::Ui, tab: &mut Self::Tab) {
// I suppose I could say type Tab = MyApp, since I'd like to display data from my app?
// But then we get into some fights with borrow-checking since DockArea needs a mut ref and show needs a mut ref.
ui.label(format!("Content of {tab}"));
}
}
...
impl eframe::App for MyApp {
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
DockArea::new(&mut self.tree)
.style(Style::from_egui(ctx.style().as_ref()))
.show(ctx, &mut TabViewer {}); // Here's where the trickiness stems. &mut self.tree means I can't impl TabViewer for MyApp and pass &mut self since it's already borrowed by DockArea.
}
} It looks like ExampleTabType should own the data it wants to display, but if that happens to be shared between tabs (like if they're viewing the same model from different angles) then it makes sense to have it owned by the parent MyApp. Or I guess I could have ExampleTabType own the data? But then I'm not sure how I'd share the data between tabs unless I used a bunch of Arcs. Or ExampleTabType could be an enum with associated data, but this feels really messy. What's the "right way" of pushing data down from MyApp into ExampleTabType and then into TabViewer? |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 1 reply
-
The boring long answer is, you can do this any way you want! However that isn't very helpful and most likely not the answer you're looking for, so ill answer more opinionated like. As you've already mentioned you can't pass in |
Beta Was this translation helpful? Give feedback.
The boring long answer is, you can do this any way you want! However that isn't very helpful and most likely not the answer you're looking for, so ill answer more opinionated like.
As you've already mentioned you can't pass in
self
for tab viewer as part of it is already being borrowed in order to create theDockArea
(although i agree that would have been the best way to do it had it been possible), however what you can do is create another struct named something likeSharedData
in it's own field insideMyApp
, and instead give that to the tab viewer. Rust is smart enough to tell even though you're lending out two mutable references from the same underlying structure that they will never int…