Show horizontal scrollbar if necessary, related to #59

This commit is contained in:
Jeremy Soller 2024-05-30 15:36:53 -06:00
parent 68dd4c3758
commit 53d7b06926
No known key found for this signature in database
GPG key ID: D02FD439211AF56F

View file

@ -282,7 +282,7 @@ where
) -> mouse::Interaction { ) -> mouse::Interaction {
let state = tree.state.downcast_ref::<State>(); let state = tree.state.downcast_ref::<State>();
if let Some(Dragging::Scrollbar { .. }) = &state.dragging { if let Some(Dragging::ScrollbarV { .. }) = &state.dragging {
return mouse::Interaction::Idle; return mouse::Interaction::Idle;
} }
@ -597,11 +597,15 @@ where
editor.with_buffer(|buffer| { editor.with_buffer(|buffer| {
let mut start_line_opt = None; let mut start_line_opt = None;
let mut end_line = 0; let mut end_line = 0;
let mut max_line_width = 0.0;
for run in buffer.layout_runs() { for run in buffer.layout_runs() {
end_line = run.line_i; end_line = run.line_i;
if start_line_opt.is_none() { if start_line_opt.is_none() {
start_line_opt = Some(end_line); start_line_opt = Some(end_line);
} }
if run.line_w > max_line_width {
max_line_width = run.line_w;
}
} }
let start_line = start_line_opt.unwrap_or(end_line); let start_line = start_line_opt.unwrap_or(end_line);
@ -616,7 +620,26 @@ where
(end_y as f32 - start_y as f32) / scale_factor, (end_y as f32 - start_y as f32) / scale_factor,
), ),
); );
state.scrollbar_rect.set(rect); state.scrollbar_v_rect.set(rect);
if (image_w as f32) < max_line_width {
let rect = Rectangle::new(
[
(scroll_x as f32 / max_line_width as f32) * image_w as f32
/ scale_factor,
image_h as f32 / scale_factor,
]
.into(),
Size::new(
(image_w as f32 / max_line_width as f32) * image_w as f32
/ scale_factor,
scrollbar_w as f32,
),
);
state.scrollbar_h_rect.set(Some(rect));
} else {
state.scrollbar_h_rect.set(None);
}
}); });
} }
@ -650,9 +673,9 @@ where
); );
} }
// Draw scrollbar // Draw vertical scrollbar
{ {
let scrollbar_rect = state.scrollbar_rect.get(); let scrollbar_v_rect = state.scrollbar_v_rect.get();
// neutral_3, 0.7 // neutral_3, 0.7
let track_color = cosmic_theme let track_color = cosmic_theme
@ -665,11 +688,11 @@ where
renderer.fill_quad( renderer.fill_quad(
Quad { Quad {
bounds: Rectangle::new( bounds: Rectangle::new(
Point::new(image_position.x + scrollbar_rect.x, image_position.y), Point::new(image_position.x + scrollbar_v_rect.x, image_position.y),
Size::new(scrollbar_rect.width, layout.bounds().height), Size::new(scrollbar_v_rect.width, layout.bounds().height),
), ),
border: Border { border: Border {
radius: (scrollbar_rect.width / 2.0).into(), radius: (scrollbar_v_rect.width / 2.0).into(),
width: 0.0, width: 0.0,
color: Color::TRANSPARENT, color: Color::TRANSPARENT,
}, },
@ -678,18 +701,18 @@ where
Color::from(track_color), Color::from(track_color),
); );
let pressed = matches!(&state.dragging, Some(Dragging::Scrollbar { .. })); let pressed = matches!(&state.dragging, Some(Dragging::ScrollbarV { .. }));
let mut hover = false; let mut hover = false;
if let Some(p) = cursor_position.position_in(layout.bounds()) { if let Some(p) = cursor_position.position_in(layout.bounds()) {
let x = p.x - self.padding.left; let x = p.x - self.padding.left;
if x >= scrollbar_rect.x && x < (scrollbar_rect.x + scrollbar_rect.width) { if x >= scrollbar_v_rect.x && x < (scrollbar_v_rect.x + scrollbar_v_rect.width) {
hover = true; hover = true;
} }
} }
let mut scrollbar_draw = let mut scrollbar_draw =
scrollbar_rect + Vector::new(image_position.x, image_position.y); scrollbar_v_rect + Vector::new(image_position.x, image_position.y);
if !hover && !pressed { if !hover && !pressed {
// Decrease draw width and keep centered when not hovered or pressed // Decrease draw width and keep centered when not hovered or pressed
scrollbar_draw.width /= 2.0; scrollbar_draw.width /= 2.0;
@ -739,6 +762,94 @@ where
); );
} }
// Draw horizontal scrollbar
//TODO: reduce repitition
if let Some(scrollbar_h_rect) = state.scrollbar_h_rect.get() {
// neutral_3, 0.7
let track_color = cosmic_theme
.palette
.neutral_3
.without_alpha()
.with_alpha(0.7);
// Draw track quad
renderer.fill_quad(
Quad {
bounds: Rectangle::new(
Point::new(image_position.x, image_position.y + scrollbar_h_rect.y),
Size::new(layout.bounds().width, scrollbar_h_rect.height),
),
border: Border {
radius: (scrollbar_h_rect.height / 2.0).into(),
width: 0.0,
color: Color::TRANSPARENT,
},
..Default::default()
},
Color::from(track_color),
);
let pressed = matches!(&state.dragging, Some(Dragging::ScrollbarH { .. }));
let mut hover = false;
if let Some(p) = cursor_position.position_in(layout.bounds()) {
let y = p.y - self.padding.top;
if y >= scrollbar_h_rect.y && y < (scrollbar_h_rect.y + scrollbar_h_rect.height) {
hover = true;
}
}
let mut scrollbar_draw =
scrollbar_h_rect + Vector::new(image_position.x, image_position.y);
if !hover && !pressed {
// Decrease draw width and keep centered when not hovered or pressed
scrollbar_draw.height /= 2.0;
scrollbar_draw.y += scrollbar_draw.height / 2.0;
}
// neutral_6, 0.7
let base_color = cosmic_theme
.palette
.neutral_6
.without_alpha()
.with_alpha(0.7);
let scrollbar_color = if pressed {
// pressed_state_color, 0.5
cosmic_theme
.background
.component
.pressed
.without_alpha()
.with_alpha(0.5)
.over(base_color)
} else if hover {
// hover_state_color, 0.2
cosmic_theme
.background
.component
.hover
.without_alpha()
.with_alpha(0.2)
.over(base_color)
} else {
base_color
};
// Draw scrollbar quad
renderer.fill_quad(
Quad {
bounds: scrollbar_draw,
border: Border {
radius: (scrollbar_draw.height / 2.0).into(),
width: 0.0,
color: Color::TRANSPARENT,
},
..Default::default()
},
Color::from(scrollbar_color),
);
}
let duration = instant.elapsed(); let duration = instant.elapsed();
log::debug!("redraw {}, {}: {:?}", view_w, view_h, duration); log::debug!("redraw {}, {}: {:?}", view_w, view_h, duration);
} }
@ -757,9 +868,10 @@ where
let state = tree.state.downcast_mut::<State>(); let state = tree.state.downcast_mut::<State>();
let editor_offset_x = state.editor_offset_x.get(); let editor_offset_x = state.editor_offset_x.get();
let scale_factor = state.scale_factor.get(); let scale_factor = state.scale_factor.get();
let scrollbar_rect = state.scrollbar_rect.get(); let scrollbar_v_rect = state.scrollbar_v_rect.get();
let mut editor = self.editor.lock().unwrap(); let mut editor = self.editor.lock().unwrap();
let buffer_size = editor.with_buffer(|buffer| buffer.size()); let (buffer_size, buffer_scroll) =
editor.with_buffer(|buffer| (buffer.size(), buffer.scroll()));
let last_changed = editor.changed(); let last_changed = editor.changed();
let mut font_system = font_system().write().unwrap(); let mut font_system = font_system().write().unwrap();
let mut editor = editor.borrow_with(font_system.raw()); let mut editor = editor.borrow_with(font_system.raw());
@ -884,9 +996,10 @@ where
if let Button::Left = button { if let Button::Left = button {
let x_logical = p.x - self.padding.left; let x_logical = p.x - self.padding.left;
let y_logical = p.y - self.padding.top; let y_logical = p.y - self.padding.top;
let x = x_logical * scale_factor - editor_offset_x as f32; let mut x = x_logical * scale_factor - editor_offset_x as f32;
let y = y_logical * scale_factor; let y = y_logical * scale_factor;
if x >= 0.0 && x < buffer_size.0 && y >= 0.0 && y < buffer_size.1 { if x >= 0.0 && x < buffer_size.0 && y >= 0.0 && y < buffer_size.1 {
x += buffer_scroll.horizontal;
let click_kind = let click_kind =
if let Some((click_kind, click_time)) = state.click.take() { if let Some((click_kind, click_time)) = state.click.take() {
if click_time.elapsed() < self.click_timing { if click_time.elapsed() < self.click_timing {
@ -917,13 +1030,13 @@ where
} }
state.click = Some((click_kind, Instant::now())); state.click = Some((click_kind, Instant::now()));
state.dragging = Some(Dragging::Buffer); state.dragging = Some(Dragging::Buffer);
} else if scrollbar_rect.contains(Point::new(x_logical, y_logical)) { } else if scrollbar_v_rect.contains(Point::new(x_logical, y_logical)) {
state.dragging = Some(Dragging::Scrollbar { state.dragging = Some(Dragging::ScrollbarV {
start_y: y, start_y: y,
start_scroll: editor.with_buffer(|buffer| buffer.scroll()), start_scroll: editor.with_buffer(|buffer| buffer.scroll()),
}); });
} else if x_logical >= scrollbar_rect.x } else if x_logical >= scrollbar_v_rect.x
&& x_logical < (scrollbar_rect.x + scrollbar_rect.width) && x_logical < (scrollbar_v_rect.x + scrollbar_v_rect.width)
{ {
editor.with_buffer_mut(|buffer| { editor.with_buffer_mut(|buffer| {
let mut scroll = buffer.scroll(); let mut scroll = buffer.scroll();
@ -931,7 +1044,7 @@ where
((y / buffer.size().1) * buffer.lines.len() as f32) as i32; ((y / buffer.size().1) * buffer.lines.len() as f32) as i32;
scroll.line = scroll_line.try_into().unwrap_or_default(); scroll.line = scroll_line.try_into().unwrap_or_default();
buffer.set_scroll(scroll); buffer.set_scroll(scroll);
state.dragging = Some(Dragging::Scrollbar { state.dragging = Some(Dragging::ScrollbarV {
start_y: y, start_y: y,
start_scroll: buffer.scroll(), start_scroll: buffer.scroll(),
}); });
@ -963,16 +1076,17 @@ where
if let Some(p) = cursor_position.position() { if let Some(p) = cursor_position.position() {
let x_logical = (p.x - layout.bounds().x) - self.padding.left; let x_logical = (p.x - layout.bounds().x) - self.padding.left;
let y_logical = (p.y - layout.bounds().y) - self.padding.top; let y_logical = (p.y - layout.bounds().y) - self.padding.top;
let x = x_logical * scale_factor - editor_offset_x as f32; let mut x = x_logical * scale_factor - editor_offset_x as f32;
let y = y_logical * scale_factor; let y = y_logical * scale_factor;
match dragging { match dragging {
Dragging::Buffer => { Dragging::Buffer => {
x += buffer_scroll.horizontal;
editor.action(Action::Drag { editor.action(Action::Drag {
x: x as i32, x: x as i32,
y: y as i32, y: y as i32,
}); });
} }
Dragging::Scrollbar { Dragging::ScrollbarV {
start_y, start_y,
start_scroll, start_scroll,
} => { } => {
@ -987,6 +1101,12 @@ where
buffer.set_scroll(scroll); buffer.set_scroll(scroll);
}); });
} }
Dragging::ScrollbarH {
start_x,
start_scroll,
} => {
//TODO: horizontal scrollbar drag
}
} }
} }
status = Status::Captured; status = Status::Captured;
@ -1055,7 +1175,8 @@ enum ClickKind {
enum Dragging { enum Dragging {
Buffer, Buffer,
Scrollbar { start_y: f32, start_scroll: Scroll }, ScrollbarV { start_y: f32, start_scroll: Scroll },
ScrollbarH { start_x: f32, start_scroll: Scroll },
} }
pub struct State { pub struct State {
@ -1066,7 +1187,8 @@ pub struct State {
is_focused: bool, is_focused: bool,
scale_factor: Cell<f32>, scale_factor: Cell<f32>,
scroll_pixels: f32, scroll_pixels: f32,
scrollbar_rect: Cell<Rectangle<f32>>, scrollbar_v_rect: Cell<Rectangle<f32>>,
scrollbar_h_rect: Cell<Option<Rectangle<f32>>>,
handle_opt: Mutex<Option<image::Handle>>, handle_opt: Mutex<Option<image::Handle>>,
} }
@ -1081,7 +1203,8 @@ impl State {
is_focused: false, is_focused: false,
scale_factor: Cell::new(1.0), scale_factor: Cell::new(1.0),
scroll_pixels: 0.0, scroll_pixels: 0.0,
scrollbar_rect: Cell::new(Rectangle::default()), scrollbar_v_rect: Cell::new(Rectangle::default()),
scrollbar_h_rect: Cell::new(None),
handle_opt: Mutex::new(None), handle_opt: Mutex::new(None),
} }
} }