dock: Add cache to panel view. (#600)
This commit is contained in:
parent
3e16c0d220
commit
9675f1e02b
4 changed files with 206 additions and 189 deletions
|
|
@ -33,8 +33,8 @@ impl_internal_actions!(table_story, [ChangeSize, OpenDetail]);
|
||||||
#[derive(Clone, Debug, Default)]
|
#[derive(Clone, Debug, Default)]
|
||||||
struct Stock {
|
struct Stock {
|
||||||
id: usize,
|
id: usize,
|
||||||
symbol: String,
|
symbol: SharedString,
|
||||||
name: String,
|
name: SharedString,
|
||||||
price: f64,
|
price: f64,
|
||||||
change: f64,
|
change: f64,
|
||||||
change_percent: f64,
|
change_percent: f64,
|
||||||
|
|
@ -103,8 +103,8 @@ fn random_stocks(size: usize) -> Vec<Stock> {
|
||||||
(0..size)
|
(0..size)
|
||||||
.map(|id| Stock {
|
.map(|id| Stock {
|
||||||
id,
|
id,
|
||||||
symbol: Faker.fake::<String>(),
|
symbol: Faker.fake::<String>().into(),
|
||||||
name: Faker.fake::<String>(),
|
name: Faker.fake::<String>().into(),
|
||||||
change: (-100.0..100.0).fake(),
|
change: (-100.0..100.0).fake(),
|
||||||
change_percent: (-1.0..1.0).fake(),
|
change_percent: (-1.0..1.0).fake(),
|
||||||
volume: (0.0..1000.0).fake(),
|
volume: (0.0..1000.0).fake(),
|
||||||
|
|
|
||||||
|
|
@ -3,9 +3,10 @@
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use gpui::{
|
use gpui::{
|
||||||
div, prelude::FluentBuilder as _, px, App, AppContext, Axis, Context, Element, Empty, Entity,
|
div, prelude::FluentBuilder as _, px, AnyView, App, AppContext, Axis, Context, Element, Empty,
|
||||||
InteractiveElement as _, IntoElement, MouseMoveEvent, MouseUpEvent, ParentElement as _, Pixels,
|
Entity, InteractiveElement as _, IntoElement, MouseMoveEvent, MouseUpEvent, ParentElement as _,
|
||||||
Point, Render, StatefulInteractiveElement, Style, Styled as _, WeakEntity, Window,
|
Pixels, Point, Render, StatefulInteractiveElement, Style, StyleRefinement, Styled as _,
|
||||||
|
WeakEntity, Window,
|
||||||
};
|
};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
|
@ -394,6 +395,8 @@ impl Render for Dock {
|
||||||
return div();
|
return div();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let cache_style = StyleRefinement::default().v_flex().size_full();
|
||||||
|
|
||||||
div()
|
div()
|
||||||
.relative()
|
.relative()
|
||||||
.overflow_hidden()
|
.overflow_hidden()
|
||||||
|
|
@ -408,8 +411,10 @@ impl Render for Dock {
|
||||||
})
|
})
|
||||||
.map(|this| match &self.panel {
|
.map(|this| match &self.panel {
|
||||||
DockItem::Split { view, .. } => this.child(view.clone()),
|
DockItem::Split { view, .. } => this.child(view.clone()),
|
||||||
DockItem::Tabs { view, .. } => this.child(view.clone()),
|
DockItem::Tabs { view, .. } => {
|
||||||
DockItem::Panel { view, .. } => this.child(view.clone().view()),
|
this.child(AnyView::from(view.clone()).cached(cache_style))
|
||||||
|
}
|
||||||
|
DockItem::Panel { view, .. } => this.child(view.clone().view().cached(cache_style)),
|
||||||
// Not support to render Tiles and Tile into Dock
|
// Not support to render Tiles and Tile into Dock
|
||||||
DockItem::Tiles { .. } => this,
|
DockItem::Tiles { .. } => this,
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ use gpui::{
|
||||||
div, prelude::FluentBuilder, px, rems, App, AppContext, Context, Corner, DefiniteLength,
|
div, prelude::FluentBuilder, px, rems, App, AppContext, Context, Corner, DefiniteLength,
|
||||||
DismissEvent, DragMoveEvent, Empty, Entity, EventEmitter, FocusHandle, Focusable,
|
DismissEvent, DragMoveEvent, Empty, Entity, EventEmitter, FocusHandle, Focusable,
|
||||||
InteractiveElement as _, IntoElement, ParentElement, Pixels, Render, ScrollHandle,
|
InteractiveElement as _, IntoElement, ParentElement, Pixels, Render, ScrollHandle,
|
||||||
SharedString, StatefulInteractiveElement, Styled, WeakEntity, Window,
|
SharedString, StatefulInteractiveElement, StyleRefinement, Styled, WeakEntity, Window,
|
||||||
};
|
};
|
||||||
use rust_i18n::t;
|
use rust_i18n::t;
|
||||||
|
|
||||||
|
|
@ -14,7 +14,7 @@ use crate::{
|
||||||
h_flex,
|
h_flex,
|
||||||
popup_menu::{PopupMenu, PopupMenuExt},
|
popup_menu::{PopupMenu, PopupMenuExt},
|
||||||
tab::{Tab, TabBar},
|
tab::{Tab, TabBar},
|
||||||
v_flex, ActiveTheme, AxisExt, IconName, Placement, Selectable, Sizable,
|
v_flex, ActiveTheme, AxisExt, IconName, Placement, Selectable, Sizable, StyledExt as _,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
|
|
@ -767,7 +767,11 @@ impl TabPanel {
|
||||||
.overflow_y_scroll()
|
.overflow_y_scroll()
|
||||||
.overflow_x_hidden()
|
.overflow_x_hidden()
|
||||||
.flex_1()
|
.flex_1()
|
||||||
.child(active_panel.view())
|
.child(
|
||||||
|
active_panel
|
||||||
|
.view()
|
||||||
|
.cached(StyleRefinement::default().v_flex().size_full()),
|
||||||
|
)
|
||||||
.when(state.droppable, |this| {
|
.when(state.droppable, |this| {
|
||||||
this.on_drag_move(cx.listener(Self::on_panel_drag_move))
|
this.on_drag_move(cx.listener(Self::on_panel_drag_move))
|
||||||
.child(
|
.child(
|
||||||
|
|
|
||||||
|
|
@ -589,201 +589,209 @@ impl Element for Scrollbar {
|
||||||
let is_visible = self.state.get().is_scrollbar_visible();
|
let is_visible = self.state.get().is_scrollbar_visible();
|
||||||
let is_hover_to_show = cx.theme().scrollbar_show.is_hover();
|
let is_hover_to_show = cx.theme().scrollbar_show.is_hover();
|
||||||
|
|
||||||
for state in prepaint.states.iter() {
|
window.with_content_mask(
|
||||||
let axis = state.axis;
|
Some(ContentMask {
|
||||||
let radius = state.radius;
|
bounds: hitbox_bounds,
|
||||||
let bounds = state.bounds;
|
}),
|
||||||
let thumb_bounds = state.thumb_bounds;
|
|window| {
|
||||||
let scroll_area_size = state.scroll_size;
|
for state in prepaint.states.iter() {
|
||||||
let container_size = state.container_size;
|
let axis = state.axis;
|
||||||
let thumb_size = state.thumb_size;
|
let radius = state.radius;
|
||||||
let margin_end = state.margin_end;
|
let bounds = state.bounds;
|
||||||
let is_vertical = axis.is_vertical();
|
let thumb_bounds = state.thumb_bounds;
|
||||||
|
let scroll_area_size = state.scroll_size;
|
||||||
|
let container_size = state.container_size;
|
||||||
|
let thumb_size = state.thumb_size;
|
||||||
|
let margin_end = state.margin_end;
|
||||||
|
let is_vertical = axis.is_vertical();
|
||||||
|
|
||||||
window.set_cursor_style(CursorStyle::default(), &state.bar_hitbox);
|
window.set_cursor_style(CursorStyle::default(), &state.bar_hitbox);
|
||||||
|
|
||||||
window.paint_layer(hitbox_bounds, |cx| {
|
window.paint_layer(hitbox_bounds, |cx| {
|
||||||
cx.paint_quad(fill(state.bounds, state.bg));
|
cx.paint_quad(fill(state.bounds, state.bg));
|
||||||
|
|
||||||
cx.paint_quad(PaintQuad {
|
cx.paint_quad(PaintQuad {
|
||||||
bounds,
|
bounds,
|
||||||
corner_radii: (0.).into(),
|
corner_radii: (0.).into(),
|
||||||
background: gpui::transparent_black().into(),
|
background: gpui::transparent_black().into(),
|
||||||
border_widths: if is_vertical {
|
border_widths: if is_vertical {
|
||||||
Edges {
|
Edges {
|
||||||
top: px(0.),
|
top: px(0.),
|
||||||
right: px(0.),
|
right: px(0.),
|
||||||
bottom: px(0.),
|
bottom: px(0.),
|
||||||
left: BORDER_WIDTH,
|
left: BORDER_WIDTH,
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
Edges {
|
|
||||||
top: BORDER_WIDTH,
|
|
||||||
right: px(0.),
|
|
||||||
bottom: px(0.),
|
|
||||||
left: px(0.),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
border_color: state.border,
|
|
||||||
});
|
|
||||||
|
|
||||||
cx.paint_quad(fill(state.thumb_fill_bounds, state.thumb_bg).corner_radii(radius));
|
|
||||||
});
|
|
||||||
|
|
||||||
window.on_mouse_event({
|
|
||||||
let state = self.state.clone();
|
|
||||||
let view_id = self.view_id;
|
|
||||||
let scroll_handle = self.scroll_handle.clone();
|
|
||||||
|
|
||||||
move |event: &ScrollWheelEvent, phase, _, cx| {
|
|
||||||
if phase.bubble() && hitbox_bounds.contains(&event.position) {
|
|
||||||
if scroll_handle.offset() != state.get().last_scroll_offset {
|
|
||||||
state.set(
|
|
||||||
state
|
|
||||||
.get()
|
|
||||||
.with_last_scroll(scroll_handle.offset(), Some(Instant::now())),
|
|
||||||
);
|
|
||||||
cx.notify(view_id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let safe_range = (-scroll_area_size + container_size)..px(0.);
|
|
||||||
|
|
||||||
if is_hover_to_show || is_visible {
|
|
||||||
window.on_mouse_event({
|
|
||||||
let state = self.state.clone();
|
|
||||||
let view_id = self.view_id;
|
|
||||||
let scroll_handle = self.scroll_handle.clone();
|
|
||||||
|
|
||||||
move |event: &MouseDownEvent, phase, _, cx| {
|
|
||||||
if phase.bubble() && bounds.contains(&event.position) {
|
|
||||||
cx.stop_propagation();
|
|
||||||
|
|
||||||
if thumb_bounds.contains(&event.position) {
|
|
||||||
// click on the thumb bar, set the drag position
|
|
||||||
let pos = event.position - thumb_bounds.origin;
|
|
||||||
|
|
||||||
state.set(state.get().with_drag_pos(axis, pos));
|
|
||||||
|
|
||||||
cx.notify(view_id);
|
|
||||||
} else {
|
} else {
|
||||||
// click on the scrollbar, jump to the position
|
Edges {
|
||||||
// Set the thumb bar center to the click position
|
top: BORDER_WIDTH,
|
||||||
let offset = scroll_handle.offset();
|
right: px(0.),
|
||||||
let percentage = if is_vertical {
|
bottom: px(0.),
|
||||||
(event.position.y - thumb_size / 2. - bounds.origin.y)
|
left: px(0.),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
border_color: state.border,
|
||||||
|
});
|
||||||
|
|
||||||
|
cx.paint_quad(
|
||||||
|
fill(state.thumb_fill_bounds, state.thumb_bg).corner_radii(radius),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
window.on_mouse_event({
|
||||||
|
let state = self.state.clone();
|
||||||
|
let view_id = self.view_id;
|
||||||
|
let scroll_handle = self.scroll_handle.clone();
|
||||||
|
|
||||||
|
move |event: &ScrollWheelEvent, phase, _, cx| {
|
||||||
|
if phase.bubble() && hitbox_bounds.contains(&event.position) {
|
||||||
|
if scroll_handle.offset() != state.get().last_scroll_offset {
|
||||||
|
state.set(state.get().with_last_scroll(
|
||||||
|
scroll_handle.offset(),
|
||||||
|
Some(Instant::now()),
|
||||||
|
));
|
||||||
|
cx.notify(view_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let safe_range = (-scroll_area_size + container_size)..px(0.);
|
||||||
|
|
||||||
|
if is_hover_to_show || is_visible {
|
||||||
|
window.on_mouse_event({
|
||||||
|
let state = self.state.clone();
|
||||||
|
let view_id = self.view_id;
|
||||||
|
let scroll_handle = self.scroll_handle.clone();
|
||||||
|
|
||||||
|
move |event: &MouseDownEvent, phase, _, cx| {
|
||||||
|
if phase.bubble() && bounds.contains(&event.position) {
|
||||||
|
cx.stop_propagation();
|
||||||
|
|
||||||
|
if thumb_bounds.contains(&event.position) {
|
||||||
|
// click on the thumb bar, set the drag position
|
||||||
|
let pos = event.position - thumb_bounds.origin;
|
||||||
|
|
||||||
|
state.set(state.get().with_drag_pos(axis, pos));
|
||||||
|
|
||||||
|
cx.notify(view_id);
|
||||||
|
} else {
|
||||||
|
// click on the scrollbar, jump to the position
|
||||||
|
// Set the thumb bar center to the click position
|
||||||
|
let offset = scroll_handle.offset();
|
||||||
|
let percentage = if is_vertical {
|
||||||
|
(event.position.y - thumb_size / 2. - bounds.origin.y)
|
||||||
|
/ (bounds.size.height - thumb_size)
|
||||||
|
} else {
|
||||||
|
(event.position.x - thumb_size / 2. - bounds.origin.x)
|
||||||
|
/ (bounds.size.width - thumb_size)
|
||||||
|
}
|
||||||
|
.min(1.);
|
||||||
|
|
||||||
|
if is_vertical {
|
||||||
|
scroll_handle.set_offset(point(
|
||||||
|
offset.x,
|
||||||
|
(-scroll_area_size * percentage)
|
||||||
|
.clamp(safe_range.start, safe_range.end),
|
||||||
|
));
|
||||||
|
} else {
|
||||||
|
scroll_handle.set_offset(point(
|
||||||
|
(-scroll_area_size * percentage)
|
||||||
|
.clamp(safe_range.start, safe_range.end),
|
||||||
|
offset.y,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
window.on_mouse_event({
|
||||||
|
let scroll_handle = self.scroll_handle.clone();
|
||||||
|
let state = self.state.clone();
|
||||||
|
let view_id = self.view_id;
|
||||||
|
|
||||||
|
move |event: &MouseMoveEvent, _, _, cx| {
|
||||||
|
// Update hovered state for scrollbar
|
||||||
|
if bounds.contains(&event.position) {
|
||||||
|
if state.get().hovered_axis != Some(axis) {
|
||||||
|
state.set(state.get().with_hovered(Some(axis)));
|
||||||
|
cx.notify(view_id);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if state.get().hovered_axis == Some(axis) {
|
||||||
|
if state.get().hovered_axis.is_some() {
|
||||||
|
state.set(state.get().with_hovered(None));
|
||||||
|
cx.notify(view_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update hovered state for scrollbar thumb
|
||||||
|
if thumb_bounds.contains(&event.position) {
|
||||||
|
if state.get().hovered_on_thumb != Some(axis) {
|
||||||
|
state.set(state.get().with_hovered_on_thumb(Some(axis)));
|
||||||
|
cx.notify(view_id);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if state.get().hovered_on_thumb == Some(axis) {
|
||||||
|
state.set(state.get().with_hovered_on_thumb(None));
|
||||||
|
cx.notify(view_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move thumb position on dragging
|
||||||
|
if state.get().dragged_axis == Some(axis) && event.dragging() {
|
||||||
|
// drag_pos is the position of the mouse down event
|
||||||
|
// We need to keep the thumb bar still at the origin down position
|
||||||
|
let drag_pos = state.get().drag_pos;
|
||||||
|
|
||||||
|
let percentage = (if is_vertical {
|
||||||
|
(event.position.y - drag_pos.y - bounds.origin.y)
|
||||||
/ (bounds.size.height - thumb_size)
|
/ (bounds.size.height - thumb_size)
|
||||||
} else {
|
} else {
|
||||||
(event.position.x - thumb_size / 2. - bounds.origin.x)
|
(event.position.x - drag_pos.x - bounds.origin.x)
|
||||||
/ (bounds.size.width - thumb_size)
|
/ (bounds.size.width - thumb_size - margin_end)
|
||||||
}
|
})
|
||||||
.min(1.);
|
.clamp(0., 1.);
|
||||||
|
|
||||||
if is_vertical {
|
let offset = if is_vertical {
|
||||||
scroll_handle.set_offset(point(
|
point(
|
||||||
offset.x,
|
scroll_handle.offset().x,
|
||||||
(-scroll_area_size * percentage)
|
(-(scroll_area_size - container_size) * percentage)
|
||||||
.clamp(safe_range.start, safe_range.end),
|
.clamp(safe_range.start, safe_range.end),
|
||||||
));
|
)
|
||||||
} else {
|
} else {
|
||||||
scroll_handle.set_offset(point(
|
point(
|
||||||
(-scroll_area_size * percentage)
|
(-(scroll_area_size - container_size) * percentage)
|
||||||
.clamp(safe_range.start, safe_range.end),
|
.clamp(safe_range.start, safe_range.end),
|
||||||
offset.y,
|
scroll_handle.offset().y,
|
||||||
));
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
if (scroll_handle.offset().y - offset.y).abs() > px(1.)
|
||||||
|
|| (scroll_handle.offset().x - offset.x).abs() > px(1.)
|
||||||
|
{
|
||||||
|
scroll_handle.set_offset(offset);
|
||||||
|
cx.notify(view_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
window.on_mouse_event({
|
window.on_mouse_event({
|
||||||
let scroll_handle = self.scroll_handle.clone();
|
let view_id = self.view_id;
|
||||||
let state = self.state.clone();
|
let state = self.state.clone();
|
||||||
let view_id = self.view_id;
|
|
||||||
|
|
||||||
move |event: &MouseMoveEvent, _, _, cx| {
|
move |_event: &MouseUpEvent, phase, _, cx| {
|
||||||
// Update hovered state for scrollbar
|
if phase.bubble() {
|
||||||
if bounds.contains(&event.position) {
|
state.set(state.get().with_unset_drag_pos());
|
||||||
if state.get().hovered_axis != Some(axis) {
|
|
||||||
state.set(state.get().with_hovered(Some(axis)));
|
|
||||||
cx.notify(view_id);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if state.get().hovered_axis == Some(axis) {
|
|
||||||
if state.get().hovered_axis.is_some() {
|
|
||||||
state.set(state.get().with_hovered(None));
|
|
||||||
cx.notify(view_id);
|
cx.notify(view_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
|
||||||
// Update hovered state for scrollbar thumb
|
|
||||||
if thumb_bounds.contains(&event.position) {
|
|
||||||
if state.get().hovered_on_thumb != Some(axis) {
|
|
||||||
state.set(state.get().with_hovered_on_thumb(Some(axis)));
|
|
||||||
cx.notify(view_id);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if state.get().hovered_on_thumb == Some(axis) {
|
|
||||||
state.set(state.get().with_hovered_on_thumb(None));
|
|
||||||
cx.notify(view_id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Move thumb position on dragging
|
|
||||||
if state.get().dragged_axis == Some(axis) && event.dragging() {
|
|
||||||
// drag_pos is the position of the mouse down event
|
|
||||||
// We need to keep the thumb bar still at the origin down position
|
|
||||||
let drag_pos = state.get().drag_pos;
|
|
||||||
|
|
||||||
let percentage = (if is_vertical {
|
|
||||||
(event.position.y - drag_pos.y - bounds.origin.y)
|
|
||||||
/ (bounds.size.height - thumb_size)
|
|
||||||
} else {
|
|
||||||
(event.position.x - drag_pos.x - bounds.origin.x)
|
|
||||||
/ (bounds.size.width - thumb_size - margin_end)
|
|
||||||
})
|
|
||||||
.clamp(0., 1.);
|
|
||||||
|
|
||||||
let offset = if is_vertical {
|
|
||||||
point(
|
|
||||||
scroll_handle.offset().x,
|
|
||||||
(-(scroll_area_size - container_size) * percentage)
|
|
||||||
.clamp(safe_range.start, safe_range.end),
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
point(
|
|
||||||
(-(scroll_area_size - container_size) * percentage)
|
|
||||||
.clamp(safe_range.start, safe_range.end),
|
|
||||||
scroll_handle.offset().y,
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
if (scroll_handle.offset().y - offset.y).abs() > px(1.)
|
|
||||||
|| (scroll_handle.offset().x - offset.x).abs() > px(1.)
|
|
||||||
{
|
|
||||||
scroll_handle.set_offset(offset);
|
|
||||||
cx.notify(view_id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
},
|
||||||
|
);
|
||||||
window.on_mouse_event({
|
|
||||||
let view_id = self.view_id;
|
|
||||||
let state = self.state.clone();
|
|
||||||
|
|
||||||
move |_event: &MouseUpEvent, phase, _, cx| {
|
|
||||||
if phase.bubble() {
|
|
||||||
state.set(state.get().with_unset_drag_pos());
|
|
||||||
cx.notify(view_id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue