Fix drawing widgets on cursor not removing cursor
This commit is contained in:
parent
45ece466c2
commit
24fd0050fb
2 changed files with 54 additions and 16 deletions
|
|
@ -157,7 +157,7 @@ impl Default for Cell {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub struct StackFrame {
|
struct StackFrame {
|
||||||
pub pos: Pos,
|
pub pos: Pos,
|
||||||
pub size: Size,
|
pub size: Size,
|
||||||
pub drawable_area: Option<(Pos, Size)>,
|
pub drawable_area: Option<(Pos, Size)>,
|
||||||
|
|
@ -188,7 +188,7 @@ impl StackFrame {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn then(&self, pos: Pos, size: Size) -> Self {
|
fn then(&self, pos: Pos, size: Size) -> Self {
|
||||||
let pos = self.local_to_global(pos);
|
let pos = self.local_to_global(pos);
|
||||||
|
|
||||||
let drawable_area = self
|
let drawable_area = self
|
||||||
|
|
@ -202,17 +202,17 @@ impl StackFrame {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn local_to_global(&self, local_pos: Pos) -> Pos {
|
fn local_to_global(&self, local_pos: Pos) -> Pos {
|
||||||
local_pos + self.pos
|
local_pos + self.pos
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn global_to_local(&self, global_pos: Pos) -> Pos {
|
fn global_to_local(&self, global_pos: Pos) -> Pos {
|
||||||
global_pos - self.pos
|
global_pos - self.pos
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Ranges along the x and y axis where drawing is allowed, in global
|
/// Ranges along the x and y axis where drawing is allowed, in global
|
||||||
/// coordinates.
|
/// coordinates.
|
||||||
pub fn legal_ranges(&self) -> Option<(Range<i32>, Range<i32>)> {
|
fn legal_ranges(&self) -> Option<(Range<i32>, Range<i32>)> {
|
||||||
if let Some((pos, size)) = self.drawable_area {
|
if let Some((pos, size)) = self.drawable_area {
|
||||||
let xrange = pos.x..pos.x + size.width as i32;
|
let xrange = pos.x..pos.x + size.width as i32;
|
||||||
let yrange = pos.y..pos.y + size.height as i32;
|
let yrange = pos.y..pos.y + size.height as i32;
|
||||||
|
|
@ -227,6 +227,8 @@ impl StackFrame {
|
||||||
pub struct Buffer {
|
pub struct Buffer {
|
||||||
size: Size,
|
size: Size,
|
||||||
data: Vec<Cell>,
|
data: Vec<Cell>,
|
||||||
|
cursor: Option<Pos>,
|
||||||
|
|
||||||
/// A stack of rectangular drawing areas.
|
/// A stack of rectangular drawing areas.
|
||||||
///
|
///
|
||||||
/// When rendering to the buffer with a nonempty stack, it behaves as if it
|
/// When rendering to the buffer with a nonempty stack, it behaves as if it
|
||||||
|
|
@ -237,6 +239,9 @@ pub struct Buffer {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Buffer {
|
impl Buffer {
|
||||||
|
/// Index in `data` of the cell at the given position. The position must
|
||||||
|
/// be inside the buffer.
|
||||||
|
///
|
||||||
/// Ignores the stack.
|
/// Ignores the stack.
|
||||||
fn index(&self, x: u16, y: u16) -> usize {
|
fn index(&self, x: u16, y: u16) -> usize {
|
||||||
assert!(x < self.size.width);
|
assert!(x < self.size.width);
|
||||||
|
|
@ -249,6 +254,9 @@ impl Buffer {
|
||||||
y * width + x
|
y * width + x
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A reference to the cell at the given position. The position must be
|
||||||
|
/// inside the buffer.
|
||||||
|
///
|
||||||
/// Ignores the stack.
|
/// Ignores the stack.
|
||||||
pub fn at(&self, x: u16, y: u16) -> &Cell {
|
pub fn at(&self, x: u16, y: u16) -> &Cell {
|
||||||
assert!(x < self.size.width);
|
assert!(x < self.size.width);
|
||||||
|
|
@ -258,6 +266,9 @@ impl Buffer {
|
||||||
&self.data[i]
|
&self.data[i]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A mutable reference to the cell at the given position. The position must
|
||||||
|
/// be inside the buffer.
|
||||||
|
///
|
||||||
/// Ignores the stack.
|
/// Ignores the stack.
|
||||||
fn at_mut(&mut self, x: u16, y: u16) -> &mut Cell {
|
fn at_mut(&mut self, x: u16, y: u16) -> &mut Cell {
|
||||||
assert!(x < self.size.width);
|
assert!(x < self.size.width);
|
||||||
|
|
@ -267,7 +278,7 @@ impl Buffer {
|
||||||
&mut self.data[i]
|
&mut self.data[i]
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn current_frame(&self) -> StackFrame {
|
fn current_frame(&self) -> StackFrame {
|
||||||
self.stack.last().copied().unwrap_or(StackFrame {
|
self.stack.last().copied().unwrap_or(StackFrame {
|
||||||
pos: Pos::ZERO,
|
pos: Pos::ZERO,
|
||||||
size: self.size,
|
size: self.size,
|
||||||
|
|
@ -283,6 +294,19 @@ impl Buffer {
|
||||||
self.stack.pop();
|
self.stack.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Size of the current drawable area, respecting the stack.
|
||||||
|
pub fn size(&self) -> Size {
|
||||||
|
self.current_frame().size
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cursor(&self) -> Option<Pos> {
|
||||||
|
self.cursor.map(|p| self.current_frame().global_to_local(p))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_cursor(&mut self, pos: Option<Pos>) {
|
||||||
|
self.cursor = pos.map(|p| self.current_frame().local_to_global(p));
|
||||||
|
}
|
||||||
|
|
||||||
/// Resize the buffer and reset its contents.
|
/// Resize the buffer and reset its contents.
|
||||||
///
|
///
|
||||||
/// The buffer's contents are reset even if the buffer is already the
|
/// The buffer's contents are reset even if the buffer is already the
|
||||||
|
|
@ -300,6 +324,8 @@ impl Buffer {
|
||||||
self.data.resize_with(len, Cell::default);
|
self.data.resize_with(len, Cell::default);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.cursor = None;
|
||||||
|
|
||||||
self.stack.clear();
|
self.stack.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -307,29 +333,35 @@ impl Buffer {
|
||||||
///
|
///
|
||||||
/// `buf.reset()` is equivalent to `buf.resize(buf.size())`.
|
/// `buf.reset()` is equivalent to `buf.resize(buf.size())`.
|
||||||
pub fn reset(&mut self) {
|
pub fn reset(&mut self) {
|
||||||
self.data.fill_with(Cell::default);
|
self.resize(self.size);
|
||||||
self.stack.clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Remove the grapheme at the specified coordinates from the buffer.
|
/// Remove the grapheme at the specified coordinates from the buffer.
|
||||||
///
|
///
|
||||||
/// Removes the entire grapheme, not just the cell at the coordinates.
|
/// Removes the entire grapheme, not just the cell at the coordinates.
|
||||||
/// Preserves the style of the affected cells. Works even if the coordinates
|
/// Preserves the style of the affected cells. Preserves the cursor. Works
|
||||||
/// don't point to the beginning of the grapheme.
|
/// even if the coordinates don't point to the beginning of the grapheme.
|
||||||
///
|
///
|
||||||
/// Ignores the stack.
|
/// Ignores the stack.
|
||||||
fn erase(&mut self, x: u16, y: u16) {
|
fn erase(&mut self, x: u16, y: u16) {
|
||||||
let cell = self.at(x, y);
|
let cell = self.at(x, y);
|
||||||
let width: u16 = cell.width.into();
|
let width: u16 = cell.width.into();
|
||||||
let offset: u16 = cell.offset.into();
|
let offset: u16 = cell.offset.into();
|
||||||
|
|
||||||
for x in (x - offset)..(x - offset + width) {
|
for x in (x - offset)..(x - offset + width) {
|
||||||
let cell = self.at_mut(x, y);
|
let cell = self.at_mut(x, y);
|
||||||
let style = cell.style;
|
let style = cell.style;
|
||||||
|
|
||||||
*cell = Cell::default();
|
*cell = Cell::default();
|
||||||
cell.style = style;
|
cell.style = style;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Write styled text to the buffer, respecting the width of individual
|
||||||
|
/// graphemes.
|
||||||
|
///
|
||||||
|
/// The initial x position is considered the first column for tab width
|
||||||
|
/// calculations.
|
||||||
pub fn write(&mut self, widthdb: &mut WidthDB, pos: Pos, styled: &Styled) {
|
pub fn write(&mut self, widthdb: &mut WidthDB, pos: Pos, styled: &Styled) {
|
||||||
let frame = self.current_frame();
|
let frame = self.current_frame();
|
||||||
let (xrange, yrange) = match frame.legal_ranges() {
|
let (xrange, yrange) = match frame.legal_ranges() {
|
||||||
|
|
@ -359,6 +391,8 @@ impl Buffer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Write a single grapheme to the buffer, respecting its width.
|
||||||
|
///
|
||||||
/// Assumes that `pos.y` is in range.
|
/// Assumes that `pos.y` is in range.
|
||||||
fn write_grapheme(
|
fn write_grapheme(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
|
@ -403,6 +437,13 @@ impl Buffer {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(pos) = self.cursor {
|
||||||
|
if pos.y == y as i32 && start_x <= pos.x && pos.x <= end_x {
|
||||||
|
// The cursor lies within the bounds of the current grapheme and
|
||||||
|
self.cursor = None;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn cells(&self) -> Cells<'_> {
|
pub fn cells(&self) -> Cells<'_> {
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,6 @@ use crate::wrap;
|
||||||
pub struct Frame {
|
pub struct Frame {
|
||||||
pub(crate) widthdb: WidthDB,
|
pub(crate) widthdb: WidthDB,
|
||||||
pub(crate) buffer: Buffer,
|
pub(crate) buffer: Buffer,
|
||||||
cursor: Option<Pos>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Frame {
|
impl Frame {
|
||||||
|
|
@ -23,21 +22,19 @@ impl Frame {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn size(&self) -> Size {
|
pub fn size(&self) -> Size {
|
||||||
self.buffer.current_frame().size
|
self.buffer.size()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn reset(&mut self) {
|
pub fn reset(&mut self) {
|
||||||
self.buffer.reset();
|
self.buffer.reset();
|
||||||
self.cursor = None;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn cursor(&self) -> Option<Pos> {
|
pub fn cursor(&self) -> Option<Pos> {
|
||||||
self.cursor
|
self.buffer.cursor()
|
||||||
.map(|p| self.buffer.current_frame().global_to_local(p))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_cursor(&mut self, pos: Option<Pos>) {
|
pub fn set_cursor(&mut self, pos: Option<Pos>) {
|
||||||
self.cursor = pos.map(|p| self.buffer.current_frame().local_to_global(p));
|
self.buffer.set_cursor(pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn show_cursor(&mut self, pos: Pos) {
|
pub fn show_cursor(&mut self, pos: Pos) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue