mirror of
https://github.com/FliegendeWurst/cursive.git
synced 2024-11-10 03:10:41 +00:00
Add inner size to printer
Renamed Printer::size -> output_size
This commit is contained in:
parent
5586403080
commit
0fbc5a888e
@ -25,6 +25,12 @@ pub struct Printer<'a> {
|
||||
/// Size of the area we are allowed to draw on.
|
||||
///
|
||||
/// Anything outside of this should be discarded.
|
||||
pub output_size: Vec2,
|
||||
|
||||
/// Size allocated to the view.
|
||||
///
|
||||
/// This should be the same value as the one given in the last call to
|
||||
/// `View::layout`.
|
||||
pub size: Vec2,
|
||||
|
||||
/// Offset into the view for this printer.
|
||||
@ -47,6 +53,7 @@ impl<'a> Clone for Printer<'a> {
|
||||
Printer {
|
||||
offset: self.offset,
|
||||
content_offset: self.content_offset,
|
||||
output_size: self.output_size,
|
||||
size: self.size,
|
||||
focused: self.focused,
|
||||
theme: self.theme,
|
||||
@ -61,12 +68,14 @@ impl<'a> Printer<'a> {
|
||||
/// But nobody needs to know that.
|
||||
#[doc(hidden)]
|
||||
pub fn new<T: Into<Vec2>>(
|
||||
size: T, theme: &'a Theme, backend: &'a Backend
|
||||
size: T, theme: &'a Theme, backend: &'a Backend,
|
||||
) -> Self {
|
||||
let size = size.into();
|
||||
Printer {
|
||||
offset: Vec2::zero(),
|
||||
content_offset: Vec2::zero(),
|
||||
size: size.into(),
|
||||
output_size: size,
|
||||
size,
|
||||
focused: true,
|
||||
theme,
|
||||
backend,
|
||||
@ -91,7 +100,7 @@ impl<'a> Printer<'a> {
|
||||
|
||||
// We accept requests between `content_offset` and
|
||||
// `content_offset + size`
|
||||
if !start.fits_in(self.size + self.content_offset) {
|
||||
if !(start < self.output_size + self.content_offset) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -106,13 +115,22 @@ impl<'a> Printer<'a> {
|
||||
|
||||
let text_width = text.width();
|
||||
|
||||
// If we're waaaay too far left, just give up.
|
||||
if hidden_part.x > text_width {
|
||||
return;
|
||||
}
|
||||
|
||||
// We have to drop hidden_part.x width from the start of the string.
|
||||
// prefix() may be too short if there's a double-width character.
|
||||
// So instead, keep the suffix and drop the prefix.
|
||||
|
||||
// TODO: use a different prefix method that is *at least* the width
|
||||
// (and not *at most*)
|
||||
let tail = suffix(text.graphemes(true), text_width - hidden_part.x, "");
|
||||
let tail = suffix(
|
||||
text.graphemes(true),
|
||||
text_width - hidden_part.x,
|
||||
"",
|
||||
);
|
||||
let skipped_len = text.len() - tail.length;
|
||||
let skipped_width = text_width - tail.width;
|
||||
assert_eq!(text[..skipped_len].width(), skipped_width);
|
||||
@ -130,7 +148,7 @@ impl<'a> Printer<'a> {
|
||||
let start = start - self.content_offset;
|
||||
|
||||
// Do we have enough room for the entire line?
|
||||
let room = self.size.x - start.x;
|
||||
let room = self.output_size.x - start.x;
|
||||
|
||||
// Drop the end of the text if it's too long
|
||||
// We want the number of CHARACTERS, not bytes.
|
||||
@ -144,12 +162,14 @@ impl<'a> Printer<'a> {
|
||||
}
|
||||
|
||||
/// Prints a vertical line using the given character.
|
||||
pub fn print_vline<T: Into<Vec2>>(&self, start: T, height: usize, c: &str) {
|
||||
pub fn print_vline<T: Into<Vec2>>(
|
||||
&self, start: T, height: usize, c: &str,
|
||||
) {
|
||||
let start = start.into();
|
||||
|
||||
// Here again, we can abort if we're trying to print too far right or
|
||||
// too low.
|
||||
if !start.fits_in(self.size + self.content_offset) {
|
||||
if !start.fits_in(self.output_size + self.content_offset) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -170,11 +190,11 @@ impl<'a> Printer<'a> {
|
||||
let start = start - self.content_offset;
|
||||
|
||||
// Don't go overboard
|
||||
let height = min(height, self.size.y - start.y);
|
||||
let height = min(height, self.output_size.y - start.y);
|
||||
|
||||
let start = start + self.offset;
|
||||
for y in 0..height {
|
||||
self.backend.print_at(start + (0,y), c);
|
||||
self.backend.print_at(start + (0, y), c);
|
||||
}
|
||||
}
|
||||
|
||||
@ -183,7 +203,7 @@ impl<'a> Printer<'a> {
|
||||
let start = start.into();
|
||||
|
||||
// Nothing to be done if the start if too far to the bottom/right
|
||||
if !start.fits_in(self.size + self.content_offset) {
|
||||
if !start.fits_in(self.output_size + self.content_offset) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -203,7 +223,10 @@ impl<'a> Printer<'a> {
|
||||
let start = start - self.content_offset;
|
||||
|
||||
// Don't write too much if we're close to the end
|
||||
let width = min(width, (self.size.x - start.x) / c.width());
|
||||
let width = min(
|
||||
width,
|
||||
(self.output_size.x - start.x) / c.width(),
|
||||
);
|
||||
|
||||
// Could we avoid allocating?
|
||||
let text: String = ::std::iter::repeat(c).take(width).collect();
|
||||
@ -232,7 +255,8 @@ impl<'a> Printer<'a> {
|
||||
where
|
||||
F: FnOnce(&Printer),
|
||||
{
|
||||
let old = self.backend.set_color(c.resolve(&self.theme.palette));
|
||||
let old = self.backend
|
||||
.set_color(c.resolve(&self.theme.palette));
|
||||
f(self);
|
||||
self.backend.set_color(old);
|
||||
}
|
||||
@ -249,8 +273,6 @@ impl<'a> Printer<'a> {
|
||||
let color = style.color;
|
||||
let effects = style.effects;
|
||||
|
||||
// eprintln!("{:?}", effects);
|
||||
|
||||
if let Some(color) = color {
|
||||
self.with_color(color, |printer| {
|
||||
printer.with_effects(effects, f);
|
||||
@ -305,7 +327,7 @@ impl<'a> Printer<'a> {
|
||||
/// printer.print_box((0,0), (6,4), false);
|
||||
/// ```
|
||||
pub fn print_box<T: Into<Vec2>, S: Into<Vec2>>(
|
||||
&self, start: T, size: S, invert: bool
|
||||
&self, start: T, size: S, invert: bool,
|
||||
) {
|
||||
let start = start.into();
|
||||
let size = size.into();
|
||||
@ -427,6 +449,7 @@ impl<'a> Printer<'a> {
|
||||
|
||||
s.offset = s.offset + offset;
|
||||
|
||||
s.output_size = s.output_size.saturating_sub(offset);
|
||||
s.size = s.size.saturating_sub(offset);
|
||||
})
|
||||
}
|
||||
@ -452,6 +475,8 @@ impl<'a> Printer<'a> {
|
||||
S: Into<Vec2>,
|
||||
{
|
||||
self.clone().with(|s| {
|
||||
let size = size.into();
|
||||
s.output_size = Vec2::min(s.output_size, size);
|
||||
s.size = Vec2::min(s.size, size);
|
||||
})
|
||||
}
|
||||
@ -475,4 +500,19 @@ impl<'a> Printer<'a> {
|
||||
s.content_offset = s.content_offset + offset;
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns a sub-printer with a different inner size.
|
||||
///
|
||||
/// This will not change the actual output size, but will appear bigger to
|
||||
/// users of this printer.
|
||||
///
|
||||
/// Useful to give to children who think they're big, but really aren't.
|
||||
pub fn inner_size<S>(&self, size: S) -> Self
|
||||
where
|
||||
S: Into<Vec2>,
|
||||
{
|
||||
self.clone().with(|s| {
|
||||
s.size = size.into();
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,11 @@
|
||||
use Printer;
|
||||
use direction::Direction;
|
||||
use event::{AnyCb, Event, EventResult, Key};
|
||||
use rect::Rect;
|
||||
use std::cmp::min;
|
||||
use vec::Vec2;
|
||||
use view::{Selector, View};
|
||||
use xy::XY;
|
||||
use With;
|
||||
use Printer;
|
||||
|
||||
/// Wraps a view in a scrollable area.
|
||||
pub struct ScrollView<V> {
|
||||
@ -47,6 +47,38 @@ impl<V> ScrollView<V> {
|
||||
let max_offset = self.inner_size.saturating_sub(self.last_size);
|
||||
self.offset = offset.into().or_min(max_offset);
|
||||
}
|
||||
|
||||
/// Controls whether this view can scroll vertically.
|
||||
///
|
||||
/// Defaults to `true`.
|
||||
pub fn set_scroll_y(&mut self, enabled: bool) {
|
||||
self.enabled.y = enabled;
|
||||
}
|
||||
|
||||
/// Controls whether this view can scroll horizontally.
|
||||
///
|
||||
/// Defaults to `false`.
|
||||
pub fn set_scroll_x(&mut self, enabled: bool) {
|
||||
self.enabled.x = enabled;
|
||||
}
|
||||
|
||||
/// Controls whether this view can scroll vertically.
|
||||
///
|
||||
/// Defaults to `true`.
|
||||
///
|
||||
/// Chainable variant.
|
||||
pub fn scroll_y(self, enabled: bool) -> Self {
|
||||
self.with(|s| s.set_scroll_y(enabled))
|
||||
}
|
||||
|
||||
/// Controls whether this view can scroll horizontally.
|
||||
///
|
||||
/// Defaults to `false`.
|
||||
///
|
||||
/// Chainable variant.
|
||||
pub fn scroll_x(self, enabled: bool) -> Self {
|
||||
self.with(|s| s.set_scroll_x(enabled))
|
||||
}
|
||||
}
|
||||
|
||||
impl<V> View for ScrollView<V>
|
||||
@ -55,7 +87,7 @@ where
|
||||
{
|
||||
fn draw(&self, printer: &Printer) {
|
||||
// Draw content
|
||||
let printer = printer.content_offset(self.offset);
|
||||
let printer = printer.content_offset(self.offset).inner_size(self.inner_size);
|
||||
self.inner.draw(&printer);
|
||||
|
||||
// Draw scrollbar?
|
||||
@ -72,14 +104,34 @@ where
|
||||
// If it's an arrow, try to scroll in the given direction.
|
||||
// If it's a mouse scroll, try to scroll as well.
|
||||
match event {
|
||||
Event::Key(Key::Up) if self.offset.y > 0 => {
|
||||
Event::Key(Key::Up)
|
||||
if self.enabled.y && self.offset.y > 0 =>
|
||||
{
|
||||
self.offset.y -= 1;
|
||||
EventResult::Consumed(None)
|
||||
}
|
||||
Event::Key(Key::Left) if self.offset.x > 0 => {
|
||||
Event::Key(Key::Down)
|
||||
if self.enabled.y
|
||||
&& (self.offset.y + self.last_size.y
|
||||
< self.inner_size.y) =>
|
||||
{
|
||||
self.offset.y += 1;
|
||||
EventResult::Consumed(None)
|
||||
}
|
||||
Event::Key(Key::Left)
|
||||
if self.enabled.x && self.offset.x > 0 =>
|
||||
{
|
||||
self.offset.x -= 1;
|
||||
EventResult::Consumed(None)
|
||||
}
|
||||
Event::Key(Key::Right)
|
||||
if self.enabled.x
|
||||
&& (self.offset.x + self.last_size.x
|
||||
< self.inner_size.x) =>
|
||||
{
|
||||
self.offset.x += 1;
|
||||
EventResult::Consumed(None)
|
||||
}
|
||||
_ => EventResult::Ignored,
|
||||
}
|
||||
}
|
||||
@ -107,7 +159,8 @@ where
|
||||
|
||||
// For each enabled direction, return the min of size and constraint.
|
||||
// For the rest, directly return the size.
|
||||
self.enabled.select_or(Vec2::min(size, constraint), size)
|
||||
self.enabled
|
||||
.select_or(Vec2::min(size, constraint), size)
|
||||
}
|
||||
|
||||
fn call_on_any<'a>(&mut self, selector: &Selector, cb: AnyCb<'a>) {
|
||||
|
Loading…
Reference in New Issue
Block a user