image_viewer: Make the outline panel width adjustable
- Add a drag handle on the outline panel's right edge that resizes the panel between 120 and 480 pixels - Track the drag on the surrounding row so the pointer can roam, and clamp the width to keep the panel usable - Keep the chosen width while toggling the panel and inherit it when the view is split
This commit is contained in:
1 parent
1b2685ac9b
commit
de4affc638
1 file changed
+94
-12
@@ -12,12 +12,12 @@ use editor::{
|
||||
};
|
||||
use file_icons::FileIcons;
|
||||
use gpui::{
|
||||
AnyElement, App, Bounds, Context, DismissEvent, DispatchPhase, Element, ElementId, Entity,
|
||||
EventEmitter, FocusHandle, Focusable, Font, GlobalElementId, InspectorElementId,
|
||||
InteractiveElement, IntoElement, KeyDownEvent, LayoutId, MouseButton, MouseDownEvent,
|
||||
MouseMoveEvent, MouseUpEvent, ParentElement, PinchEvent, Pixels, Point, Render, RenderImage,
|
||||
ScrollDelta, ScrollWheelEvent, Style, Styled, Subscription, Task, WeakEntity, Window, actions,
|
||||
anchored, canvas, checkerboard, deferred, div, img, point, px, size,
|
||||
AnyElement, App, Bounds, Context, DismissEvent, DispatchPhase, DragMoveEvent, Element,
|
||||
ElementId, Entity, EventEmitter, FocusHandle, Focusable, Font, GlobalElementId,
|
||||
InspectorElementId, InteractiveElement, IntoElement, KeyDownEvent, LayoutId, MouseButton,
|
||||
MouseDownEvent, MouseMoveEvent, MouseUpEvent, ParentElement, PinchEvent, Pixels, Point, Render,
|
||||
RenderImage, ScrollDelta, ScrollWheelEvent, Style, Styled, Subscription, Task, WeakEntity,
|
||||
Window, actions, anchored, canvas, checkerboard, deferred, div, img, point, px, size,
|
||||
};
|
||||
use language::File as _;
|
||||
use pdf_viewer::{
|
||||
@@ -123,6 +123,9 @@ const FIND_BAR_WIDTH: f32 = 280.0;
|
||||
const THUMBNAIL_DPI: f32 = 20.0; // Renders letter pages about 170px wide.
|
||||
const THUMBNAIL_PANEL_WIDTH: f32 = 150.0;
|
||||
const OUTLINE_PANEL_WIDTH: f32 = 220.0;
|
||||
const OUTLINE_PANEL_MIN_WIDTH: f32 = 120.0;
|
||||
const OUTLINE_PANEL_MAX_WIDTH: f32 = 480.0;
|
||||
const OUTLINE_RESIZE_HANDLE_WIDTH: f32 = 6.0;
|
||||
const OUTLINE_INDENT: f32 = 12.0;
|
||||
const PROPERTIES_PANEL_WIDTH: f32 = 220.0;
|
||||
const HIGHLIGHT_COLORS: [pdf_viewer::PdfAnnotationColor; 4] = [
|
||||
@@ -202,6 +205,15 @@ struct NormRect {
|
||||
height: f32,
|
||||
}
|
||||
|
||||
/// Drag payload identifying a resize drag of the outline panel's right edge.
|
||||
struct OutlinePanelResize;
|
||||
|
||||
impl Render for OutlinePanelResize {
|
||||
fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
|
||||
div()
|
||||
}
|
||||
}
|
||||
|
||||
/// Which annotation tool the viewer is armed with.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
enum PdfAnnotationTool {
|
||||
@@ -267,6 +279,10 @@ pub struct ImageView {
|
||||
pdf_find: Option<PdfFindState>,
|
||||
show_thumbnail_panel: bool,
|
||||
show_outline_panel: bool,
|
||||
/// Current outline panel width, adjusted by dragging its resize handle.
|
||||
outline_panel_width: Pixels,
|
||||
/// Mouse x and panel width when the outline resize drag started.
|
||||
outline_resize_origin: Option<(Pixels, Pixels)>,
|
||||
show_properties_panel: bool,
|
||||
presentation_mode: bool,
|
||||
page_rotation: u16,
|
||||
@@ -425,6 +441,8 @@ impl ImageView {
|
||||
pdf_find: None,
|
||||
show_thumbnail_panel: false,
|
||||
show_outline_panel: false,
|
||||
outline_panel_width: px(OUTLINE_PANEL_WIDTH),
|
||||
outline_resize_origin: None,
|
||||
show_properties_panel: false,
|
||||
presentation_mode: false,
|
||||
page_rotation: 0,
|
||||
@@ -1911,6 +1929,7 @@ impl ImageView {
|
||||
/// Renders the outline sidebar, indenting nested entries like a document tree.
|
||||
fn render_outline_panel(
|
||||
outline: Option<&[pdf_viewer::PdfOutlineItem]>,
|
||||
width: Pixels,
|
||||
cx: &mut Context<Self>,
|
||||
) -> AnyElement {
|
||||
let mut next_id = 0_usize;
|
||||
@@ -1921,7 +1940,8 @@ impl ImageView {
|
||||
|
||||
div()
|
||||
.id("pdf-outline")
|
||||
.w(px(OUTLINE_PANEL_WIDTH))
|
||||
.debug_selector(|| "pdf-outline".into())
|
||||
.w(width)
|
||||
.h_full()
|
||||
.p_2()
|
||||
.overflow_y_scroll()
|
||||
@@ -1937,6 +1957,37 @@ impl ImageView {
|
||||
.into_any_element()
|
||||
}
|
||||
|
||||
/// Renders the drag handle on the outline panel's right edge. The actual
|
||||
/// resize tracking happens in the `on_drag_move` handler on the surrounding
|
||||
/// row so the pointer can roam while dragging.
|
||||
fn render_outline_resize_handle(&mut self, cx: &mut Context<Self>) -> AnyElement {
|
||||
div()
|
||||
.id("outline-resize-handle")
|
||||
.debug_selector(|| "outline-resize-handle".into())
|
||||
.occlude()
|
||||
.w(px(OUTLINE_RESIZE_HANDLE_WIDTH))
|
||||
.h_full()
|
||||
.cursor_col_resize()
|
||||
.hover(|style| style.bg(cx.theme().colors().element_hover))
|
||||
.on_drag(OutlinePanelResize, |_, _, _, cx| {
|
||||
cx.stop_propagation();
|
||||
cx.new(|_| OutlinePanelResize)
|
||||
})
|
||||
.on_mouse_down(
|
||||
MouseButton::Left,
|
||||
cx.listener(|this, event: &MouseDownEvent, _, _| {
|
||||
this.outline_resize_origin = Some((event.position.x, this.outline_panel_width));
|
||||
}),
|
||||
)
|
||||
.on_mouse_up(
|
||||
MouseButton::Left,
|
||||
cx.listener(|this, _: &MouseUpEvent, _, _| {
|
||||
this.outline_resize_origin = None;
|
||||
}),
|
||||
)
|
||||
.into_any_element()
|
||||
}
|
||||
|
||||
fn render_outline_items(
|
||||
items: &[pdf_viewer::PdfOutlineItem],
|
||||
depth: usize,
|
||||
@@ -3147,6 +3198,8 @@ impl Item for ImageView {
|
||||
pdf_find: None,
|
||||
show_thumbnail_panel: false,
|
||||
show_outline_panel: false,
|
||||
outline_panel_width: self.outline_panel_width,
|
||||
outline_resize_origin: None,
|
||||
show_properties_panel: false,
|
||||
presentation_mode: false,
|
||||
page_rotation: 0,
|
||||
@@ -3934,16 +3987,46 @@ impl Render for ImageView {
|
||||
cx,
|
||||
))
|
||||
} else if self.show_outline_panel {
|
||||
Some(Self::render_outline_panel(self.pdf_outline.as_deref(), cx))
|
||||
Some(Self::render_outline_panel(
|
||||
self.pdf_outline.as_deref(),
|
||||
self.outline_panel_width,
|
||||
cx,
|
||||
))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let has_sidebar = sidebar.is_some();
|
||||
let resize_handle = if self.show_outline_panel {
|
||||
Some(self.render_outline_resize_handle(cx))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
h_flex()
|
||||
.size_full()
|
||||
.when_some(sidebar, |this, sidebar| {
|
||||
this.child(sidebar).child(Divider::vertical())
|
||||
})
|
||||
.when_some(sidebar, |this, sidebar| this.child(sidebar))
|
||||
.when_some(resize_handle, |this, handle| this.child(handle))
|
||||
.when(has_sidebar, |this| this.child(Divider::vertical()))
|
||||
.on_drag_move(cx.listener(
|
||||
|this, event: &DragMoveEvent<OutlinePanelResize>, _, cx| {
|
||||
if let Some((origin_x, origin_width)) =
|
||||
this.outline_resize_origin
|
||||
{
|
||||
let width =
|
||||
origin_width + (event.event.position.x - origin_x);
|
||||
this.outline_panel_width = if width < px(OUTLINE_PANEL_MIN_WIDTH) {
|
||||
px(OUTLINE_PANEL_MIN_WIDTH)
|
||||
} else if width > px(OUTLINE_PANEL_MAX_WIDTH) {
|
||||
px(OUTLINE_PANEL_MAX_WIDTH)
|
||||
} else {
|
||||
width
|
||||
};
|
||||
cx.stop_propagation();
|
||||
cx.notify();
|
||||
}
|
||||
},
|
||||
))
|
||||
.child(div().flex_1().h_full().child(main_pdf_view))
|
||||
.when(self.show_text_panel, |this| {
|
||||
this.child(Divider::vertical()).child(
|
||||
@@ -5301,7 +5384,6 @@ mod tests {
|
||||
assert_eq!(cache.current_memory_bytes(), 0);
|
||||
assert!(cache.is_empty());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
mod persistence {
|
||||
|
||||
Reference in new issue
Block a user