mod core;
mod raw;
pub use self::core::{Core, Scroller};
use crate::event::{Event, EventResult};
use crate::{Printer, Rect, Vec2};
#[derive(Debug)]
pub enum ScrollStrategy {
KeepRow,
StickToTop,
StickToBottom,
}
impl Default for ScrollStrategy {
fn default() -> Self {
ScrollStrategy::KeepRow
}
}
pub fn on_event<T, OnEvent, ImportantArea>(
scroller: &mut T,
event: Event,
on_event: OnEvent,
important_area: ImportantArea,
) -> EventResult
where
T: Scroller,
OnEvent: FnMut(&mut T, Event) -> EventResult,
ImportantArea: FnMut(&T, Vec2) -> Rect,
{
raw::on_event(
event,
scroller,
Scroller::get_scroller_mut,
on_event,
important_area,
)
}
pub fn important_area<T, ImportantArea>(
scroller: &T,
size: Vec2,
mut important_area: ImportantArea,
) -> Rect
where
T: Scroller,
ImportantArea: FnMut(&T, Vec2) -> Rect,
{
let viewport = scroller.get_scroller().content_viewport();
let area = important_area(scroller, size);
let top_left = area.top_left().saturating_sub(viewport.top_left());
let bot_right = area
.bottom_right()
.saturating_sub(viewport.top_left())
.or_min(viewport.bottom_right());
Rect::from_corners(top_left, bot_right)
}
pub fn layout<T, Layout, RequiredSize>(
scroller: &mut T,
size: Vec2,
needs_relayout: bool,
layout: Layout,
required_size: RequiredSize,
) where
T: Scroller,
Layout: FnMut(&mut T, Vec2),
RequiredSize: FnMut(&mut T, Vec2) -> Vec2,
{
raw::layout(
size,
needs_relayout,
scroller,
Scroller::get_scroller_mut,
required_size,
layout,
);
}
pub fn required_size<T, RequiredSize>(
scroller: &mut T,
size: Vec2,
needs_relayout: bool,
required_size: RequiredSize,
) -> Vec2
where
T: Scroller,
RequiredSize: FnMut(&mut T, Vec2) -> Vec2,
{
raw::required_size(
size,
needs_relayout,
scroller,
Scroller::get_scroller_mut,
required_size,
)
}
pub fn draw<T, Draw>(scroller: &T, printer: &Printer, draw: Draw)
where
T: Scroller,
Draw: FnOnce(&T, &Printer),
{
raw::draw(printer, scroller, Scroller::get_scroller, draw);
}
pub fn draw_lines<T, LineDrawer>(
scroller: &T,
printer: &Printer,
mut line_drawer: LineDrawer,
) where
T: Scroller,
LineDrawer: FnMut(&T, &Printer, usize),
{
draw(scroller, printer, |s, printer| {
let start = printer.content_offset.y;
let end = start + printer.output_size.y;
for y in start..end {
let printer = printer.offset((0, y)).cropped((printer.size.x, 1));
line_drawer(s, &printer, y);
}
});
}
pub fn draw_frame<T, LeftBorder, TopBorder, RightBorder, BottomBorder>(
scroller: &T,
printer: &Printer,
mut left_border: LeftBorder,
mut top_border: TopBorder,
mut right_border: RightBorder,
mut bottom_border: BottomBorder,
) where
T: Scroller,
LeftBorder: FnMut(&T, &Printer, usize),
TopBorder: FnMut(&T, &Printer, usize),
RightBorder: FnMut(&T, &Printer, usize),
BottomBorder: FnMut(&T, &Printer, usize),
{
let viewport = scroller.get_scroller().content_viewport();
let size = printer.size.saturating_sub((1, 1));
for (i, x) in (viewport.left()..=viewport.right()).enumerate() {
top_border(scroller, &printer.offset((i + 1, 0)), x);
bottom_border(scroller, &printer.offset((i + 1, size.y)), x);
}
let scrollbar_size = scroller.get_scroller().scrollbar_size();
printer.print_hline((viewport.right() + 2, 0), scrollbar_size.x, "─");
printer.print_hline((viewport.right() + 2, size.y), scrollbar_size.x, "─");
printer.print_vline((0, viewport.bottom() + 2), scrollbar_size.y, "│");
printer.print_vline(
(size.x, viewport.bottom() + 2),
scrollbar_size.y,
"│",
);
for (i, y) in (viewport.top()..=viewport.bottom()).enumerate() {
left_border(scroller, &printer.offset((0, i + 1)), y);
right_border(scroller, &printer.offset((size.x, i + 1)), y);
}
printer.print((0, 0), "┌");
printer.print(size.keep_y(), "└");
printer.print(size.keep_x(), "┐");
printer.print(size, "┘");
}
pub fn draw_box_frame<T, IsHDelim, IsVDelim>(
scroller: &T,
printer: &Printer,
is_h_delim: IsHDelim,
is_v_delim: IsVDelim,
) where
T: Scroller,
IsHDelim: Fn(&T, usize) -> bool,
IsVDelim: Fn(&T, usize) -> bool,
{
draw_frame(
scroller,
printer,
|s, printer, y| {
if is_h_delim(s, y) {
printer.print((0, 0), "├");
} else {
printer.print((0, 0), "│");
}
},
|s, printer, x| {
if is_v_delim(s, x) {
printer.print((0, 0), "┬");
} else {
printer.print((0, 0), "─");
}
},
|s, printer, y| {
if is_h_delim(s, y) {
printer.print((0, 0), "┤");
} else {
printer.print((0, 0), "│");
}
},
|s, printer, x| {
if is_v_delim(s, x) {
printer.print((0, 0), "┴");
} else {
printer.print((0, 0), "─");
}
},
);
}