use crate::text::Target;
use crate::widget::Id;
use crate::widget::operation::{Operation, Outcome, Scrollable};
use crate::{Point, Rectangle, Vector};
pub trait Selectable {
fn select(&mut self, start: Point, end: Point, target: Target);
fn select_all(&mut self);
fn deselect(&mut self);
fn copy(&mut self) -> Option<String>;
}
pub fn select(start: Point, end: Point, target: Target) -> impl Operation {
struct Select {
start: Point,
end: Point,
target: Target,
translation: Vector,
}
impl Operation for Select {
fn traverse(&mut self, operate: &mut dyn FnMut(&mut dyn Operation)) {
let translation = self.translation;
operate(self);
self.translation = translation;
}
fn scrollable(
&mut self,
_id: Option<&Id>,
_bounds: Rectangle,
_content_bounds: Rectangle,
translation: Vector,
_state: &mut dyn Scrollable,
) {
self.translation += translation;
}
fn selectable_text(
&mut self,
_id: Option<&Id>,
_bounds: Rectangle,
state: &mut dyn Selectable,
) {
state.select(
self.start + self.translation,
self.end + self.translation,
self.target,
);
}
}
Select {
start,
end,
target,
translation: Vector::ZERO,
}
}
pub fn select_all() -> impl Operation {
struct SelectAll;
impl Operation for SelectAll {
fn traverse(&mut self, operate: &mut dyn FnMut(&mut dyn Operation)) {
operate(self);
}
fn selectable_text(
&mut self,
_id: Option<&Id>,
_bounds: Rectangle,
state: &mut dyn Selectable,
) {
state.select_all();
}
}
SelectAll
}
pub fn deselect() -> impl Operation {
struct Deselect;
impl Operation for Deselect {
fn traverse(&mut self, operate: &mut dyn FnMut(&mut dyn Operation)) {
operate(self);
}
fn selectable_text(
&mut self,
_id: Option<&Id>,
_bounds: Rectangle,
state: &mut dyn Selectable,
) {
state.deselect();
}
}
Deselect
}
pub fn copy() -> impl Operation<String> {
struct Copy {
text: String,
}
impl Operation<String> for Copy {
fn traverse(&mut self, operate: &mut dyn FnMut(&mut dyn Operation<String>)) {
operate(self);
}
fn selectable_text(
&mut self,
_id: Option<&Id>,
_bounds: Rectangle,
state: &mut dyn Selectable,
) {
let Some(text) = state.copy().filter(|text| !text.is_empty()) else {
return;
};
if !self.text.is_empty() {
self.text.push('\n');
}
self.text.push_str(&text);
}
fn finish(&self) -> Outcome<String> {
if self.text.is_empty() {
Outcome::None
} else {
Outcome::Some(self.text.clone())
}
}
}
Copy {
text: String::new(),
}
}