mirror of
https://github.com/FliegendeWurst/cursive.git
synced 2024-11-27 19:26:09 +00:00
Fix mouse position with TextArea
This commit is contained in:
parent
a5952d0741
commit
ca23a9c10f
@ -1,7 +1,7 @@
|
|||||||
use std::cmp::min;
|
use std::cmp::min;
|
||||||
use {Printer, With, XY};
|
use {Printer, With, XY};
|
||||||
use direction::Direction;
|
use direction::Direction;
|
||||||
use event::{Event, EventResult, Key, MouseEvent};
|
use event::{Event, EventResult, Key, MouseEvent, MouseButton};
|
||||||
use odds::vec::VecExt;
|
use odds::vec::VecExt;
|
||||||
use theme::{ColorStyle, Effect};
|
use theme::{ColorStyle, Effect};
|
||||||
use unicode_segmentation::UnicodeSegmentation;
|
use unicode_segmentation::UnicodeSegmentation;
|
||||||
@ -28,7 +28,8 @@ pub struct TextArea {
|
|||||||
scrollbase: ScrollBase,
|
scrollbase: ScrollBase,
|
||||||
|
|
||||||
/// Cache to avoid re-computing layout on no-op events
|
/// Cache to avoid re-computing layout on no-op events
|
||||||
last_size: Option<XY<SizeCache>>,
|
size_cache: Option<XY<SizeCache>>,
|
||||||
|
last_size: Vec2,
|
||||||
|
|
||||||
/// Byte offset of the currently selected grapheme.
|
/// Byte offset of the currently selected grapheme.
|
||||||
cursor: usize,
|
cursor: usize,
|
||||||
@ -48,7 +49,8 @@ impl TextArea {
|
|||||||
rows: Vec::new(),
|
rows: Vec::new(),
|
||||||
enabled: true,
|
enabled: true,
|
||||||
scrollbase: ScrollBase::new().right_padding(0),
|
scrollbase: ScrollBase::new().right_padding(0),
|
||||||
last_size: None,
|
size_cache: None,
|
||||||
|
last_size: Vec2::zero(),
|
||||||
cursor: 0,
|
cursor: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -59,13 +61,13 @@ impl TextArea {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn invalidate(&mut self) {
|
fn invalidate(&mut self) {
|
||||||
self.last_size = None;
|
self.size_cache = None;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the content of the view.
|
/// Sets the content of the view.
|
||||||
pub fn set_content<S: Into<String>>(&mut self, content: S) {
|
pub fn set_content<S: Into<String>>(&mut self, content: S) {
|
||||||
self.content = content.into();
|
self.content = content.into();
|
||||||
if let Some(size) = self.last_size.map(|s| s.map(|s| s.value)) {
|
if let Some(size) = self.size_cache.map(|s| s.map(|s| s.value)) {
|
||||||
self.compute_rows(size);
|
self.compute_rows(size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -172,7 +174,7 @@ impl TextArea {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn is_cache_valid(&self, size: Vec2) -> bool {
|
fn is_cache_valid(&self, size: Vec2) -> bool {
|
||||||
match self.last_size {
|
match self.size_cache {
|
||||||
None => false,
|
None => false,
|
||||||
Some(ref last) => last.x.accept(size.x) && last.y.accept(size.y),
|
Some(ref last) => last.x.accept(size.x) && last.y.accept(size.y),
|
||||||
}
|
}
|
||||||
@ -195,7 +197,8 @@ impl TextArea {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compute_rows(&mut self, size: Vec2) {
|
fn soft_compute_rows(&mut self, size: Vec2) {
|
||||||
|
|
||||||
if self.is_cache_valid(size) {
|
if self.is_cache_valid(size) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -214,8 +217,12 @@ impl TextArea {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !self.rows.is_empty() {
|
if !self.rows.is_empty() {
|
||||||
self.last_size = Some(SizeCache::build(size, size));
|
self.size_cache = Some(SizeCache::build(size, size));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn compute_rows(&mut self, size: Vec2) {
|
||||||
|
self.soft_compute_rows(size);
|
||||||
self.scrollbase.set_heights(size.y, self.rows.len());
|
self.scrollbase.set_heights(size.y, self.rows.len());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -289,13 +296,13 @@ impl TextArea {
|
|||||||
///
|
///
|
||||||
/// The only damages are assumed to have occured around the cursor.
|
/// The only damages are assumed to have occured around the cursor.
|
||||||
fn fix_damages(&mut self) {
|
fn fix_damages(&mut self) {
|
||||||
if self.last_size.is_none() {
|
if self.size_cache.is_none() {
|
||||||
// If we don't know our size, it means we'll get a layout command soon.
|
// If we don't know our size, it means we'll get a layout command soon.
|
||||||
// So no need to do that here.
|
// So no need to do that here.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let size = self.last_size.unwrap().map(|s| s.value);
|
let size = self.size_cache.unwrap().map(|s| s.value);
|
||||||
|
|
||||||
// Find affected text.
|
// Find affected text.
|
||||||
// We know the damage started at this row, so it'll need to go.
|
// We know the damage started at this row, so it'll need to go.
|
||||||
@ -362,7 +369,7 @@ impl TextArea {
|
|||||||
impl View for TextArea {
|
impl View for TextArea {
|
||||||
fn required_size(&mut self, constraint: Vec2) -> Vec2 {
|
fn required_size(&mut self, constraint: Vec2) -> Vec2 {
|
||||||
// Make sure our structure is up to date
|
// Make sure our structure is up to date
|
||||||
self.compute_rows(constraint);
|
self.soft_compute_rows(constraint);
|
||||||
|
|
||||||
// Ideally, we'd want x = the longest row + 1
|
// Ideally, we'd want x = the longest row + 1
|
||||||
// (we always keep a space at the end)
|
// (we always keep a space at the end)
|
||||||
@ -425,6 +432,7 @@ impl View for TextArea {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn on_event(&mut self, event: Event) -> EventResult {
|
fn on_event(&mut self, event: Event) -> EventResult {
|
||||||
|
let mut fix_scroll = true;
|
||||||
match event {
|
match event {
|
||||||
Event::Char(ch) => self.insert(ch),
|
Event::Char(ch) => self.insert(ch),
|
||||||
Event::Key(Key::Enter) => self.insert('\n'),
|
Event::Key(Key::Enter) => self.insert('\n'),
|
||||||
@ -459,15 +467,46 @@ impl View for TextArea {
|
|||||||
Event::Key(Key::Right) if self.cursor < self.content.len() => {
|
Event::Key(Key::Right) if self.cursor < self.content.len() => {
|
||||||
self.move_right()
|
self.move_right()
|
||||||
}
|
}
|
||||||
|
Event::Mouse {
|
||||||
|
event: MouseEvent::WheelUp,
|
||||||
|
..
|
||||||
|
} if self.scrollbase.can_scroll_up() => {
|
||||||
|
fix_scroll = false;
|
||||||
|
self.scrollbase.scroll_up(5);
|
||||||
|
}
|
||||||
|
Event::Mouse {
|
||||||
|
event: MouseEvent::WheelDown,
|
||||||
|
..
|
||||||
|
} if self.scrollbase.can_scroll_down() => {
|
||||||
|
fix_scroll = false;
|
||||||
|
self.scrollbase.scroll_down(5);
|
||||||
|
}
|
||||||
|
Event::Mouse {
|
||||||
|
event: MouseEvent::Press(MouseButton::Left),
|
||||||
|
position,
|
||||||
|
offset,
|
||||||
|
} if position.checked_sub(offset).map(|position| {
|
||||||
|
self.scrollbase.start_drag(position, self.last_size.x)
|
||||||
|
}).unwrap_or(false) => {
|
||||||
|
fix_scroll = false;
|
||||||
|
}
|
||||||
|
Event::Mouse {
|
||||||
|
event: MouseEvent::Hold(MouseButton::Left),
|
||||||
|
position,
|
||||||
|
offset
|
||||||
|
} => {
|
||||||
|
fix_scroll = false;
|
||||||
|
position
|
||||||
|
.checked_sub(offset)
|
||||||
|
.map(|position| self.scrollbase.drag(position));
|
||||||
|
}
|
||||||
Event::Mouse {
|
Event::Mouse {
|
||||||
event: MouseEvent::Press(_),
|
event: MouseEvent::Press(_),
|
||||||
position,
|
position,
|
||||||
offset,
|
offset,
|
||||||
} if position.fits_in_rect(
|
} if position.fits_in_rect(
|
||||||
offset,
|
offset,
|
||||||
self.last_size
|
self.last_size,
|
||||||
.map(|s| s.map(SizeCache::value))
|
|
||||||
.unwrap_or_else(Vec2::zero),
|
|
||||||
) =>
|
) =>
|
||||||
{
|
{
|
||||||
position.checked_sub(offset).map(|position| {
|
position.checked_sub(offset).map(|position| {
|
||||||
@ -488,8 +527,10 @@ impl View for TextArea {
|
|||||||
}
|
}
|
||||||
|
|
||||||
debug!("Rows: {:?}", self.rows);
|
debug!("Rows: {:?}", self.rows);
|
||||||
let focus = self.selected_row();
|
if fix_scroll {
|
||||||
self.scrollbase.scroll_to(focus);
|
let focus = self.selected_row();
|
||||||
|
self.scrollbase.scroll_to(focus);
|
||||||
|
}
|
||||||
|
|
||||||
EventResult::Consumed(None)
|
EventResult::Consumed(None)
|
||||||
}
|
}
|
||||||
@ -499,6 +540,7 @@ impl View for TextArea {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn layout(&mut self, size: Vec2) {
|
fn layout(&mut self, size: Vec2) {
|
||||||
|
self.last_size = size;
|
||||||
self.compute_rows(size);
|
self.compute_rows(size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user