You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
gobang/src/ui/scrollbar.rs

90 lines
2.1 KiB
Rust

use easy_cast::CastFloat;
use std::convert::TryFrom;
use tui::{
backend::Backend,
buffer::Buffer,
layout::{Margin, Rect},
style::{Color, Style},
symbols::{block::FULL, line::DOUBLE_VERTICAL},
widgets::Widget,
Frame,
};
struct Scrollbar {
max: u16,
pos: u16,
style_bar: Style,
style_pos: Style,
inside: bool,
border: bool,
}
impl Scrollbar {
fn new(max: usize, pos: usize, border: bool, inside: bool) -> Self {
Self {
max: u16::try_from(max).unwrap_or_default(),
pos: u16::try_from(pos).unwrap_or_default(),
style_pos: Style::default(),
style_bar: Style::default(),
inside,
border,
}
}
}
impl Widget for Scrollbar {
fn render(self, area: Rect, buf: &mut Buffer) {
if area.height <= 2 {
return;
}
if self.max == 0 {
return;
}
let right = if self.inside {
area.right().saturating_sub(1)
} else {
area.right()
};
if right <= area.left() {
return;
};
let (bar_top, bar_height) = {
let scrollbar_area = area.inner(&Margin {
horizontal: 0,
vertical: if self.border { 1 } else { 0 },
});
(scrollbar_area.top(), scrollbar_area.height)
};
for y in bar_top..(bar_top + bar_height) {
buf.set_string(right, y, DOUBLE_VERTICAL, self.style_bar);
}
let progress = f32::from(self.pos) / f32::from(self.max);
let progress = if progress > 1.0 { 1.0 } else { progress };
let pos = f32::from(bar_height) * progress;
let pos: u16 = pos.cast_nearest();
let pos = pos.saturating_sub(1);
buf.set_string(right, bar_top + pos, FULL, self.style_pos);
}
}
pub fn draw_scrollbar<B: Backend>(
f: &mut Frame<B>,
r: Rect,
max: usize,
pos: usize,
border: bool,
inside: bool,
) {
let mut widget = Scrollbar::new(max, pos, border, inside);
widget.style_pos = Style::default().fg(Color::Blue);
f.render_widget(widget, r);
}