Split Printer::sub_printer into sub-methods

This commit is contained in:
Alexandre Bury 2018-04-03 16:38:54 -07:00
parent 4042a45b8d
commit 8641098781
14 changed files with 112 additions and 69 deletions

View File

@ -537,7 +537,7 @@ impl Cursive {
1
};
let id = self.active_screen;
let sv_printer = printer.offset((0, offset), !selected);
let sv_printer = printer.offset((0, offset)).focused(!selected);
self.screens[id].draw_bg(&sv_printer);
@ -545,11 +545,7 @@ impl Cursive {
// If the menubar is active, nothing else can be.
// Draw the menubar?
if self.menubar.visible() {
let printer = printer.sub_printer(
Vec2::zero(),
printer.size,
self.menubar.receive_events(),
);
let printer = printer.focused(self.menubar.receive_events());
self.menubar.draw(&printer);
}

View File

@ -9,6 +9,7 @@ use theme::{BorderStyle, ColorStyle, Effect, PaletteColor, Style, Theme};
use unicode_segmentation::UnicodeSegmentation;
use utils::lines::simple::prefix;
use vec::Vec2;
use with::With;
/// Convenient interface to draw on a subset of the screen.
pub struct Printer<'a> {
@ -36,6 +37,20 @@ pub struct Printer<'a> {
backend: &'a backend::Concrete,
}
impl<'a> Clone for Printer<'a> {
fn clone(&self) -> Self {
Printer {
offset: self.offset,
content_offset: self.content_offset,
size: self.size,
focused: self.focused,
theme: self.theme,
backend: self.backend,
new: Rc::clone(&self.new),
}
}
}
impl<'a> Printer<'a> {
/// Creates a new printer on the given window.
///
@ -308,37 +323,73 @@ impl<'a> Printer<'a> {
}
/// Prints a horizontal delimiter with side border `├` and `┤`.
pub fn print_hdelim<T: Into<Vec2>>(&self, start: T, len: usize) {
pub fn print_hdelim<T>(&self, start: T, len: usize)
where
T: Into<Vec2>,
{
let start = start.into();
self.print(start, "");
self.print_hline(start + (1, 0), len.saturating_sub(2), "");
self.print(start + (len.saturating_sub(1), 0), "");
}
/// Returns a printer on a subset of this one's area.
pub fn sub_printer<S: Into<Vec2>, T: Into<Vec2>>(
&'a self, offset: S, size: T, focused: bool
) -> Printer<'a> {
let size = size.into();
let offset = offset.into().or_min(self.size);
let available = if !offset.fits_in(self.size) {
Vec2::zero()
} else {
Vec2::min(self.size - offset, size)
};
Printer {
offset: self.offset + offset,
// We can't be larger than what remains
size: available,
focused: self.focused && focused,
theme: self.theme,
backend: self.backend,
new: Rc::clone(&self.new),
}
/// Returns a sub-printer with the given offset.
pub fn offset<S>(&self, offset: S) -> Printer
where
S: Into<Vec2>,
{
let offset = offset.into();
self.clone().with(|s| {
let consumed = Vec2::min(s.content_offset, offset);
s.content_offset = s.content_offset - consumed;
s.offset = s.offset + offset - consumed;
s.size = s.size.saturating_sub(offset);
})
}
/// Returns a sub-printer with the given offset.
pub fn offset<S: Into<Vec2>>(&self, offset: S, focused: bool) -> Printer {
self.sub_printer(offset, self.size, focused)
/// Returns a new sub-printer inheriting the given focus.
///
/// If `self` is focused and `focused == true`, the child will be focused.
///
/// Otherwise, he will be unfocused.
pub fn focused(&self, focused: bool) -> Self {
self.clone().with(|s| {
s.focused &= focused;
})
}
/// Returns a new sub-printer with a cropped area.
///
/// The new printer size will be the minimum of `size` and its current size.
///
/// Any size reduction happens at the bottom-right.
pub fn cropped<S>(&self, size: S) -> Self
where
S: Into<Vec2>,
{
self.clone().with(|s| {
s.size = Vec2::min(s.size, size);
})
}
/// Returns a new sub-printer with a shrinked area.
///
/// The printer size will be reduced by the given border from the bottom-right.
pub fn shrinked<S>(&self, borders: S) -> Self
where
S: Into<Vec2>,
{
self.cropped(self.size.saturating_sub(borders))
}
/// Returns a new sub-printer with a content offset.
pub fn content_offset<S>(&self, offset: S) -> Self
where
S: Into<Vec2>,
{
self.clone().with(|s| {
s.content_offset = s.content_offset + offset;
})
}
}

View File

@ -269,7 +269,7 @@ impl ScrollBase {
// Y is the actual coordinate of the line.
// The item ID is then Y + self.start_line
line_drawer(
&printer.sub_printer(Vec2::new(0, y), Vec2::new(w, 1), true),
&printer.offset((0, y)).cropped((w, 1)),
y + self.start_line,
);
}

View File

@ -371,11 +371,10 @@ impl Dialog {
// Add some special effect to the focused button
let position = Vec2::new(offset, y);
button.offset.set(position);
button.button.draw(&printer.sub_printer(
position,
size,
self.focus == DialogFocus::Button(i),
));
button.button.draw(&printer
.offset(position)
.cropped(size)
.focused(self.focus == DialogFocus::Button(i)));
// Keep 1 blank between two buttons
offset += size.x + 1;
// Also keep 1 blank above the buttons
@ -395,11 +394,10 @@ impl Dialog {
None => return,
};
self.content.draw(&printer.sub_printer(
self.borders.top_left() + self.padding.top_left(),
inner_size,
self.focus == DialogFocus::Content,
));
self.content.draw(&printer
.offset(self.borders.top_left() + self.padding.top_left())
.cropped(inner_size)
.focused(self.focus == DialogFocus::Content));
}
fn draw_title(&self, printer: &Printer) {

View File

@ -327,11 +327,10 @@ impl View for LinearLayout {
// eprintln!("Printer size: {:?}", printer.size);
// eprintln!("Child size: {:?}", item.child.size);
// eprintln!("Offset: {:?}", item.offset);
let printer = &printer.sub_printer(
self.orientation.make_vec(item.offset, 0),
item.child.size,
i == self.focus,
);
let printer = &printer
.offset(self.orientation.make_vec(item.offset, 0))
.cropped(item.child.size)
.focused(i == self.focus);
item.child.view.draw(printer);
}
}

View File

@ -279,7 +279,9 @@ impl View for ListView {
.draw(printer, |printer, i| match self.children[i] {
ListChild::Row(ref label, ref view) => {
printer.print((0, 0), label);
view.draw(&printer.offset((offset, 0), i == self.focus));
view.draw(&printer
.offset((offset, 0))
.focused(i == self.focus));
}
ListChild::Delimiter => (),
});

View File

@ -211,7 +211,7 @@ impl View for MenuPopup {
let h = self.menu.len();
// If we're too high, add a vertical offset
let offset = self.align.v.get_offset(h, printer.size.y);
let printer = &printer.offset((0, offset), true);
let printer = &printer.offset((0, offset));
// Start with a box
printer.print_box(Vec2::new(0, 0), printer.size, false);
@ -219,8 +219,7 @@ impl View for MenuPopup {
// We're giving it a reduced size because of borders.
// But we're keeping the full width,
// to integrate horizontal delimiters in the frame.
let size = printer.size - (0, 2);
let printer = printer.sub_printer((0, 1), size, true);
let printer = printer.offset((0, 1)).shrinked((0, 1));
self.scrollbase.draw(&printer, |printer, i| {
printer.with_selection(i == self.focus, |printer| {

View File

@ -35,8 +35,7 @@ impl<V: View> ViewWrapper for Panel<V> {
fn wrap_draw(&self, printer: &Printer) {
printer.print_box((0, 0), printer.size, true);
let size = printer.size.saturating_sub((2, 2));
let printer = printer.sub_printer((1, 1), size, true);
let printer = printer.offset((1, 1)).shrinked((1, 1));
self.view.draw(&printer);
}

View File

@ -215,7 +215,7 @@ impl View for ProgressBar {
printer.with_effect(Effect::Reverse, |printer| {
printer.print((offset, 0), &label);
});
let printer = &printer.sub_printer((0, 0), (length, 1), true);
let printer = &printer.cropped((length, 1));
printer.print_hline((0, 0), length, " ");
printer.print((offset, 0), &label);
});

View File

@ -6,12 +6,17 @@ use vec::Vec2;
pub struct ScrollView<V> {
inner: V,
offset: Vec2,
// Togglable horizontal/vertical scrolling?
}
impl <V> View for ScrollView<V> where V: View {
fn draw(&self, printer: &Printer) {
self.printer.offset
self.inner.draw(printer);
// Draw content
let printer = printer.content_offset(self.offset);
self.inner.draw(&printer);
// Draw scrollbar?
}
}

View File

@ -703,8 +703,7 @@ impl<T: 'static> View for SelectView<T> {
} else {
let h = self.items.len();
let offset = self.align.v.get_offset(h, printer.size.y);
let printer =
&printer.sub_printer(Vec2::new(0, offset), printer.size, true);
let printer = &printer.offset((0, offset));
self.scrollbase.draw(printer, |printer, i| {
printer.with_selection(i == self.focus(), |printer| {

View File

@ -86,7 +86,7 @@ impl<T: View> ViewWrapper for ShadowView<T> {
self.left_padding as usize,
self.top_padding as usize,
);
let printer = &printer.offset(offset, true);
let printer = &printer.offset(offset);
if printer.theme.shadow {
let h = printer.size.y;
let w = printer.size.x;
@ -102,11 +102,7 @@ impl<T: View> ViewWrapper for ShadowView<T> {
}
// Draw the view background
let printer = printer.sub_printer(
Vec2::zero(),
printer.size.saturating_sub((1, 1)),
true,
);
let printer = printer.shrinked((1,1));
self.view.draw(&printer);
}
}

View File

@ -420,11 +420,10 @@ impl StackView {
StackPositionIterator::new(self.layers.iter(), printer.size)
.enumerate()
{
v.view.draw(&printer.sub_printer(
offset,
v.size,
i + 1 == last,
));
v.view.draw(&printer
.offset(offset)
.cropped(v.size)
.focused(i + 1 == last));
}
});
}

View File

@ -455,7 +455,7 @@ impl View for TextView {
let h = self.rows.len();
// If the content is smaller than the view, align it somewhere.
let offset = self.align.v.get_offset(h, printer.size.y);
let printer = &printer.offset((0, offset), true);
let printer = &printer.offset((0, offset));
let content = self.content.lock().unwrap();