Show horizontal scrollbar if necessary, related to #59
This commit is contained in:
parent
68dd4c3758
commit
53d7b06926
1 changed files with 146 additions and 23 deletions
169
src/text_box.rs
169
src/text_box.rs
|
|
@ -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),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue