mirror of
https://github.com/feigeCode/navop.git
synced 2026-11-06 08:07:31 +00:00
fix(terminal): 左侧/底部侧栏拖动改用工作区根元素的真实 bounds
侧栏拖动的宽度换算依赖 workspace_bounds,而它此前由 WorkspaceResizeEventHandler::prepaint 用元素自身 bounds 写入。该元素是 h_flex 里 0×0 的弹性子项,落在工作区右缘、垂直居中,于是: - 左侧:`鼠标 x - 工作区右缘` 恒为负,每次拖动都被夹到最小宽度 (280),表现为「移到左边后拖不动」。 - 底部:`工作区中线 - 鼠标 y` 同样为负,也被夹到最小宽度。 - 右侧:元素右缘恰好等于工作区右缘,才碰巧正常。 改为在工作区根 h_flex 上用 on_prepaint 捕获真实 bounds(与 db_view 的 写法一致),事件处理元素只保留鼠标监听。内嵌 dock(TerminalView 嵌入 资源工作台)的 view_bounds 同样从 window.bounds() 改为 dock 根元素的 on_prepaint,避免视图不在窗口原点时换算偏移。 新增两条契约测试分别锁定工作区与内嵌 dock 的 bounds 来源。 验证:cargo test -p terminal_view --lib 572 passed。
This commit is contained in:
@@ -88,6 +88,7 @@ impl TerminalView {
|
||||
) -> AnyElement {
|
||||
let state = self.tool_dock_render_state(cx);
|
||||
let view = cx.entity().clone();
|
||||
let bounds_view = view.clone();
|
||||
let bg_color = self.current_theme.background;
|
||||
let center = CenterRegionState {
|
||||
font_family,
|
||||
@@ -106,6 +107,13 @@ impl TerminalView {
|
||||
.min_w_0()
|
||||
.min_h_0()
|
||||
.overflow_hidden()
|
||||
// 拖动换算要用 dock 根元素的真实 bounds;事件监听元素自身是 0×0,
|
||||
// 而 window.bounds() 在嵌入面板里也不等于 dock 的位置。
|
||||
.on_prepaint(move |bounds, _, cx| {
|
||||
bounds_view.update(cx, |view, _| {
|
||||
view.view_bounds = bounds;
|
||||
});
|
||||
})
|
||||
.bg(bg_color)
|
||||
.key_context(TERMINAL_CONTEXT)
|
||||
.on_action(cx.listener(Self::start_recording_action))
|
||||
|
||||
@@ -40,16 +40,11 @@ impl Element for ResizeEventHandler {
|
||||
_: Option<&InspectorElementId>,
|
||||
_: Bounds<Pixels>,
|
||||
_: &mut Self::RequestLayoutState,
|
||||
window: &mut Window,
|
||||
cx: &mut App,
|
||||
_window: &mut Window,
|
||||
_cx: &mut App,
|
||||
) -> Self::PrepaintState {
|
||||
let bounds = window.bounds();
|
||||
self.view.update(cx, |view, _| {
|
||||
view.view_bounds = Bounds {
|
||||
origin: Point::default(),
|
||||
size: bounds.size,
|
||||
};
|
||||
});
|
||||
// view_bounds 由 dock 根元素的 on_prepaint 写入:本元素是 0×0 的弹性
|
||||
// 子项,而窗口 bounds 在嵌入面板里也不等于 dock 的位置。
|
||||
}
|
||||
|
||||
fn paint(
|
||||
|
||||
@@ -945,3 +945,24 @@ fn terminal_render_uses_cached_font_metrics() {
|
||||
assert!(metric_source.contains("fn refresh_terminal_font_metrics("));
|
||||
assert!(!render_setup.contains("cx.text_system().all_font_names()"));
|
||||
}
|
||||
|
||||
/// 内嵌 dock 的拖动换算同样必须使用 dock 根元素的真实 bounds,
|
||||
/// 不能用 `window.bounds()`(嵌入面板时原点/尺寸都不是 dock 的)。
|
||||
#[test]
|
||||
fn embedded_sidebar_resize_uses_dock_bounds_not_window_bounds() {
|
||||
let render_layout = include_str!("../render_layout.rs");
|
||||
let resize_event_handler = include_str!("../resize_event_handler.rs");
|
||||
|
||||
assert!(
|
||||
render_layout.contains(".on_prepaint(move |bounds, _, cx|"),
|
||||
"tool dock root must capture its own bounds via on_prepaint"
|
||||
);
|
||||
assert!(
|
||||
render_layout.contains("view.view_bounds = bounds"),
|
||||
"tool dock root prepaint must write view_bounds"
|
||||
);
|
||||
assert!(
|
||||
!resize_event_handler.contains("window.bounds()"),
|
||||
"resize event handler must not derive view bounds from the window"
|
||||
);
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ use gpui::{
|
||||
AnyElement, Context, InteractiveElement as _, IntoElement as _, ParentElement as _,
|
||||
Styled as _, div,
|
||||
};
|
||||
use gpui_component::{h_flex, v_flex};
|
||||
use gpui_component::{ElementExt as _, h_flex, v_flex};
|
||||
use one_core::layout::TOOLBAR_WIDTH;
|
||||
use one_core::sidebar_contribution::SidebarPlacement;
|
||||
|
||||
@@ -76,12 +76,21 @@ impl TerminalWorkspace {
|
||||
)
|
||||
});
|
||||
|
||||
let workspace = cx.entity();
|
||||
h_flex()
|
||||
.id("terminal-workspace-root")
|
||||
.size_full()
|
||||
.min_w_0()
|
||||
.min_h_0()
|
||||
.overflow_hidden()
|
||||
// 侧栏拖动换算要用工作区根元素的真实 bounds。事件监听元素本身是
|
||||
// 0×0 的弹性子项,拿它自己的 bounds 当工作区边界会让左/下拖动
|
||||
// 永远被夹到最小宽度。
|
||||
.on_prepaint(move |bounds, _, cx| {
|
||||
workspace.update(cx, |workspace, _| {
|
||||
workspace.workspace_bounds = bounds;
|
||||
});
|
||||
})
|
||||
.when_some(left, |this, panel| {
|
||||
this.child(
|
||||
div()
|
||||
|
||||
@@ -116,14 +116,13 @@ impl Element for WorkspaceResizeEventHandler {
|
||||
&mut self,
|
||||
_: Option<&GlobalElementId>,
|
||||
_: Option<&InspectorElementId>,
|
||||
bounds: Bounds<Pixels>,
|
||||
_: Bounds<Pixels>,
|
||||
_: &mut Self::RequestLayoutState,
|
||||
_: &mut Window,
|
||||
cx: &mut App,
|
||||
_: &mut App,
|
||||
) -> Self::PrepaintState {
|
||||
self.workspace.update(cx, |workspace, _| {
|
||||
workspace.workspace_bounds = bounds;
|
||||
});
|
||||
// 工作区 bounds 由根元素的 on_prepaint 写入:本元素是 0×0 的弹性
|
||||
// 子项,自身 bounds 不能当作工作区边界。
|
||||
}
|
||||
|
||||
fn paint(
|
||||
|
||||
@@ -198,3 +198,25 @@ fn closing_pane_preserves_surviving_ratio(cx: &mut TestAppContext) {
|
||||
assert_width(pane_width(visual, PANE_SELECTORS[1]), px(630.));
|
||||
assert_eq!(2, visual.read(|cx| harness.read(cx).tree.panes().len()));
|
||||
}
|
||||
|
||||
/// 侧栏拖动换算依赖 `workspace_bounds`。它必须来自工作区根元素的真实
|
||||
/// bounds:事件监听元素是 0×0 的弹性子项,拿它自己的 bounds 会让左侧
|
||||
/// 与底部拖动永远被夹到最小宽度(左侧面板拖不动)。
|
||||
#[test]
|
||||
fn sidebar_resize_bounds_come_from_the_workspace_root() {
|
||||
let layout_source = include_str!("layout.rs");
|
||||
let resize_source = include_str!("resize.rs");
|
||||
|
||||
assert!(
|
||||
layout_source.contains(".on_prepaint(move |bounds, _, cx|"),
|
||||
"workspace root must capture its own bounds via on_prepaint"
|
||||
);
|
||||
assert!(
|
||||
layout_source.contains("workspace.workspace_bounds = bounds"),
|
||||
"workspace root prepaint must write workspace_bounds"
|
||||
);
|
||||
assert!(
|
||||
!resize_source.contains("workspace_bounds = bounds"),
|
||||
"resize event handler is zero-sized; its bounds must not be used as the workspace bounds"
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user