use crate::{
ContainerAtom, Id, IdSalt, IntoAtoms, Response, Sense, SizedContainerAtom, Ui, Widget,
};
use core::ops::{Deref, DerefMut};
use emath::{Rect, Vec2};
use smallvec::SmallVec;
#[derive(Clone)]
pub struct WidgetAtom<'a> {
pub(crate) id: Option<Id>,
pub(crate) sense: Sense,
selectable: bool,
pub container: ContainerAtom<'a>,
}
impl Default for WidgetAtom<'_> {
fn default() -> Self {
Self::new(())
}
}
impl<'a> WidgetAtom<'a> {
pub fn new(atoms: impl IntoAtoms<'a>) -> Self {
Self {
id: None,
sense: Sense::hover(),
selectable: false,
container: ContainerAtom::new(atoms),
}
}
#[inline]
pub fn id(mut self, id: Id) -> Self {
self.id = Some(id);
self
}
#[inline]
pub fn sense(mut self, sense: Sense) -> Self {
self.sense = sense;
self
}
#[inline]
pub fn selectable(mut self, selectable: bool) -> Self {
self.selectable = selectable;
self
}
pub fn show(self, ui: &mut Ui) -> WidgetAtomResponse {
self.allocate(ui).paint(ui)
}
pub fn measure(self, ui: &Ui, available_size: Vec2) -> SizedWidgetAtom<'a> {
let Self {
id,
mut sense,
selectable,
container,
} = self;
if selectable {
let allow_drag_to_select = ui.input(|i| !i.has_touch_screen());
let mut select_sense = if allow_drag_to_select {
Sense::click_and_drag()
} else {
Sense::click()
};
select_sense -= Sense::FOCUSABLE;
sense |= select_sense;
}
let id = id.unwrap_or_else(|| ui.next_auto_id());
let container = container.measure(ui, available_size);
SizedWidgetAtom {
id,
sense,
selectable,
container,
}
}
pub fn allocate(self, ui: &mut Ui) -> AllocatedWidgetAtom<'a> {
self.measure(ui, ui.available_size()).allocate(ui)
}
}
#[derive(Clone, Debug)]
pub struct SizedWidgetAtom<'a> {
id: Id,
sense: Sense,
selectable: bool,
pub container: SizedContainerAtom<'a>,
}
impl<'a> SizedWidgetAtom<'a> {
pub fn allocate(self, ui: &mut Ui) -> AllocatedWidgetAtom<'a> {
let (_, rect) = ui.allocate_space(self.container.outer_size);
let mut response = ui.interact(rect, self.id, self.sense);
response.set_intrinsic_size(self.container.intrinsic_size);
AllocatedWidgetAtom {
container: self.container,
selectable: self.selectable,
response,
}
}
pub fn paint_at(self, ui: &Ui, rect: Rect) -> WidgetAtomResponse {
let response = ui.interact(rect, self.id, self.sense);
let custom_rects =
self.container
.paint_at_with_selection(ui, rect, self.selectable.then_some(&response));
WidgetAtomResponse {
response,
custom_rects,
}
}
}
#[derive(Clone, Debug)]
pub struct AllocatedWidgetAtom<'a> {
selectable: bool,
pub container: SizedContainerAtom<'a>,
pub response: Response,
}
impl AllocatedWidgetAtom<'_> {
pub fn paint(self, ui: &Ui) -> WidgetAtomResponse {
let rect = self.response.rect;
let custom_rects = self.container.paint_at_with_selection(
ui,
rect,
self.selectable.then_some(&self.response),
);
WidgetAtomResponse {
response: self.response,
custom_rects,
}
}
}
#[derive(Clone, Debug)]
pub struct WidgetAtomResponse {
pub response: Response,
pub(crate) custom_rects: SmallVec<[(IdSalt, Rect); 1]>,
}
impl WidgetAtomResponse {
pub fn empty(response: Response) -> Self {
Self {
response,
custom_rects: Default::default(),
}
}
pub fn custom_rects(&self) -> impl Iterator<Item = (IdSalt, Rect)> + '_ {
self.custom_rects.iter().copied()
}
pub fn rect(&self, id: IdSalt) -> Option<Rect> {
self.custom_rects
.iter()
.find_map(|(i, r)| if *i == id { Some(*r) } else { None })
}
}
impl Deref for WidgetAtomResponse {
type Target = Response;
fn deref(&self) -> &Self::Target {
&self.response
}
}
impl DerefMut for WidgetAtomResponse {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.response
}
}
impl Widget for WidgetAtom<'_> {
fn ui(self, ui: &mut Ui) -> Response {
self.show(ui).response
}
}
impl<'a> Deref for WidgetAtom<'a> {
type Target = ContainerAtom<'a>;
fn deref(&self) -> &Self::Target {
&self.container
}
}
impl DerefMut for WidgetAtom<'_> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.container
}
}
impl<'a> Deref for SizedWidgetAtom<'a> {
type Target = SizedContainerAtom<'a>;
fn deref(&self) -> &Self::Target {
&self.container
}
}
impl DerefMut for SizedWidgetAtom<'_> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.container
}
}
impl<'a> Deref for AllocatedWidgetAtom<'a> {
type Target = SizedContainerAtom<'a>;
fn deref(&self) -> &Self::Target {
&self.container
}
}
impl DerefMut for AllocatedWidgetAtom<'_> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.container
}
}
#[deprecated = "Renamed to `WidgetAtom`"]
pub type AtomLayout<'a> = WidgetAtom<'a>;
#[deprecated = "Renamed to `SizedWidgetAtom`"]
pub type SizedAtomLayout<'a> = SizedWidgetAtom<'a>;
#[deprecated = "Renamed to `AllocatedWidgetAtom`"]
pub type AllocatedAtomLayout<'a> = AllocatedWidgetAtom<'a>;
#[deprecated = "Renamed to `WidgetAtomResponse`"]
pub type AtomLayoutResponse = WidgetAtomResponse;