use super::*;
use util::{caption::CaptionMut, state::AtomState};
use std::{sync::Arc, ops::{Range, RangeInclusive}};
pub struct TBState<E> where E: Env {
pub off: (u32,u32), pub max_off: (u32,u32),
pub cursor: Cursor,
pub glyphs: Arc<ESGlyphs<E>>,
}
impl<E> TBState<E> where E: Env {
pub fn retrieve<'a,S,P,C>(caption: &S, glyphs: Arc<ESGlyphs<E>>, p: &P, c: &C, ctx: &mut E::Context, b: &Bounds) -> Self where S: Caption<E>+'a, P: AtomState<E,(u32,u32)>, C: AtomState<E,Cursor> {
let off = p.get(ctx);
let siz = glyphs.size();
let max_off = (
siz.w.saturating_sub( b.w() ),
siz.h.saturating_sub( b.h() ),
);
let cursor = c.get(ctx);
let num_glyphs = caption.len() as u32;
let cursor = cursor.min(num_glyphs);
Self{
off,
max_off,
cursor,
glyphs,
}
}
pub fn bound_off(&self, o: (u32,u32)) -> (u32,u32) {
(
o.0.min(self.max_off.0),
o.1.min(self.max_off.1),
)
}
pub fn bound_off2(&self, o: (u32,u32)) -> Offset {
Offset{
x: o.0.min(self.max_off.0) as i32,
y: o.1.min(self.max_off.1) as i32,
}
}
pub fn off2(&self) -> Offset {
Offset{
x: self.off.0 as i32,
y: self.off.1 as i32,
}
}
pub fn cursor_display_pos(&self, i: u32) -> Option<(u32,u32)> {
self.glyphs.char_at(i)
.map(|i|
(
i.offset().x as u32,
i.offset().y as u32,
)
)
}
pub fn cpl(&self, i: u32) -> Option<((u32,u32),Bounds,usize)> {
let mut j = 0;
for (k,l) in self.glyphs.lines().enumerate() {
for c in l.0 {
if i == j {
return Some((
(
c.offset().x as u32,
(c.offset().y as u32).saturating_sub(self.glyphs.line_ascent()),
),
l.1,
k
));
}
j+=1;
}
}
None
}
pub fn selection_box(&self) -> Vec<Bounds> {
let sel = self.cursor.range();
if sel.len() == 0 {
return Vec::new();
}
let start = self.cpl(sel.start).unwrap();
let end = self.cpl(sel.end).unwrap();
assert!(end.2 >= start.2);
let mut dest = Vec::new();
if start.2 == end.2 {
return vec![
Bounds::from_xyxy(
start.0 .0 as i32,
start.1 .y(),
end.0 .0 as i32,
start.1 .y1(),
)
];
}
dest.push(Bounds::from_xyxy(
start.0 .0 as i32,
start.1 .y(),
start.1 .x1(),
start.1 .y1(),
));
for i in start.2+1 .. end.2 {
let b = self.glyphs.lines().skip(i).next().unwrap().1; dest.push(b);
}
dest.push(Bounds::from_xyxy(
end.1 .x(),
end.1 .y(),
end.0 .0 as i32,
end.1 .y1(),
));
dest
}
pub fn cursor_pos_reverse(&self, pos: Offset) -> u32 {
self.glyphs.glyphs()
.enumerate()
.filter(|(_,b)| b.offset().y <= pos.y && b.offset().x <= pos.x )
.map(|(i,_)| i as u32 )
.last() .unwrap_or(0)
}
pub fn cursor_pos_reverse_line_centric(&self, line: u32, x: i32) -> Option<u32> {
fn try_centerx<E>(p: &ESGlyph<E>) -> i32 where E: Env {
if let Some(o) = p.bounds() {
o.center().x
}else{
p.offset().x
}
}
self.glyphs.lines()
.skip(line as usize)
.next()
.map(|(l,_)| {
let mut last = 0;
for (i,b) in l.enumerate() {
if try_centerx::<E>(&b) >= x {
return i as u32;
}
last = i;
}
return last as u32;
})
}
}
#[derive(Copy,Clone,Default)]
pub struct Cursor {
pub select: u32,
pub caret: u32,
}
impl Cursor {
pub fn min(&self, min: u32) -> Self {
Self{
select: self.select.min(min),
caret: self.caret.min(min),
}
}
pub fn range(&self) -> Range<u32> {
self.select.min(self.caret) .. self.select.max(self.caret)
}
pub fn range_usize(&self) -> Range<usize> {
self.select.min(self.caret) as usize .. self.select.max(self.caret) as usize
}
pub fn range_incl(&self) -> RangeInclusive<u32> {
self.select.min(self.caret) ..= self.select.max(self.caret)
}
pub fn start_len(&self) -> (u32,u32) {
let r = self.range();
(r.start,r.end-r.start)
}
pub fn is_selection(&self) -> bool {
self.select != self.caret
}
pub fn unselect(&mut self) {
self.select = self.caret;
}
pub fn unselect_add(&mut self, o: u32, skip_unselect: bool) {
self.caret += o;
if !skip_unselect {
self.select = self.caret;
}
}
pub fn unselect_sub(&mut self, o: u32, skip_unselect: bool) {
self.caret = self.caret.saturating_sub(o);
if !skip_unselect {
self.select = self.caret;
}
}
pub fn unselect_addi(&mut self, o: i32, skip_unselect: bool) {
self.caret = (self.caret as i32 +o).max(0) as u32;
if !skip_unselect {
self.select = self.caret;
}
}
pub fn limit(&mut self, min: u32) {
*self = self.min(min);
}
pub fn del_selection<'a,S,E>(&mut self, c: &mut S) where S: CaptionMut<E>+'a {
let (start,len) = self.start_len();
c.pop_left((start+len) as usize, len as usize);
self.caret = start;
self.unselect();
}
}