use crate::dir::Direction;
use crate::event::{Event, EventCx, IsUsed, Scroll, Unused, Used};
#[allow(unused)] use crate::geom::Rect;
use crate::layout::Align;
use crate::window::WindowId;
use crate::{ChildIndices, Events, Id, Tile, Widget};
use kas_macros::{impl_self, widget_index};
#[allow(unused)] use crate::event::EventState;
#[derive(Clone, Debug)]
pub(crate) struct PopupDescriptor {
pub id: Id,
pub parent: Id,
pub direction: Direction,
pub align: Align,
}
pub(crate) const POPUP_INNER_INDEX: usize = 0;
#[impl_self]
mod Popup {
#[widget]
#[layout(frame!(self.inner).with_style(kas::theme::FrameStyle::Popup))]
pub struct Popup<W: Widget> {
core: widget_core!(),
direction: Direction,
align: Align,
#[widget]
pub inner: W,
win_id: Option<WindowId>,
}
impl Tile for Self {
fn child_indices(&self) -> ChildIndices {
ChildIndices::none()
}
fn find_child_index(&self, id: &Id) -> Option<usize> {
let index = Some(widget_index!(self.inner));
if self.win_id.is_none() || id.next_key_after(self.id_ref()) != index {
return None;
}
index
}
}
impl Events for Self {
type Data = W::Data;
#[inline]
fn recurse_indices(&self) -> ChildIndices {
if self.win_id.is_some() {
ChildIndices::one(widget_index!(self.inner))
} else {
ChildIndices::none()
}
}
fn handle_event(&mut self, _: &mut EventCx, _: &W::Data, event: Event) -> IsUsed {
match event {
Event::PopupClosed(_) => {
self.win_id = None;
Used
}
_ => Unused,
}
}
fn handle_scroll(&mut self, cx: &mut EventCx, _: &Self::Data, _: Scroll) {
cx.set_scroll(Scroll::None);
}
}
impl Self {
pub fn new(inner: W, direction: Direction) -> Self {
Popup {
core: Default::default(),
direction,
align: Align::Default,
inner,
win_id: None,
}
}
pub fn direction(&self) -> Direction {
self.direction
}
pub fn set_direction(&mut self, direction: Direction) {
self.direction = direction;
}
#[inline]
pub fn alignment(&self) -> Align {
self.align
}
#[must_use]
#[inline]
pub fn align(mut self, align: Align) -> Self {
self.align = align;
self
}
pub fn is_open(&self) -> bool {
self.win_id.is_some()
}
pub fn open(
&mut self,
cx: &mut EventCx,
data: &W::Data,
parent: Id,
set_focus: bool,
) -> bool {
let desc = PopupDescriptor {
id: self.id(),
parent,
direction: self.direction,
align: self.align,
};
if let Some(id) = self.win_id {
cx.reposition_popup(id, desc);
return false;
}
let index = widget_index!(self.inner);
assert_eq!(index, POPUP_INNER_INDEX);
let id = self.make_child_id(index);
cx.configure(self.inner.as_node(data), id);
self.win_id = Some(cx.add_popup(desc, set_focus));
true
}
pub fn close(&mut self, cx: &mut EventCx) {
if let Some(id) = self.win_id.take() {
cx.close_window(id);
}
}
}
}