2016-06-28 05:10:59 +00:00
|
|
|
use std::cmp::{max, min};
|
2015-05-31 23:38:53 +00:00
|
|
|
|
2015-06-06 01:08:05 +00:00
|
|
|
use theme::ColorPair;
|
2015-05-31 23:38:53 +00:00
|
|
|
use vec::Vec2;
|
|
|
|
use printer::Printer;
|
|
|
|
|
2015-05-31 23:58:55 +00:00
|
|
|
/// Provide scrolling functionalities to a view.
|
2016-06-28 05:40:11 +00:00
|
|
|
#[derive(Default)]
|
2015-05-31 23:38:53 +00:00
|
|
|
pub struct ScrollBase {
|
|
|
|
pub start_line: usize,
|
|
|
|
pub content_height: usize,
|
|
|
|
pub view_height: usize,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ScrollBase {
|
|
|
|
pub fn new() -> Self {
|
|
|
|
ScrollBase {
|
|
|
|
start_line: 0,
|
|
|
|
content_height: 0,
|
|
|
|
view_height: 0,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-31 23:58:55 +00:00
|
|
|
/// Call this method whem the content or the view changes.
|
2015-05-31 23:38:53 +00:00
|
|
|
pub fn set_heights(&mut self, view_height: usize, content_height: usize) {
|
|
|
|
self.view_height = view_height;
|
|
|
|
self.content_height = content_height;
|
|
|
|
|
|
|
|
if self.scrollable() {
|
2016-06-28 05:10:59 +00:00
|
|
|
self.start_line = min(self.start_line,
|
|
|
|
self.content_height - self.view_height);
|
2015-05-31 23:38:53 +00:00
|
|
|
} else {
|
|
|
|
self.start_line = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-31 23:58:55 +00:00
|
|
|
/// Returns `TRUE` if the view needs to scroll.
|
2015-05-31 23:38:53 +00:00
|
|
|
pub fn scrollable(&self) -> bool {
|
|
|
|
self.view_height < self.content_height
|
|
|
|
}
|
|
|
|
|
2015-05-31 23:58:55 +00:00
|
|
|
/// Returns `TRUE` unless we are at the top.
|
2015-05-31 23:38:53 +00:00
|
|
|
pub fn can_scroll_up(&self) -> bool {
|
|
|
|
self.start_line > 0
|
|
|
|
}
|
|
|
|
|
2015-05-31 23:58:55 +00:00
|
|
|
/// Returns `TRUE` unless we are at the bottom.
|
2015-05-31 23:38:53 +00:00
|
|
|
pub fn can_scroll_down(&self) -> bool {
|
|
|
|
self.start_line + self.view_height < self.content_height
|
|
|
|
}
|
|
|
|
|
2015-05-31 23:58:55 +00:00
|
|
|
/// Scroll to the top of the view.
|
2015-05-31 23:38:53 +00:00
|
|
|
pub fn scroll_top(&mut self) {
|
|
|
|
self.start_line = 0;
|
|
|
|
}
|
|
|
|
|
2015-05-31 23:58:55 +00:00
|
|
|
/// Makes sure that the given line is visible, scrolling if needed.
|
2015-05-31 23:38:53 +00:00
|
|
|
pub fn scroll_to(&mut self, y: usize) {
|
|
|
|
if y >= self.start_line + self.view_height {
|
|
|
|
self.start_line = 1 + y - self.view_height;
|
|
|
|
} else if y < self.start_line {
|
|
|
|
self.start_line = y;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-31 23:58:55 +00:00
|
|
|
/// Scroll to the bottom of the view.
|
2015-05-31 23:38:53 +00:00
|
|
|
pub fn scroll_bottom(&mut self) {
|
|
|
|
self.start_line = self.content_height - self.view_height;
|
|
|
|
}
|
|
|
|
|
2015-05-31 23:58:55 +00:00
|
|
|
/// Scroll down by the given number of line, never going further than the bottom of the view.
|
2015-05-31 23:38:53 +00:00
|
|
|
pub fn scroll_down(&mut self, n: usize) {
|
2016-06-28 05:10:59 +00:00
|
|
|
self.start_line = min(self.start_line + n,
|
|
|
|
self.content_height - self.view_height);
|
2015-05-31 23:38:53 +00:00
|
|
|
}
|
|
|
|
|
2015-05-31 23:58:55 +00:00
|
|
|
/// Scroll up by the given number of lines, never going above the top of the view.
|
2015-05-31 23:38:53 +00:00
|
|
|
pub fn scroll_up(&mut self, n: usize) {
|
|
|
|
self.start_line -= min(self.start_line, n);
|
|
|
|
}
|
|
|
|
|
2015-05-31 23:58:55 +00:00
|
|
|
/// Draws the scroll bar and the content using the given drawer.
|
|
|
|
///
|
|
|
|
/// `line_drawer` will be called once for each line that needs to be drawn.
|
|
|
|
/// It will be given the absolute ID of the item to draw..
|
|
|
|
/// It will also be given a printer with the correct offset,
|
|
|
|
/// so it should only print on the first line.
|
|
|
|
///
|
|
|
|
/// # Examples
|
|
|
|
///
|
|
|
|
/// ```
|
2015-06-04 18:40:35 +00:00
|
|
|
/// # use cursive::view::ScrollBase;
|
|
|
|
/// # use cursive::printer::Printer;
|
2015-06-06 01:08:05 +00:00
|
|
|
/// # use cursive::theme;
|
2015-06-04 18:40:35 +00:00
|
|
|
/// # let scrollbase = ScrollBase::new();
|
2015-06-06 01:08:05 +00:00
|
|
|
/// # let printer = Printer::new((5,1), theme::load_default());
|
2015-06-04 18:40:35 +00:00
|
|
|
/// # let printer = &printer;
|
|
|
|
/// let lines = ["Line 1", "Line number 2"];
|
2015-05-31 23:58:55 +00:00
|
|
|
/// scrollbase.draw(printer, |printer, i| {
|
|
|
|
/// printer.print((0,0), lines[i]);
|
|
|
|
/// });
|
|
|
|
/// ```
|
2015-05-31 23:38:53 +00:00
|
|
|
pub fn draw<F>(&self, printer: &Printer, line_drawer: F)
|
2016-03-15 22:37:57 +00:00
|
|
|
where F: Fn(&Printer, usize)
|
2015-05-31 23:38:53 +00:00
|
|
|
{
|
2015-05-31 23:58:55 +00:00
|
|
|
// Print the content in a sub_printer
|
2016-06-28 05:10:59 +00:00
|
|
|
let max_y = min(self.view_height,
|
|
|
|
self.content_height - self.start_line);
|
2016-03-15 22:37:57 +00:00
|
|
|
let w = if self.scrollable() {
|
|
|
|
printer.size.x - 2
|
|
|
|
} else {
|
|
|
|
printer.size.x
|
|
|
|
};
|
2015-05-31 23:58:55 +00:00
|
|
|
for y in 0..max_y {
|
|
|
|
// Y is the actual coordinate of the line.
|
|
|
|
// The item ID is then Y + self.start_line
|
2016-06-28 05:10:59 +00:00
|
|
|
line_drawer(&printer.sub_printer(Vec2::new(0, y),
|
|
|
|
Vec2::new(w, 1),
|
|
|
|
true),
|
2016-03-15 22:37:57 +00:00
|
|
|
y + self.start_line);
|
2015-05-31 23:38:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-05-31 23:58:55 +00:00
|
|
|
// And draw the scrollbar if needed
|
2015-05-31 23:38:53 +00:00
|
|
|
if self.view_height < self.content_height {
|
|
|
|
// We directly compute the size of the scrollbar (this allow use to avoid using floats).
|
|
|
|
// (ratio) * max_height
|
|
|
|
// Where ratio is ({start or end} / content.height)
|
2016-06-28 05:10:59 +00:00
|
|
|
let height = max(1,
|
|
|
|
self.view_height * self.view_height /
|
|
|
|
self.content_height);
|
2015-05-31 23:38:53 +00:00
|
|
|
// Number of different possible positions
|
|
|
|
let steps = self.view_height - height + 1;
|
|
|
|
|
|
|
|
// Now
|
2016-06-28 05:10:59 +00:00
|
|
|
let start = steps * self.start_line /
|
|
|
|
(1 + self.content_height - self.view_height);
|
2015-05-31 23:38:53 +00:00
|
|
|
|
2016-03-15 22:37:57 +00:00
|
|
|
let color = if printer.focused {
|
|
|
|
ColorPair::Highlight
|
|
|
|
} else {
|
|
|
|
ColorPair::HighlightInactive
|
|
|
|
};
|
2015-06-03 00:44:31 +00:00
|
|
|
|
2016-06-26 22:03:12 +00:00
|
|
|
printer.print_vline((printer.size.x - 1, 0), printer.size.y, "|");
|
2015-06-03 00:44:31 +00:00
|
|
|
printer.with_color(color, |printer| {
|
2016-06-26 22:03:12 +00:00
|
|
|
printer.print_vline((printer.size.x - 1, start), height, " ");
|
2015-06-03 00:44:31 +00:00
|
|
|
});
|
2015-05-31 23:38:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|