mirror of
https://github.com/FliegendeWurst/cursive.git
synced 2024-11-14 13:13:08 +00:00
Remove internal scrolling from SelectView
This commit is contained in:
parent
49e1d1d15e
commit
840fd627b7
@ -38,7 +38,7 @@ fn main() {
|
|||||||
// Let's add a BoxView to keep the list at a reasonable size
|
// Let's add a BoxView to keep the list at a reasonable size
|
||||||
// (it can scroll anyway).
|
// (it can scroll anyway).
|
||||||
siv.add_layer(
|
siv.add_layer(
|
||||||
Dialog::around(select.fixed_size((20, 10)))
|
Dialog::around(select.scrollable().fixed_size((20, 10)))
|
||||||
.title("Where are you from?"),
|
.title("Where are you from?"),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ use std::rc::Rc;
|
|||||||
use theme::ColorStyle;
|
use theme::ColorStyle;
|
||||||
use unicode_width::UnicodeWidthStr;
|
use unicode_width::UnicodeWidthStr;
|
||||||
use vec::Vec2;
|
use vec::Vec2;
|
||||||
use view::{Position, ScrollBase, View};
|
use view::{Position, View};
|
||||||
use views::MenuPopup;
|
use views::MenuPopup;
|
||||||
use Cursive;
|
use Cursive;
|
||||||
use Printer;
|
use Printer;
|
||||||
@ -51,7 +51,6 @@ pub struct SelectView<T = String> {
|
|||||||
enabled: bool,
|
enabled: bool,
|
||||||
// the focus needs to be manipulable from callbacks
|
// the focus needs to be manipulable from callbacks
|
||||||
focus: Rc<Cell<usize>>,
|
focus: Rc<Cell<usize>>,
|
||||||
scrollbase: ScrollBase,
|
|
||||||
// This is a custom callback to include a &T.
|
// This is a custom callback to include a &T.
|
||||||
// It will be called whenever "Enter" is pressed.
|
// It will be called whenever "Enter" is pressed.
|
||||||
on_submit: Option<Rc<Fn(&mut Cursive, &T)>>,
|
on_submit: Option<Rc<Fn(&mut Cursive, &T)>>,
|
||||||
@ -79,7 +78,6 @@ impl<T: 'static> SelectView<T> {
|
|||||||
items: Vec::new(),
|
items: Vec::new(),
|
||||||
enabled: true,
|
enabled: true,
|
||||||
focus: Rc::new(Cell::new(0)),
|
focus: Rc::new(Cell::new(0)),
|
||||||
scrollbase: ScrollBase::new(),
|
|
||||||
on_select: None,
|
on_select: None,
|
||||||
on_submit: None,
|
on_submit: None,
|
||||||
align: Align::top_left(),
|
align: Align::top_left(),
|
||||||
@ -353,7 +351,6 @@ impl<T: 'static> SelectView<T> {
|
|||||||
min(i, self.len() - 1)
|
min(i, self.len() - 1)
|
||||||
};
|
};
|
||||||
self.focus.set(i);
|
self.focus.set(i);
|
||||||
self.scrollbase.scroll_to(i);
|
|
||||||
|
|
||||||
self.make_select_cb().unwrap_or_else(Callback::dummy)
|
self.make_select_cb().unwrap_or_else(Callback::dummy)
|
||||||
}
|
}
|
||||||
@ -386,9 +383,6 @@ impl<T: 'static> SelectView<T> {
|
|||||||
/// ```
|
/// ```
|
||||||
pub fn select_up(&mut self, n: usize) -> Callback {
|
pub fn select_up(&mut self, n: usize) -> Callback {
|
||||||
self.focus_up(n);
|
self.focus_up(n);
|
||||||
let focus = self.focus();
|
|
||||||
self.scrollbase.scroll_to(focus);
|
|
||||||
|
|
||||||
self.make_select_cb().unwrap_or_else(Callback::dummy)
|
self.make_select_cb().unwrap_or_else(Callback::dummy)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -399,19 +393,14 @@ impl<T: 'static> SelectView<T> {
|
|||||||
/// You should run this callback with a `&mut Cursive`.
|
/// You should run this callback with a `&mut Cursive`.
|
||||||
pub fn select_down(&mut self, n: usize) -> Callback {
|
pub fn select_down(&mut self, n: usize) -> Callback {
|
||||||
self.focus_down(n);
|
self.focus_down(n);
|
||||||
let focus = self.focus();
|
|
||||||
self.scrollbase.scroll_to(focus);
|
|
||||||
|
|
||||||
self.make_select_cb().unwrap_or_else(Callback::dummy)
|
self.make_select_cb().unwrap_or_else(Callback::dummy)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Low-level focus change. Does not fix scrollbase.
|
|
||||||
fn focus_up(&mut self, n: usize) {
|
fn focus_up(&mut self, n: usize) {
|
||||||
let focus = self.focus().saturating_sub(n);
|
let focus = self.focus().saturating_sub(n);
|
||||||
self.focus.set(focus);
|
self.focus.set(focus);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Low-level focus change. Does not fix scrollbase.
|
|
||||||
fn focus_down(&mut self, n: usize) {
|
fn focus_down(&mut self, n: usize) {
|
||||||
let focus = min(self.focus() + n, self.items.len().saturating_sub(1));
|
let focus = min(self.focus() + n, self.items.len().saturating_sub(1));
|
||||||
self.focus.set(focus);
|
self.focus.set(focus);
|
||||||
@ -427,7 +416,6 @@ impl<T: 'static> SelectView<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn on_event_regular(&mut self, event: Event) -> EventResult {
|
fn on_event_regular(&mut self, event: Event) -> EventResult {
|
||||||
let mut fix_scroll = true;
|
|
||||||
match event {
|
match event {
|
||||||
Event::Key(Key::Up) if self.focus() > 0 => self.focus_up(1),
|
Event::Key(Key::Up) if self.focus() > 0 => self.focus_up(1),
|
||||||
Event::Key(Key::Down) if self.focus() + 1 < self.items.len() => {
|
Event::Key(Key::Down) if self.focus() + 1 < self.items.len() => {
|
||||||
@ -440,93 +428,35 @@ impl<T: 'static> SelectView<T> {
|
|||||||
self.focus.set(self.items.len().saturating_sub(1))
|
self.focus.set(self.items.len().saturating_sub(1))
|
||||||
}
|
}
|
||||||
Event::Mouse {
|
Event::Mouse {
|
||||||
event: MouseEvent::WheelDown,
|
event: MouseEvent::Press(_),
|
||||||
..
|
|
||||||
}
|
|
||||||
if self.scrollbase.can_scroll_down() =>
|
|
||||||
{
|
|
||||||
fix_scroll = false;
|
|
||||||
self.scrollbase.scroll_down(5);
|
|
||||||
}
|
|
||||||
Event::Mouse {
|
|
||||||
event: MouseEvent::WheelUp,
|
|
||||||
..
|
|
||||||
}
|
|
||||||
if self.scrollbase.can_scroll_up() =>
|
|
||||||
{
|
|
||||||
fix_scroll = false;
|
|
||||||
self.scrollbase.scroll_up(5);
|
|
||||||
}
|
|
||||||
Event::Mouse {
|
|
||||||
event: MouseEvent::Press(MouseButton::Left),
|
|
||||||
position,
|
position,
|
||||||
offset,
|
offset,
|
||||||
}
|
}
|
||||||
if position
|
if position
|
||||||
.checked_sub(offset)
|
.checked_sub(offset)
|
||||||
.map(|position| {
|
.map(|position| {
|
||||||
self.scrollbase.start_drag(position, self.last_size.x)
|
position < self.last_size && position.y < self.len()
|
||||||
})
|
})
|
||||||
.unwrap_or(false) =>
|
.unwrap_or(false) =>
|
||||||
{
|
{
|
||||||
fix_scroll = false;
|
self.focus.set(position.y - offset.y)
|
||||||
}
|
}
|
||||||
Event::Mouse {
|
|
||||||
event: MouseEvent::Hold(MouseButton::Left),
|
|
||||||
position,
|
|
||||||
offset,
|
|
||||||
} => {
|
|
||||||
// If the mouse is dragged, we always consume the event.
|
|
||||||
fix_scroll = false;
|
|
||||||
let position = position.saturating_sub(offset);
|
|
||||||
self.scrollbase.drag(position);
|
|
||||||
}
|
|
||||||
Event::Mouse {
|
|
||||||
event: MouseEvent::Press(_),
|
|
||||||
position,
|
|
||||||
offset,
|
|
||||||
} => if let Some(position) = position.checked_sub(offset) {
|
|
||||||
let scrollbar_size = if self.scrollbase.scrollable() {
|
|
||||||
(2, 0)
|
|
||||||
} else {
|
|
||||||
(0, 0)
|
|
||||||
};
|
|
||||||
let clickable_size =
|
|
||||||
self.last_size.saturating_sub(scrollbar_size);
|
|
||||||
if position < clickable_size {
|
|
||||||
fix_scroll = false;
|
|
||||||
let focus = position.y + self.scrollbase.start_line;
|
|
||||||
if focus < self.len() {
|
|
||||||
// Only select actual items
|
|
||||||
self.focus.set(focus);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Event::Mouse {
|
Event::Mouse {
|
||||||
event: MouseEvent::Release(MouseButton::Left),
|
event: MouseEvent::Release(MouseButton::Left),
|
||||||
position,
|
position,
|
||||||
offset,
|
offset,
|
||||||
} => {
|
}
|
||||||
fix_scroll = false;
|
if self.on_submit.is_some()
|
||||||
self.scrollbase.release_grab();
|
&& position
|
||||||
if self.on_submit.is_some() {
|
.checked_sub(offset)
|
||||||
if let Some(position) = position.checked_sub(offset) {
|
.map(|position| {
|
||||||
let scrollbar_size = if self.scrollbase.scrollable() {
|
position < self.last_size
|
||||||
(2, 0)
|
&& position.y == self.focus()
|
||||||
} else {
|
})
|
||||||
(0, 0)
|
.unwrap_or(false) =>
|
||||||
};
|
|
||||||
let clickable_size =
|
|
||||||
self.last_size.saturating_sub(scrollbar_size);
|
|
||||||
if position < clickable_size
|
|
||||||
&& (position.y + self.scrollbase.start_line)
|
|
||||||
== self.focus()
|
|
||||||
{
|
{
|
||||||
return self.submit();
|
return self.submit();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Event::Key(Key::Enter) if self.on_submit.is_some() => {
|
Event::Key(Key::Enter) if self.on_submit.is_some() => {
|
||||||
return self.submit();
|
return self.submit();
|
||||||
}
|
}
|
||||||
@ -551,10 +481,6 @@ impl<T: 'static> SelectView<T> {
|
|||||||
}
|
}
|
||||||
_ => return EventResult::Ignored,
|
_ => return EventResult::Ignored,
|
||||||
}
|
}
|
||||||
if fix_scroll {
|
|
||||||
let focus = self.focus();
|
|
||||||
self.scrollbase.scroll_to(focus);
|
|
||||||
}
|
|
||||||
|
|
||||||
EventResult::Consumed(self.make_select_cb())
|
EventResult::Consumed(self.make_select_cb())
|
||||||
}
|
}
|
||||||
@ -697,6 +623,8 @@ impl<T: 'static> View for SelectView<T> {
|
|||||||
self.last_offset.set(printer.offset);
|
self.last_offset.set(printer.offset);
|
||||||
|
|
||||||
if self.popup {
|
if self.popup {
|
||||||
|
// Popup-select only draw the active element.
|
||||||
|
// We'll draw the full list in a popup if needed.
|
||||||
let style = if !self.enabled {
|
let style = if !self.enabled {
|
||||||
ColorStyle::secondary()
|
ColorStyle::secondary()
|
||||||
} else if !printer.focused {
|
} else if !printer.focused {
|
||||||
@ -724,26 +652,30 @@ impl<T: 'static> View for SelectView<T> {
|
|||||||
printer.print((offset, 0), label);
|
printer.print((offset, 0), label);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
// Non-popup mode: we always print the entire list.
|
||||||
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 = &printer.offset((0, offset));
|
let printer = &printer.offset((0, offset));
|
||||||
|
|
||||||
self.scrollbase.draw(printer, |printer, i| {
|
for i in 0..self.len() {
|
||||||
printer.with_selection(i == self.focus(), |printer| {
|
printer.offset((0, i)).with_selection(
|
||||||
|
i == self.focus(),
|
||||||
|
|printer| {
|
||||||
if i != self.focus() && !self.enabled {
|
if i != self.focus() && !self.enabled {
|
||||||
printer
|
printer.with_color(
|
||||||
.with_color(ColorStyle::secondary(), |printer| {
|
ColorStyle::secondary(),
|
||||||
self.draw_item(printer, i)
|
|printer| self.draw_item(printer, i),
|
||||||
});
|
);
|
||||||
} else {
|
} else {
|
||||||
self.draw_item(printer, i);
|
self.draw_item(printer, i);
|
||||||
}
|
}
|
||||||
});
|
},
|
||||||
});
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn required_size(&mut self, req: Vec2) -> Vec2 {
|
fn required_size(&mut self, _: Vec2) -> Vec2 {
|
||||||
// Items here are not compressible.
|
// Items here are not compressible.
|
||||||
// So no matter what the horizontal requirements are,
|
// So no matter what the horizontal requirements are,
|
||||||
// we'll still return our longest item.
|
// we'll still return our longest item.
|
||||||
@ -758,14 +690,7 @@ impl<T: 'static> View for SelectView<T> {
|
|||||||
} else {
|
} else {
|
||||||
let h = self.items.len();
|
let h = self.items.len();
|
||||||
|
|
||||||
let scrolling = req.y < h;
|
Vec2::new(w, h)
|
||||||
|
|
||||||
// Add 2 spaces for the scrollbar if we need
|
|
||||||
let w = if scrolling { w + 2 } else { w };
|
|
||||||
|
|
||||||
// Don't request more than we're offered - we can scroll,
|
|
||||||
// after all
|
|
||||||
Vec2::new(w, min(h, req.y))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -783,10 +708,6 @@ impl<T: 'static> View for SelectView<T> {
|
|||||||
|
|
||||||
fn layout(&mut self, size: Vec2) {
|
fn layout(&mut self, size: Vec2) {
|
||||||
self.last_size = size;
|
self.last_size = size;
|
||||||
|
|
||||||
if !self.popup {
|
|
||||||
self.scrollbase.set_heights(size.y, self.items.len());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn important_area(&self, size: Vec2) -> Rect {
|
fn important_area(&self, size: Vec2) -> Rect {
|
||||||
|
Loading…
Reference in New Issue
Block a user