dock: Refactor Panel trait to has &mut self and &mut Context<Self>. (#1716)

Continue #1712, #1713

## Description

Also change the `Panel` trait to has `&mut self` and `&mut
Context<Self>`.

## Break Changes

The methods `title`, `title_prefix`, `set_zoomed`, `set_active`,
`dropdown_menu`, `toolbar_buttons`, `on_added_to`, `on_removed` has
changed `&self` to `&mut self`, and `cx: &App` to `cx: &mut
Context<Self>`.

```diff
- fn title(&self, window: &Window, cx: &App) -> AnyElement
+ fn title(&mut self, window: &Window, cx: &mut Context<Self>) -> AnyElement
```
This commit is contained in:
Jason Lee 2025-12-01 17:57:18 +08:00 committed by GitHub
parent c0f801dd8c
commit 4ded78ed30
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 106 additions and 113 deletions

View file

@ -94,11 +94,11 @@ impl Panel for ContainerPanel {
"ContainerPanel" "ContainerPanel"
} }
fn title(&self, window: &Window, cx: &App) -> AnyElement { fn title(&mut self, window: &Window, cx: &mut Context<Self>) -> AnyElement {
self.panel.title(window, cx) self.panel.title(window, cx)
} }
fn title_suffix(&self, _: &mut Window, cx: &mut App) -> Option<AnyElement> { fn title_suffix(&mut self, _: &mut Window, cx: &mut Context<Self>) -> Option<AnyElement> {
Some( Some(
div() div()
.w_24() .w_24()

View file

@ -692,7 +692,7 @@ impl Panel for StoryContainer {
"StoryContainer" "StoryContainer"
} }
fn title(&self, _window: &Window, _cx: &App) -> AnyElement { fn title(&mut self, _window: &Window, _cx: &mut Context<Self>) -> AnyElement {
self.name.clone().into_any_element() self.name.clone().into_any_element()
} }
@ -722,11 +722,11 @@ impl Panel for StoryContainer {
.contains(&self.name) .contains(&self.name)
} }
fn set_zoomed(&mut self, zoomed: bool, _window: &mut Window, _cx: &mut App) { fn set_zoomed(&mut self, zoomed: bool, _window: &mut Window, _cx: &mut Context<Self>) {
println!("panel: {} zoomed: {}", self.name, zoomed); println!("panel: {} zoomed: {}", self.name, zoomed);
} }
fn set_active(&mut self, active: bool, _window: &mut Window, cx: &mut App) { fn set_active(&mut self, active: bool, _window: &mut Window, cx: &mut Context<Self>) {
println!("panel: {} active: {}", self.name, active); println!("panel: {} active: {}", self.name, active);
if let Some(on_active) = self.on_active { if let Some(on_active) = self.on_active {
if let Some(story) = self.story.clone() { if let Some(story) = self.story.clone() {
@ -735,11 +735,20 @@ impl Panel for StoryContainer {
} }
} }
fn dropdown_menu(&self, menu: PopupMenu, _window: &Window, _cx: &App) -> PopupMenu { fn dropdown_menu(
&mut self,
menu: PopupMenu,
_window: &mut Window,
_cx: &mut Context<Self>,
) -> PopupMenu {
menu.menu("Info", Box::new(ShowPanelInfo)) menu.menu("Info", Box::new(ShowPanelInfo))
} }
fn toolbar_buttons(&self, _window: &mut Window, _cx: &mut App) -> Option<Vec<Button>> { fn toolbar_buttons(
&mut self,
_window: &mut Window,
_cx: &mut Context<Self>,
) -> Option<Vec<Button>> {
Some(vec![ Some(vec![
Button::new("info") Button::new("info")
.icon(IconName::Info) .icon(IconName::Info)

View file

@ -1,12 +1,10 @@
use std::{collections::HashMap, sync::Arc};
use crate::{button::Button, dock::TabPanel, menu::PopupMenu}; use crate::{button::Button, dock::TabPanel, menu::PopupMenu};
use gpui::{ use gpui::{
AnyElement, AnyView, App, AppContext as _, Entity, EntityId, EventEmitter, FocusHandle, AnyElement, AnyView, App, AppContext as _, Context, Entity, EntityId, EventEmitter,
Focusable, Global, Hsla, IntoElement, Render, SharedString, WeakEntity, Window, FocusHandle, Focusable, Global, Hsla, IntoElement, Render, SharedString, WeakEntity, Window,
}; };
use rust_i18n::t; use rust_i18n::t;
use std::{collections::HashMap, sync::Arc};
use super::{DockArea, PanelInfo, PanelState, invalid_panel::InvalidPanel}; use super::{DockArea, PanelInfo, PanelState, invalid_panel::InvalidPanel};
@ -68,7 +66,7 @@ pub trait Panel: EventEmitter<PanelEvent> + Render + Focusable {
} }
/// The title of the panel /// The title of the panel
fn title(&self, window: &Window, cx: &App) -> AnyElement { fn title(&mut self, window: &Window, cx: &mut Context<Self>) -> AnyElement {
SharedString::from(t!("Dock.Unnamed")).into_any_element() SharedString::from(t!("Dock.Unnamed")).into_any_element()
} }
@ -80,7 +78,7 @@ pub trait Panel: EventEmitter<PanelEvent> + Render + Focusable {
/// The suffix of the panel title, default is `None`. /// The suffix of the panel title, default is `None`.
/// ///
/// This is used to add a suffix element to the panel title. /// This is used to add a suffix element to the panel title.
fn title_suffix(&self, window: &mut Window, cx: &mut App) -> Option<AnyElement> { fn title_suffix(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<AnyElement> {
None None
} }
@ -110,28 +108,43 @@ pub trait Panel: EventEmitter<PanelEvent> + Render + Focusable {
/// This method will be called when the panel is active or inactive. /// This method will be called when the panel is active or inactive.
/// ///
/// The last_active_panel and current_active_panel will be touched when the panel is active. /// The last_active_panel and current_active_panel will be touched when the panel is active.
fn set_active(&mut self, active: bool, window: &mut Window, cx: &mut App) {} fn set_active(&mut self, active: bool, window: &mut Window, cx: &mut Context<Self>) {}
/// Set zoomed state of the panel. /// Set zoomed state of the panel.
/// ///
/// This method will be called when the panel is zoomed or unzoomed. /// This method will be called when the panel is zoomed or unzoomed.
/// ///
/// Only current Panel will touch this method. /// Only current Panel will touch this method.
fn set_zoomed(&mut self, zoomed: bool, window: &mut Window, cx: &mut App) {} fn set_zoomed(&mut self, zoomed: bool, window: &mut Window, cx: &mut Context<Self>) {}
/// When this Panel is added to a TabPanel, this will be called. /// When this Panel is added to a TabPanel, this will be called.
fn on_added_to(&mut self, tab_panel: WeakEntity<TabPanel>, window: &mut Window, cx: &mut App) {} fn on_added_to(
&mut self,
tab_panel: WeakEntity<TabPanel>,
window: &mut Window,
cx: &mut Context<Self>,
) {
}
/// When this Panel is removed from a TabPanel, this will be called. /// When this Panel is removed from a TabPanel, this will be called.
fn on_removed(&mut self, window: &mut Window, cx: &mut App) {} fn on_removed(&mut self, window: &mut Window, cx: &mut Context<Self>) {}
/// The addition dropdown menu of the panel, default is `None`. /// The addition dropdown menu of the panel, default is `None`.
fn dropdown_menu(&self, this: PopupMenu, window: &Window, cx: &App) -> PopupMenu { fn dropdown_menu(
&mut self,
this: PopupMenu,
window: &mut Window,
cx: &mut Context<Self>,
) -> PopupMenu {
this this
} }
/// The addition toolbar buttons of the panel used to show in the right of the title bar, default is `None`. /// The addition toolbar buttons of the panel used to show in the right of the title bar, default is `None`.
fn toolbar_buttons(&self, window: &mut Window, cx: &mut App) -> Option<Vec<Button>> { fn toolbar_buttons(
&mut self,
window: &mut Window,
cx: &mut Context<Self>,
) -> Option<Vec<Button>> {
None None
} }
@ -152,7 +165,7 @@ pub trait PanelView: 'static + Send + Sync {
fn panel_name(&self, cx: &App) -> &'static str; fn panel_name(&self, cx: &App) -> &'static str;
fn panel_id(&self, cx: &App) -> EntityId; fn panel_id(&self, cx: &App) -> EntityId;
fn tab_name(&self, cx: &App) -> Option<SharedString>; fn tab_name(&self, cx: &App) -> Option<SharedString>;
fn title(&self, window: &Window, cx: &App) -> AnyElement; fn title(&self, window: &Window, cx: &mut App) -> AnyElement;
fn title_suffix(&self, window: &mut Window, cx: &mut App) -> Option<AnyElement>; fn title_suffix(&self, window: &mut Window, cx: &mut App) -> Option<AnyElement>;
fn title_style(&self, cx: &App) -> Option<TitleStyle>; fn title_style(&self, cx: &App) -> Option<TitleStyle>;
fn closable(&self, cx: &App) -> bool; fn closable(&self, cx: &App) -> bool;
@ -162,7 +175,7 @@ pub trait PanelView: 'static + Send + Sync {
fn set_zoomed(&self, zoomed: bool, window: &mut Window, cx: &mut App); fn set_zoomed(&self, zoomed: bool, window: &mut Window, cx: &mut App);
fn on_added_to(&self, tab_panel: WeakEntity<TabPanel>, window: &mut Window, cx: &mut App); fn on_added_to(&self, tab_panel: WeakEntity<TabPanel>, window: &mut Window, cx: &mut App);
fn on_removed(&self, window: &mut Window, cx: &mut App); fn on_removed(&self, window: &mut Window, cx: &mut App);
fn dropdown_menu(&self, menu: PopupMenu, window: &Window, cx: &App) -> PopupMenu; fn dropdown_menu(&self, menu: PopupMenu, window: &mut Window, cx: &mut App) -> PopupMenu;
fn toolbar_buttons(&self, window: &mut Window, cx: &mut App) -> Option<Vec<Button>>; fn toolbar_buttons(&self, window: &mut Window, cx: &mut App) -> Option<Vec<Button>>;
fn view(&self) -> AnyView; fn view(&self) -> AnyView;
fn focus_handle(&self, cx: &App) -> FocusHandle; fn focus_handle(&self, cx: &App) -> FocusHandle;
@ -183,8 +196,8 @@ impl<T: Panel> PanelView for Entity<T> {
self.read(cx).tab_name(cx) self.read(cx).tab_name(cx)
} }
fn title(&self, window: &Window, cx: &App) -> AnyElement { fn title(&self, window: &Window, cx: &mut App) -> AnyElement {
self.read(cx).title(window, cx) self.update(cx, |this, cx| this.title(window, cx))
} }
fn title_suffix(&self, window: &mut Window, cx: &mut App) -> Option<AnyElement> { fn title_suffix(&self, window: &mut Window, cx: &mut App) -> Option<AnyElement> {
@ -227,8 +240,8 @@ impl<T: Panel> PanelView for Entity<T> {
self.update(cx, |this, cx| this.on_removed(window, cx)); self.update(cx, |this, cx| this.on_removed(window, cx));
} }
fn dropdown_menu(&self, menu: PopupMenu, window: &Window, cx: &App) -> PopupMenu { fn dropdown_menu(&self, menu: PopupMenu, window: &mut Window, cx: &mut App) -> PopupMenu {
self.read(cx).dropdown_menu(menu, window, cx) self.update(cx, |this, cx| this.dropdown_menu(menu, window, cx))
} }
fn toolbar_buttons(&self, window: &mut Window, cx: &mut App) -> Option<Vec<Button>> { fn toolbar_buttons(&self, window: &mut Window, cx: &mut App) -> Option<Vec<Button>> {

View file

@ -1,13 +1,13 @@
use std::sync::Arc; use std::sync::Arc;
use crate::{ use crate::{
ActiveTheme, AxisExt as _, Placement,
dock::PanelInfo, dock::PanelInfo,
h_flex, h_flex,
resizable::{ resizable::{
resizable_panel, ResizablePanelEvent, ResizablePanelGroup, ResizablePanelState, PANEL_MIN_SIZE, ResizablePanelEvent, ResizablePanelGroup, ResizablePanelState,
ResizableState, PANEL_MIN_SIZE, ResizableState, resizable_panel,
}, },
ActiveTheme, AxisExt as _, Placement,
}; };
use super::{DockArea, Panel, PanelEvent, PanelState, PanelView, TabPanel}; use super::{DockArea, Panel, PanelEvent, PanelState, PanelView, TabPanel};
@ -32,10 +32,10 @@ impl Panel for StackPanel {
"StackPanel" "StackPanel"
} }
fn title(&self, _window: &gpui::Window, _cx: &gpui::App) -> gpui::AnyElement { fn title(&mut self, _window: &gpui::Window, _cx: &mut Context<Self>) -> gpui::AnyElement {
"StackPanel".into_any_element() "StackPanel".into_any_element()
} }
fn set_active(&mut self, active: bool, window: &mut Window, cx: &mut App) { fn set_active(&mut self, active: bool, window: &mut Window, cx: &mut Context<Self>) {
for panel in &self.panels { for panel in &self.panels {
panel.set_active(active, window, cx); panel.set_active(active, window, cx);
} }

View file

@ -91,7 +91,7 @@ impl Panel for TabPanel {
"TabPanel" "TabPanel"
} }
fn title(&self, window: &Window, cx: &App) -> gpui::AnyElement { fn title(&mut self, window: &Window, cx: &mut Context<Self>) -> gpui::AnyElement {
self.active_panel(cx) self.active_panel(cx)
.map(|panel| panel.title(window, cx)) .map(|panel| panel.title(window, cx))
.unwrap_or("Empty Tab".into_any_element()) .unwrap_or("Empty Tab".into_any_element())
@ -121,7 +121,12 @@ impl Panel for TabPanel {
self.visible_panels(cx).next().is_some() self.visible_panels(cx).next().is_some()
} }
fn dropdown_menu(&self, menu: PopupMenu, window: &Window, cx: &App) -> PopupMenu { fn dropdown_menu(
&mut self,
menu: PopupMenu,
window: &mut Window,
cx: &mut Context<Self>,
) -> PopupMenu {
if let Some(panel) = self.active_panel(cx) { if let Some(panel) = self.active_panel(cx) {
panel.dropdown_menu(menu, window, cx) panel.dropdown_menu(menu, window, cx)
} else { } else {
@ -129,7 +134,11 @@ impl Panel for TabPanel {
} }
} }
fn toolbar_buttons(&self, window: &mut Window, cx: &mut App) -> Option<Vec<Button>> { fn toolbar_buttons(
&mut self,
window: &mut Window,
cx: &mut Context<Self>,
) -> Option<Vec<Button>> {
self.active_panel(cx) self.active_panel(cx)
.and_then(|panel| panel.toolbar_buttons(window, cx)) .and_then(|panel| panel.toolbar_buttons(window, cx))
} }
@ -422,7 +431,7 @@ impl TabPanel {
} }
fn render_toolbar( fn render_toolbar(
&self, &mut self,
state: &TabState, state: &TabState,
window: &mut Window, window: &mut Window,
cx: &mut Context<Self>, cx: &mut Context<Self>,
@ -481,23 +490,24 @@ impl TabPanel {
let zoomable = state.zoomable.map_or(false, |v| v.menu_visible()); let zoomable = state.zoomable.map_or(false, |v| v.menu_visible());
let closable = state.closable; let closable = state.closable;
move |this, window, cx| { move |menu, window, cx| {
view.read(cx) view.update(cx, |this, cx| {
.dropdown_menu(this, window, cx) this.dropdown_menu(menu, window, cx)
.separator() .separator()
.menu_with_disabled( .menu_with_disabled(
if zoomed { if zoomed {
t!("Dock.Zoom Out") t!("Dock.Zoom Out")
} else { } else {
t!("Dock.Zoom In") t!("Dock.Zoom In")
}, },
Box::new(ToggleZoom), Box::new(ToggleZoom),
!zoomable, !zoomable,
) )
.when(closable, |this| { .when(closable, |this| {
this.separator() this.separator()
.menu(t!("Dock.Close"), Box::new(ClosePanel)) .menu(t!("Dock.Close"), Box::new(ClosePanel))
}) })
})
} }
}) })
.anchor(Corner::TopRight), .anchor(Corner::TopRight),
@ -591,7 +601,7 @@ impl TabPanel {
} }
fn render_title_bar( fn render_title_bar(
&self, &mut self,
state: &TabState, state: &TabState,
window: &mut Window, window: &mut Window,
cx: &mut Context<Self>, cx: &mut Context<Self>,

View file

@ -148,7 +148,7 @@ impl Panel for Tiles {
"Tiles" "Tiles"
} }
fn title(&self, _window: &Window, _cx: &App) -> AnyElement { fn title(&mut self, _window: &Window, _cx: &mut Context<Self>) -> AnyElement {
"Tiles".into_any_element() "Tiles".into_any_element()
} }

View file

@ -34,10 +34,10 @@ impl ListDelegate for MyListDelegate {
} }
fn render_item( fn render_item(
&self, &mut self,
ix: IndexPath, ix: IndexPath,
_window: &mut Window, _window: &mut Window,
_cx: &mut App, _cx: &mut Context<TableState<Self>>,
) -> Option<Self::Item> { ) -> Option<Self::Item> {
self.items.get(ix.row).map(|item| { self.items.get(ix.row).map(|item| {
ListItem::new(ix) ListItem::new(ix)
@ -93,10 +93,10 @@ impl ListDelegate for MyListDelegate {
} }
fn render_section_header( fn render_section_header(
&self, &mut self,
section: usize, section: usize,
_window: &mut Window, _window: &mut Window,
cx: &mut App, cx: &mut Context<TableState<Self>>,
) -> Option<impl IntoElement> { ) -> Option<impl IntoElement> {
let title = match section { let title = match section {
0 => "Section 1", 0 => "Section 1",
@ -118,10 +118,10 @@ impl ListDelegate for MyListDelegate {
} }
fn render_section_footer( fn render_section_footer(
&self, &mut self,
section: usize, section: usize,
_window: &mut Window, _window: &mut Window,
cx: &mut App, cx: &mut Context<TableState<Self>>,
) -> Option<impl IntoElement> { ) -> Option<impl IntoElement> {
Some( Some(
div() div()
@ -139,10 +139,10 @@ impl ListDelegate for MyListDelegate {
```rust ```rust
fn render_item( fn render_item(
&self, &mut self,
ix: IndexPath, ix: IndexPath,
_window: &mut Window, _window: &mut Window,
cx: &mut App, cx: &mut Context<TableState<Self>>,
) -> Option<Self::Item> { ) -> Option<Self::Item> {
self.items.get(ix.row).map(|item| { self.items.get(ix.row).map(|item| {
ListItem::new(ix) ListItem::new(ix)
@ -205,9 +205,9 @@ impl ListDelegate for MyListDelegate {
} }
fn render_loading( fn render_loading(
&self, &mut self,
_window: &mut Window, _window: &mut Window,
_cx: &mut App, _cx: &mut Context<TableState<Self>>,
) -> impl IntoElement { ) -> impl IntoElement {
// Custom loading view // Custom loading view
v_flex() v_flex()
@ -305,7 +305,7 @@ ListSeparatorItem::new()
```rust ```rust
impl ListDelegate for MyListDelegate { impl ListDelegate for MyListDelegate {
fn render_empty(&self, _window: &mut Window, cx: &mut App) -> impl IntoElement { fn render_empty(&mut self, _window: &mut Window, cx: &mut Context<TableState<Self>>) -> impl IntoElement {
v_flex() v_flex()
.size_full() .size_full()
.justify_center() .justify_center()
@ -380,7 +380,7 @@ struct FileInfo {
impl ListDelegate for FileBrowserDelegate { impl ListDelegate for FileBrowserDelegate {
type Item = ListItem; type Item = ListItem;
fn render_item(&self, ix: IndexPath, window: &mut Window, cx: &mut App) -> Option<Self::Item> { fn render_item(&mut self, ix: IndexPath, window: &mut Window, cx: &mut Context<TableState<Self>>) -> Option<Self::Item> {
self.files.get(ix.row).map(|file| { self.files.get(ix.row).map(|file| {
let icon = if file.is_directory { let icon = if file.is_directory {
IconName::Folder IconName::Folder
@ -430,7 +430,7 @@ impl ListDelegate for ContactListDelegate {
self.contacts_by_letter.len() self.contacts_by_letter.len()
} }
fn render_section_header(&self, section: usize, _window: &mut Window, cx: &mut App) -> Option<impl IntoElement> { fn render_section_header(&mut self, section: usize, _window: &mut Window, cx: &mut Context<TableState<Self>>) -> Option<impl IntoElement> {
let letter = self.contacts_by_letter.keys().nth(section)?; let letter = self.contacts_by_letter.keys().nth(section)?;
Some( Some(
@ -450,11 +450,3 @@ impl ListDelegate for ContactListDelegate {
} }
} }
``` ```
## Performance
- **Virtualization**: Only renders visible items for large datasets
- **Efficient Updates**: Optimized re-rendering with proper change detection
- **Memory Management**: Automatic cleanup of off-screen items
- **Smooth Scrolling**: Hardware-accelerated scrolling with momentum
- **Lazy Loading**: Built-in support for infinite scrolling and pagination

View file

@ -66,7 +66,7 @@ impl TableDelegate for MyTableDelegate {
&self.columns[col_ix] &self.columns[col_ix]
} }
fn render_td(&self, row_ix: usize, col_ix: usize, _: &mut Window, _: &mut App) -> impl IntoElement { fn render_td(&mut self, row_ix: usize, col_ix: usize, _: &mut Window, _: &mut Context<TableState<Self>>) -> impl IntoElement {
let row = &self.data[row_ix]; let row = &self.data[row_ix];
let col = &self.columns[col_ix]; let col = &self.columns[col_ix];
@ -143,7 +143,7 @@ impl TableDelegate for LargeDataDelegate {
} }
// Only visible rows are rendered // Only visible rows are rendered
fn render_td(&self, row_ix: usize, col_ix: usize, _: &mut Window, _: &mut Context<TableState<Self>>) -> impl IntoElement { fn render_td(&mut self, row_ix: usize, col_ix: usize, _: &mut Window, _: &mut Context<TableState<Self>>) -> impl IntoElement {
// This is only called for visible rows // This is only called for visible rows
// Efficiently render cell content // Efficiently render cell content
let row = &self.data[row_ix]; let row = &self.data[row_ix];
@ -191,26 +191,12 @@ impl TableDelegate for MyTableDelegate {
} }
``` ```
### Row Selection ### ContextMenu
Handle row selection and interaction:
```rust ```rust
impl TableDelegate for MyTableDelegate { impl TableDelegate for MyTableDelegate {
fn render_tr(&self, row_ix: usize, _: &mut Window, cx: &mut App) -> Stateful<Div> {
div()
.id(row_ix)
.on_click(move |ev, _, _| {
if ev.modifiers().secondary() {
println!("Right-clicked row {}", row_ix);
} else {
println!("Selected row {}", row_ix);
}
})
}
// Context menu for right-click // Context menu for right-click
fn context_menu(&self, row_ix: usize, menu: PopupMenu, _: &mut Window, _: &mut App) -> PopupMenu { fn context_menu(&mut self, row_ix: usize, menu: PopupMenu, _: &mut Window, _: &mut Context<TableState<Self>>) -> PopupMenu {
let row = &self.data[row_ix]; let row = &self.data[row_ix];
menu.menu(format!("Edit {}", row.name), Box::new(EditRowAction(row_ix))) menu.menu(format!("Edit {}", row.name), Box::new(EditRowAction(row_ix)))
.menu("Delete", Box::new(DeleteRowAction(row_ix))) .menu("Delete", Box::new(DeleteRowAction(row_ix)))
@ -218,32 +204,15 @@ impl TableDelegate for MyTableDelegate {
.menu("Duplicate", Box::new(DuplicateRowAction(row_ix))) .menu("Duplicate", Box::new(DuplicateRowAction(row_ix)))
} }
} }
// Handle table events
cx.subscribe_in(&state, window, |view, table, event, _, cx| {
match event {
TableEvent::SelectRow(row_ix) => {
println!("Row {} selected", row_ix);
}
TableEvent::DoubleClickedRow(row_ix) => {
println!("Row {} double-clicked", row_ix);
// Open detail view or edit mode
}
TableEvent::SelectColumn(col_ix) => {
println!("Column {} selected", col_ix);
}
_ => {}
}
}).detach();
``` ```
### Custom Cell Rendering ### Cell Rendering
Create rich cell content with custom rendering: Create rich cell content with custom rendering:
```rust ```rust
impl TableDelegate for MyTableDelegate { impl TableDelegate for MyTableDelegate {
fn render_td(&self, row_ix: usize, col_ix: usize, _: &mut Window, cx: &mut App) -> impl IntoElement { fn render_td(&mut self, row_ix: usize, col_ix: usize, _: &mut Window, cx: &mut Context<TableState<Self>>) -> impl IntoElement {
let row = &self.data[row_ix]; let row = &self.data[row_ix];
let col = &self.columns[col_ix]; let col = &self.columns[col_ix];
@ -413,7 +382,7 @@ struct StockData {
} }
impl TableDelegate for StockTableDelegate { impl TableDelegate for StockTableDelegate {
fn render_td(&self, row_ix: usize, col_ix: usize, _: &mut Window, cx: &mut App) -> impl IntoElement { fn render_td(&mut self, row_ix: usize, col_ix: usize, _: &mut Window, cx: &mut Context<TableState<Self>>) -> impl IntoElement {
let stock = &self.stocks[row_ix]; let stock = &self.stocks[row_ix];
let col = &self.columns[col_ix]; let col = &self.columns[col_ix];