Partially implement scrollbar

This commit is contained in:
Jeremy Soller 2023-11-10 11:20:55 -07:00
parent c66a28320a
commit ac3e7ade96
No known key found for this signature in database
GPG key ID: DCFCA852D3906975
3 changed files with 124 additions and 54 deletions

18
Cargo.lock generated
View file

@ -865,7 +865,7 @@ dependencies = [
[[package]]
name = "cosmic-text"
version = "0.10.0"
source = "git+https://github.com/pop-os/cosmic-text?branch=vi-editor#9efcc41a5aca6df16a66da53aae75b1191ba0576"
source = "git+https://github.com/pop-os/cosmic-text?branch=vi-editor#e8dd8ec7d1a75219980a653998552a78eb9ec0c0"
dependencies = [
"fontdb 0.15.0",
"libm",
@ -874,7 +874,7 @@ dependencies = [
"rangemap",
"rustc-hash",
"rustybuzz 0.11.0",
"self_cell 1.0.1",
"self_cell 1.0.2",
"swash",
"syntect",
"sys-locale",
@ -1206,9 +1206,9 @@ dependencies = [
[[package]]
name = "env_logger"
version = "0.10.0"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0"
checksum = "95b3f3e67048839cb0d0781f445682a35113da7121f7c949db0e2be96a4fbece"
dependencies = [
"humantime",
"is-terminal",
@ -2744,7 +2744,7 @@ dependencies = [
[[package]]
name = "modit"
version = "0.1.0"
source = "git+https://github.com/pop-os/modit.git#0bfedf9b11412b2f3612bdc5ffebcf882f88eb01"
source = "git+https://github.com/pop-os/modit.git#6e8bcf69b7c2790e70c328374811699237520ba1"
dependencies = [
"log",
]
@ -3954,9 +3954,9 @@ checksum = "1ef965a420fe14fdac7dd018862966a4c14094f900e1650bbc71ddd7d580c8af"
[[package]]
name = "self_cell"
version = "1.0.1"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c309e515543e67811222dbc9e3dd7e1056279b782e1dacffe4242b718734fb6"
checksum = "e388332cd64eb80cd595a00941baf513caffae8dce9cfd0467fc9c66397dade6"
[[package]]
name = "serde"
@ -4081,9 +4081,9 @@ dependencies = [
[[package]]
name = "smallvec"
version = "1.11.1"
version = "1.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a"
checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970"
[[package]]
name = "smithay-client-toolkit"

View file

@ -1,5 +1,7 @@
// SPDX-License-Identifier: GPL-3.0-only
//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
use cosmic::{
app::{message, Command, Core, Settings},
cosmic_config::{self, CosmicConfigEntry},
@ -15,9 +17,7 @@ use cosmic::{
};
use cosmic_text::{Cursor, Edit, Family, FontSystem, SwashCache, SyntaxSystem, ViMode};
use std::{
env,
fmt::Write,
fs,
env, fs,
path::{Path, PathBuf},
process,
sync::Mutex,
@ -927,8 +927,7 @@ impl cosmic::Application for App {
}
}
};
tab_column =
tab_column.push(text_box(&tab.editor, self.config.metrics()).padding(8));
tab_column = tab_column.push(text_box(&tab.editor, self.config.metrics()));
tab_column = tab_column.push(text(status).font(cosmic::font::Font::MONOSPACE));
}
None => {

View file

@ -5,13 +5,13 @@ use cosmic::{
event::{Event, Status},
keyboard::{Event as KeyEvent, KeyCode, Modifiers},
mouse::{self, Button, Event as MouseEvent, ScrollDelta},
Color, Element, Length, Padding, Rectangle, Size,
Color, Element, Length, Padding, Point, Rectangle, Size, Vector,
},
iced_core::{
clipboard::Clipboard,
image,
layout::{self, Layout},
renderer,
renderer::{self, Quad},
widget::{self, tree, Widget},
Shell,
},
@ -195,17 +195,32 @@ where
fn mouse_interaction(
&self,
_tree: &widget::Tree,
tree: &widget::Tree,
layout: Layout<'_>,
cursor_position: mouse::Cursor,
_viewport: &Rectangle,
_renderer: &Renderer,
) -> mouse::Interaction {
if cursor_position.is_over(layout.bounds()) {
mouse::Interaction::Text
} else {
mouse::Interaction::Idle
let state = tree.state.downcast_ref::<State>();
match &state.dragging {
Some(Dragging::Scrollbar { .. }) => return mouse::Interaction::Idle,
_ => {}
}
if let Some(p) = cursor_position.position_in(layout.bounds()) {
let scale_factor = state.scale_factor.get();
let editor = self.editor.lock().unwrap();
let buffer_size = editor.buffer().size();
let x = (p.x - self.padding.left) * scale_factor;
let y = (p.y - self.padding.top) * scale_factor;
if x >= 0.0 && x < buffer_size.0 && y >= 0.0 && y < buffer_size.1 {
return mouse::Interaction::Text;
}
}
mouse::Interaction::Idle
}
fn draw(
@ -250,10 +265,12 @@ where
let view_h = cmp::min(viewport.height as i32, layout.bounds().height as i32)
- self.padding.vertical() as i32;
let scale_factor = style.scale_factor;
let scale_factor = style.scale_factor as f32;
let image_w = (view_w as f64 * scale_factor) as i32;
let image_h = (view_h as f64 * scale_factor) as i32;
let image_w = (view_w as f32 * scale_factor) as i32;
let image_h = (view_h as f32 * scale_factor) as i32;
//TODO: make this configurable and do not repeat
let scrollbar_w = (8.0 * scale_factor) as i32;
if image_w <= scrollbar_w || image_h <= 0 {
@ -261,12 +278,15 @@ where
return;
}
// Adjust image width by scrollbar width
let image_w = image_w - scrollbar_w;
let mut font_system = FONT_SYSTEM.lock().unwrap();
let mut editor = editor.borrow_with(&mut font_system);
// Set metrics and size
editor.buffer_mut().set_metrics_and_size(
self.metrics.scale(scale_factor as f32),
self.metrics.scale(scale_factor),
image_w as f32,
image_h as f32,
);
@ -293,7 +313,7 @@ where
},
);
// Draw scrollbar
// Calculate scrollbar
{
let mut start_line_opt = None;
let mut end_line = 0;
@ -308,16 +328,15 @@ where
let lines = editor.buffer().lines.len();
let start_y = (start_line * image_h as usize) / lines;
let end_y = ((end_line * image_h as usize) / lines).max(start_y + 1);
draw_rect(
buffer,
image_w,
image_h,
image_w - scrollbar_w,
start_y as i32,
scrollbar_w,
end_y as i32 - start_y as i32,
0x40FFFFFF,
let rect = Rectangle::new(
[image_w as f32 / scale_factor, start_y as f32 / scale_factor].into(),
Size::new(
scrollbar_w as f32 / scale_factor,
(end_y as f32 - start_y as f32) / scale_factor,
),
);
state.scrollbar_rect.set(rect);
}
}
@ -330,16 +349,35 @@ where
}
let handle = state.handle.lock().unwrap().clone();
let image_position =
layout.position() + [self.padding.left as f32, self.padding.top as f32].into();
let image_size = image::Renderer::dimensions(renderer, &handle);
image::Renderer::draw(
renderer,
handle,
Rectangle::new(
layout.position() + [self.padding.left as f32, self.padding.top as f32].into(),
Size::new(view_w as f32, view_h as f32),
image_position,
Size::new(image_size.width as f32, image_size.height as f32),
),
[0.0; 4],
);
// Draw scrollbar
let scrollbar_alpha = match &state.dragging {
Some(Dragging::Scrollbar { .. }) => 0.5,
_ => 0.25,
};
renderer.fill_quad(
Quad {
bounds: state.scrollbar_rect.get()
+ Vector::new(image_position.x, image_position.y),
border_radius: 0.0.into(),
border_width: 0.0,
border_color: Color::TRANSPARENT,
},
Color::new(1.0, 1.0, 1.0, scrollbar_alpha),
);
let duration = instant.elapsed();
log::debug!("redraw {}, {}: {:?}", view_w, view_h, duration);
}
@ -356,8 +394,10 @@ where
_viewport: &Rectangle<f32>,
) -> Status {
let state = tree.state.downcast_mut::<State>();
let scale_factor = state.scale_factor.get() as f32;
let scale_factor = state.scale_factor.get();
let scrollbar_rect = state.scrollbar_rect.get();
let mut editor = self.editor.lock().unwrap();
let buffer_size = editor.buffer().size();
let mut font_system = FONT_SYSTEM.lock().unwrap();
let mut editor = editor.borrow_with(&mut font_system);
@ -439,27 +479,51 @@ where
}
Event::Mouse(MouseEvent::ButtonPressed(Button::Left)) => {
if let Some(p) = cursor_position.position_in(layout.bounds()) {
editor.action(Action::Click {
x: ((p.x - self.padding.left) * scale_factor) as i32,
y: ((p.y - self.padding.top) * scale_factor) as i32,
});
state.is_dragging = true;
let x = (p.x - self.padding.left) * scale_factor;
let y = (p.y - self.padding.top) * scale_factor;
if x >= 0.0 && x < buffer_size.0 && y >= 0.0 && y < buffer_size.1 {
editor.action(Action::Click {
x: x as i32,
y: y as i32,
});
state.dragging = Some(Dragging::Buffer);
} else if scrollbar_rect.contains(Point::new(x, y)) {
state.dragging = Some(Dragging::Scrollbar {
start_y: y,
start_scroll: editor.buffer().scroll(),
});
}
//TODO: support clicking below or above scrollbar
status = Status::Captured;
}
}
Event::Mouse(MouseEvent::ButtonReleased(Button::Left)) => {
state.is_dragging = false;
state.dragging = None;
status = Status::Captured;
}
Event::Mouse(MouseEvent::CursorMoved { .. }) => {
if state.is_dragging {
if let Some(dragging) = &state.dragging {
if let Some(p) = cursor_position.position() {
editor.action(Action::Drag {
x: (((p.x - layout.bounds().x) - self.padding.left) * scale_factor)
as i32,
y: (((p.y - layout.bounds().y) - self.padding.top) * scale_factor)
as i32,
});
let x = ((p.x - layout.bounds().x) - self.padding.left) * scale_factor;
let y = ((p.y - layout.bounds().y) - self.padding.top) * scale_factor;
match dragging {
Dragging::Buffer => {
editor.action(Action::Drag {
x: x as i32,
y: y as i32,
});
}
Dragging::Scrollbar {
start_y,
start_scroll,
} => {
let mut buffer = editor.buffer_mut();
let scroll_offset = (((y - start_y) / buffer.size().1)
* buffer.lines.len() as f32)
as i32;
buffer.set_scroll(start_scroll + scroll_offset);
}
}
}
status = Status::Captured;
}
@ -490,10 +554,16 @@ where
}
}
enum Dragging {
Buffer,
Scrollbar { start_y: f32, start_scroll: i32 },
}
pub struct State {
modifiers: Modifiers,
is_dragging: bool,
scale_factor: Cell<f64>,
dragging: Option<Dragging>,
scale_factor: Cell<f32>,
scrollbar_rect: Cell<Rectangle<f32>>,
handle: Mutex<image::Handle>,
}
@ -502,8 +572,9 @@ impl State {
pub fn new() -> State {
State {
modifiers: Modifiers::empty(),
is_dragging: false,
dragging: None,
scale_factor: Cell::new(1.0),
scrollbar_rect: Cell::new(Rectangle::default()),
//TODO: make option!
handle: Mutex::new(image::Handle::from_pixels(1, 1, vec![0, 0, 0, 0])),
}