use crate::app::editor::EditorState;
use crate::app::types::InputMode;
impl EditorState {
fn grid_bounds(&self) -> (isize, isize) {
(
(self.o2.w.saturating_sub(1)) as isize,
(self.o2.h.saturating_sub(1)) as isize,
)
}
pub fn select(&mut self, x: isize, y: isize, w: isize, h: isize) {
let (max_grid_x, max_grid_y) = self.grid_bounds();
self.cursor.cx = x.clamp(0, max_grid_x) as usize;
self.cursor.cy = y.clamp(0, max_grid_y) as usize;
let min_cw = -(self.cursor.cx as isize);
let max_cw = max_grid_x - (self.cursor.cx as isize);
self.cursor.cw = w.clamp(min_cw, max_cw);
let min_ch = -(self.cursor.cy as isize);
let max_ch = max_grid_y - (self.cursor.cy as isize);
self.cursor.ch = h.clamp(min_ch, max_ch);
self.cursor.calc_bounds();
self.guide = false;
}
pub fn select_all(&mut self) {
self.select(0, 0, self.o2.w as isize - 1, self.o2.h as isize - 1);
self.mode = InputMode::Selection;
}
pub fn move_cursor(&mut self, dx: isize, dy: isize) {
let (max_grid_x, max_grid_y) = self.grid_bounds();
let min_x_allowed = 0isize.max(-self.cursor.cw);
let max_x_allowed = max_grid_x.min(max_grid_x - self.cursor.cw);
let min_y_allowed = 0isize.max(-self.cursor.ch);
let max_y_allowed = max_grid_y.min(max_grid_y - self.cursor.ch);
let target_x = (self.cursor.cx as isize + dx).clamp(min_x_allowed, max_x_allowed);
let target_y = (self.cursor.cy as isize - dy).clamp(min_y_allowed, max_y_allowed);
self.select(target_x, target_y, self.cursor.cw, self.cursor.ch);
}
pub fn scale_cursor(&mut self, dw: isize, dh: isize) {
self.select(
self.cursor.cx as isize,
self.cursor.cy as isize,
self.cursor.cw + dw,
self.cursor.ch - dh,
);
}
pub fn drag(&mut self, dx: isize, dy: isize) {
if self.mode == InputMode::Append {
self.mode = InputMode::Normal;
}
let max_x_allowed = self.o2.w.saturating_sub(1);
let max_y_allowed = self.o2.h.saturating_sub(1);
let actual_dx = dx.clamp(
-(self.cursor.min_x as isize),
(max_x_allowed.saturating_sub(self.cursor.max_x)) as isize,
);
let actual_dy = (-dy).clamp(
-(self.cursor.min_y as isize),
(max_y_allowed.saturating_sub(self.cursor.max_y)) as isize,
);
if actual_dx == 0 && actual_dy == 0 {
return;
}
let rows_count = (self.cursor.max_y - self.cursor.min_y) + 1;
let cols_count = (self.cursor.max_x - self.cursor.min_x) + 1;
let mut block = Vec::with_capacity(rows_count * cols_count);
for y in self.cursor.min_y..=self.cursor.max_y {
for x in self.cursor.min_x..=self.cursor.max_x {
if let Some(idx) = self.o2.index_at(x, y) {
block.push(self.o2.cells[idx]);
} else {
block.push('.');
}
}
}
for y in self.cursor.min_y..=self.cursor.max_y {
for x in self.cursor.min_x..=self.cursor.max_x {
if let Some(idx) = self.o2.index_at(x, y) {
self.o2.cells[idx] = '.';
}
}
}
self.move_cursor(actual_dx, -actual_dy);
let mut block_iter = block.into_iter();
for y in self.cursor.min_y..=self.cursor.max_y {
for x in self.cursor.min_x..=self.cursor.max_x {
if let Some(g) = block_iter.next()
&& let Some(idx) = self.o2.index_at(x, y)
{
self.o2.cells[idx] = g;
}
}
}
self.history.record(&self.o2.cells);
}
pub fn is_selected(&self, x: usize, y: usize) -> bool {
x >= self.cursor.min_x
&& x <= self.cursor.max_x
&& y >= self.cursor.min_y
&& y <= self.cursor.max_y
}
pub fn write_cursor(&mut self, g: char) {
let allowed_g = if Self::is_allowed(g) { g } else { '.' };
if self.mode == InputMode::Append {
if let Some(idx) = self.o2.index_at(self.cursor.cx, self.cursor.cy) {
self.o2.cells[idx] = allowed_g;
self.move_cursor(1, 0);
self.history.record(&self.o2.cells);
}
} else {
let mut changed = false;
for y in self.cursor.min_y..=self.cursor.max_y {
for x in self.cursor.min_x..=self.cursor.max_x {
if let Some(idx) = self.o2.index_at(x, y)
&& self.o2.cells[idx] != allowed_g
{
self.o2.cells[idx] = allowed_g;
changed = true;
}
}
}
if changed {
self.history.record(&self.o2.cells);
}
}
}
pub fn erase(&mut self) {
for y in self.cursor.min_y..=self.cursor.max_y {
for x in self.cursor.min_x..=self.cursor.max_x {
if let Some(idx) = self.o2.index_at(x, y) {
self.o2.cells[idx] = '.';
}
}
}
self.history.record(&self.o2.cells);
}
pub fn make_uppercase(&mut self) {
for y in self.cursor.min_y..=self.cursor.max_y {
for x in self.cursor.min_x..=self.cursor.max_x {
let g = self.glyph_at(x, y);
if g.is_ascii_lowercase() {
self.o2.write_silent(x, y, g.to_ascii_uppercase());
}
}
}
self.history.record(&self.o2.cells);
}
pub fn make_lowercase(&mut self) {
for y in self.cursor.min_y..=self.cursor.max_y {
for x in self.cursor.min_x..=self.cursor.max_x {
let g = self.glyph_at(x, y);
if g.is_ascii_uppercase() {
self.o2.write_silent(x, y, g.to_ascii_lowercase());
}
}
}
self.history.record(&self.o2.cells);
}
pub fn toggle_comment(&mut self) {
let first_char = self.glyph_at(self.cursor.min_x, self.cursor.min_y);
let c = if first_char == '#' { '.' } else { '#' };
for y in self.cursor.min_y..=self.cursor.max_y {
let width = self.cursor.max_x - self.cursor.min_x + 1;
if width > 1 {
self.o2.write_silent(self.cursor.min_x, y, c);
self.o2.write_silent(self.cursor.max_x, y, c);
} else {
self.o2.write_silent(self.cursor.min_x, y, c);
}
}
self.history.record(&self.o2.cells);
}
}