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

View File

@ -9,6 +9,7 @@ use theme::{BorderStyle, ColorStyle, Effect, PaletteColor, Style, Theme};
use unicode_segmentation::UnicodeSegmentation; use unicode_segmentation::UnicodeSegmentation;
use utils::lines::simple::prefix; use utils::lines::simple::prefix;
use vec::Vec2; use vec::Vec2;
use with::With;
/// Convenient interface to draw on a subset of the screen. /// Convenient interface to draw on a subset of the screen.
pub struct Printer<'a> { pub struct Printer<'a> {
@ -36,6 +37,20 @@ pub struct Printer<'a> {
backend: &'a backend::Concrete, 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> { impl<'a> Printer<'a> {
/// Creates a new printer on the given window. /// Creates a new printer on the given window.
/// ///
@ -308,37 +323,73 @@ impl<'a> Printer<'a> {
} }
/// Prints a horizontal delimiter with side border `├` and `┤`. /// 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(); let start = start.into();
self.print(start, ""); self.print(start, "");
self.print_hline(start + (1, 0), len.saturating_sub(2), ""); self.print_hline(start + (1, 0), len.saturating_sub(2), "");
self.print(start + (len.saturating_sub(1), 0), ""); self.print(start + (len.saturating_sub(1), 0), "");
} }
/// Returns a printer on a subset of this one's area. /// Returns a sub-printer with the given offset.
pub fn sub_printer<S: Into<Vec2>, T: Into<Vec2>>( pub fn offset<S>(&self, offset: S) -> Printer
&'a self, offset: S, size: T, focused: bool where
) -> Printer<'a> { S: Into<Vec2>,
let size = size.into(); {
let offset = offset.into().or_min(self.size); let offset = offset.into();
let available = if !offset.fits_in(self.size) { self.clone().with(|s| {
Vec2::zero() let consumed = Vec2::min(s.content_offset, offset);
} else {
Vec2::min(self.size - offset, size) s.content_offset = s.content_offset - consumed;
}; s.offset = s.offset + offset - consumed;
Printer { s.size = s.size.saturating_sub(offset);
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. /// Returns a new sub-printer inheriting the given focus.
pub fn offset<S: Into<Vec2>>(&self, offset: S, focused: bool) -> Printer { ///
self.sub_printer(offset, self.size, focused) /// 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. // Y is the actual coordinate of the line.
// The item ID is then Y + self.start_line // The item ID is then Y + self.start_line
line_drawer( 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, y + self.start_line,
); );
} }

View File

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

View File

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

View File

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

View File

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

View File

@ -215,7 +215,7 @@ impl View for ProgressBar {
printer.with_effect(Effect::Reverse, |printer| { printer.with_effect(Effect::Reverse, |printer| {
printer.print((offset, 0), &label); 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_hline((0, 0), length, " ");
printer.print((offset, 0), &label); printer.print((offset, 0), &label);
}); });

View File

@ -6,12 +6,17 @@ use vec::Vec2;
pub struct ScrollView<V> { pub struct ScrollView<V> {
inner: V, inner: V,
offset: Vec2, offset: Vec2,
// Togglable horizontal/vertical scrolling?
} }
impl <V> View for ScrollView<V> where V: View { impl <V> View for ScrollView<V> where V: View {
fn draw(&self, printer: &Printer) { fn draw(&self, printer: &Printer) {
self.printer.offset // Draw content
self.inner.draw(printer); 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 { } else {
let h = self.items.len(); let h = self.items.len();
let offset = self.align.v.get_offset(h, printer.size.y); let offset = self.align.v.get_offset(h, printer.size.y);
let printer = let printer = &printer.offset((0, offset));
&printer.sub_printer(Vec2::new(0, offset), printer.size, true);
self.scrollbase.draw(printer, |printer, i| { self.scrollbase.draw(printer, |printer, i| {
printer.with_selection(i == self.focus(), |printer| { 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.left_padding as usize,
self.top_padding as usize, self.top_padding as usize,
); );
let printer = &printer.offset(offset, true); let printer = &printer.offset(offset);
if printer.theme.shadow { if printer.theme.shadow {
let h = printer.size.y; let h = printer.size.y;
let w = printer.size.x; let w = printer.size.x;
@ -102,11 +102,7 @@ impl<T: View> ViewWrapper for ShadowView<T> {
} }
// Draw the view background // Draw the view background
let printer = printer.sub_printer( let printer = printer.shrinked((1,1));
Vec2::zero(),
printer.size.saturating_sub((1, 1)),
true,
);
self.view.draw(&printer); self.view.draw(&printer);
} }
} }

View File

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

View File

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