use kas::Collection;
use kas::dir::{Down, Right};
use kas::layout::{
DynRowStorage, RowPositionSolver, RowSetter, RowSolver, RowStorage, RulesSetter, RulesSolver,
};
use kas::prelude::*;
use std::collections::hash_map::{Entry, HashMap};
use std::ops::{Index, IndexMut};
#[macro_export]
macro_rules! row {
( $( $ee:expr ),* ) => {
$crate::Row::new( ::kas::collection! [ $( $ee ),* ] )
};
( $( $ee:expr ),+ , ) => {
$crate::Row::new( ::kas::collection! [ $( $ee ),+ ] )
};
}
#[macro_export]
macro_rules! column {
( $( $ee:expr ),* ) => {
$crate::Column::new( ::kas::collection! [ $( $ee ),* ] )
};
( $( $ee:expr ),+ , ) => {
$crate::Column::new( ::kas::collection! [ $( $ee ),+ ] )
};
}
#[macro_export]
macro_rules! list {
( $( $ee:expr ),* ) => {
$crate::List::new( ::kas::collection! [ $( $ee ),* ] )
};
( $( $ee:expr ),+ , ) => {
$crate::List::new( ::kas::collection! [ $( $ee ),+ ] )
};
}
pub type Row<C> = List<C, Right>;
pub type Column<C> = List<C, Down>;
#[impl_self]
mod List {
#[autoimpl(Default where C: Default, D: Default)]
#[widget]
pub struct List<C: Collection, D: Directional> {
pub(crate) core: widget_core!(),
pub(crate) layout: DynRowStorage,
#[collection]
pub(crate) widgets: C,
pub(crate) direction: D,
next: usize,
id_map: HashMap<usize, usize>, }
impl Layout for Self {
fn size_rules(&mut self, cx: &mut SizeCx, axis: AxisInfo) -> SizeRules {
let dim = (self.direction, self.widgets.len());
let mut solver = RowSolver::new(axis, dim, &mut self.layout);
for n in 0..self.widgets.len() {
if let Some(child) = self.widgets.get_mut_tile(n) {
solver.for_child(&mut self.layout, n, |axis| child.size_rules(cx, axis));
}
}
solver.finish(&mut self.layout)
}
fn set_rect(&mut self, cx: &mut SizeCx, rect: Rect, hints: AlignHints) {
self.core.set_rect(rect);
let dim = (self.direction, self.widgets.len());
let mut setter = RowSetter::<D, Vec<i32>, _>::new(rect, dim, &mut self.layout);
for n in 0..self.widgets.len() {
if let Some(child) = self.widgets.get_mut_tile(n) {
child.set_rect(cx, setter.child_rect(&mut self.layout, n), hints);
}
}
}
fn draw(&self, mut draw: DrawCx) {
let solver = RowPositionSolver::new(self.direction);
solver.for_children(&self.widgets, draw.get_clip_rect(), |w| w.draw(draw.re()));
}
}
impl Tile for Self {
fn role(&self, _: &mut dyn RoleCx) -> Role<'_> {
Role::None
}
fn find_child_index(&self, id: &Id) -> Option<usize> {
id.next_key_after(self.id_ref())
.and_then(|k| self.id_map.get(&k).cloned())
}
}
impl Events for Self {
type Data = C::Data;
fn make_child_id(&mut self, index: usize) -> Id {
if let Some(child) = self.widgets.get_tile(index) {
if child.id_ref().is_valid() {
if let Some(key) = child.id_ref().next_key_after(self.id_ref()) {
if let Entry::Vacant(entry) = self.id_map.entry(key) {
entry.insert(index);
return child.id();
}
}
}
}
loop {
let key = self.next;
self.next += 1;
if let Entry::Vacant(entry) = self.id_map.entry(key) {
entry.insert(index);
return self.id_ref().make_child(key);
}
}
}
fn probe(&self, coord: Coord) -> Id {
let solver = RowPositionSolver::new(self.direction);
solver
.find_child(&self.widgets, coord)
.and_then(|child| child.try_probe(coord))
.unwrap_or_else(|| self.id())
}
fn configure(&mut self, _: &mut ConfigCx) {
self.id_map.clear();
}
}
impl Self
where
D: Default,
{
#[inline]
pub fn new(widgets: C) -> Self {
Self::new_dir(widgets, D::default())
}
}
impl<C: Collection> List<C, kas::dir::Left> {
#[inline]
pub fn left(widgets: C) -> Self {
Self::new(widgets)
}
}
impl<C: Collection> List<C, kas::dir::Right> {
#[inline]
pub fn right(widgets: C) -> Self {
Self::new(widgets)
}
}
impl<C: Collection> List<C, kas::dir::Up> {
#[inline]
pub fn up(widgets: C) -> Self {
Self::new(widgets)
}
}
impl<C: Collection> List<C, kas::dir::Down> {
#[inline]
pub fn down(widgets: C) -> Self {
Self::new(widgets)
}
}
impl<C: Collection, D: Directional + Eq> List<C, D> {
pub fn set_direction(&mut self, cx: &mut ConfigCx, direction: D) {
if direction == self.direction {
return;
}
self.direction = direction;
cx.resize();
}
}
impl Self {
#[inline]
pub fn new_dir(widgets: C, direction: D) -> Self {
List {
core: Default::default(),
layout: Default::default(),
widgets,
direction,
next: 0,
id_map: Default::default(),
}
}
pub fn direction(&self) -> Direction {
self.direction.as_direction()
}
#[inline]
pub fn with_direction(mut self, direction: D) -> Self {
self.direction = direction;
self
}
#[inline]
pub fn layout_storage(&mut self) -> &mut (impl RowStorage + use<C, D>) {
&mut self.layout
}
pub fn is_empty(&self) -> bool {
self.widgets.is_empty()
}
pub fn len(&self) -> usize {
self.widgets.len()
}
}
impl<W: Widget, D: Directional> List<Vec<W>, D> {
pub fn get(&self, index: usize) -> Option<&W> {
self.widgets.get(index)
}
pub fn get_mut(&mut self, index: usize) -> Option<&mut W> {
self.widgets.get_mut(index)
}
pub fn clear(&mut self) {
self.widgets.clear();
}
pub fn push(&mut self, cx: &mut ConfigCx, data: &W::Data, mut widget: W) -> usize {
let index = self.widgets.len();
let id = self.make_child_id(index);
cx.configure(widget.as_node(data), id);
self.widgets.push(widget);
cx.resize();
index
}
pub fn pop(&mut self, cx: &mut ConfigCx) -> Option<W> {
let result = self.widgets.pop();
if let Some(w) = result.as_ref() {
cx.resize();
if w.id_ref().is_valid() {
if let Some(key) = w.id_ref().next_key_after(self.id_ref()) {
self.id_map.remove(&key);
}
}
}
result
}
pub fn insert(&mut self, cx: &mut ConfigCx, data: &W::Data, index: usize, mut widget: W) {
for v in self.id_map.values_mut() {
if *v >= index {
*v += 1;
}
}
let id = self.make_child_id(index);
cx.configure(widget.as_node(data), id);
self.widgets.insert(index, widget);
cx.resize();
}
pub fn remove(&mut self, cx: &mut ConfigCx, index: usize) -> W {
let w = self.widgets.remove(index);
if w.id_ref().is_valid() {
if let Some(key) = w.id_ref().next_key_after(self.id_ref()) {
self.id_map.remove(&key);
}
}
cx.resize();
for v in self.id_map.values_mut() {
if *v > index {
*v -= 1;
}
}
w
}
pub fn truncate(&mut self, cx: &mut ConfigCx, len: usize) {
if len < self.len() {
cx.resize();
loop {
let w = self.widgets.pop().unwrap();
if w.id_ref().is_valid() {
if let Some(key) = w.id_ref().next_key_after(self.id_ref()) {
self.id_map.remove(&key);
}
}
if len == self.widgets.len() {
return;
}
}
}
}
pub fn replace(&mut self, cx: &mut ConfigCx, data: &W::Data, index: usize, mut w: W) -> W {
let id = self.make_child_id(index);
cx.configure(w.as_node(data), id);
std::mem::swap(&mut w, &mut self.widgets[index]);
if w.id_ref().is_valid() {
if let Some(key) = w.id_ref().next_key_after(self.id_ref()) {
self.id_map.remove(&key);
}
}
cx.resize();
w
}
pub fn extend<T>(&mut self, cx: &mut ConfigCx, data: &W::Data, iter: T)
where
T: IntoIterator<Item = W>,
{
let iter = iter.into_iter();
if let Some(ub) = iter.size_hint().1 {
self.widgets.reserve(ub);
}
for mut w in iter {
let id = self.make_child_id(self.widgets.len());
cx.configure(w.as_node(data), id);
self.widgets.push(w);
}
cx.resize();
}
pub fn resize_with<F>(&mut self, cx: &mut ConfigCx, data: &W::Data, len: usize, f: F)
where
F: Fn(usize) -> W,
{
let old_len = self.widgets.len();
if len < old_len {
cx.resize();
loop {
let w = self.widgets.pop().unwrap();
if w.id_ref().is_valid() {
if let Some(key) = w.id_ref().next_key_after(self.id_ref()) {
self.id_map.remove(&key);
}
}
if len == self.widgets.len() {
return;
}
}
}
if len > old_len {
self.widgets.reserve(len - old_len);
for index in old_len..len {
let id = self.make_child_id(index);
let mut w = f(index);
cx.configure(w.as_node(data), id);
self.widgets.push(w);
}
cx.resize();
}
}
pub fn iter(&self) -> impl Iterator<Item = &W> {
ListIter {
list: &self.widgets,
}
}
pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut W> {
ListIterMut {
list: &mut self.widgets,
}
}
}
impl<W: Widget, D: Directional> Index<usize> for List<Vec<W>, D> {
type Output = W;
fn index(&self, index: usize) -> &Self::Output {
&self.widgets[index]
}
}
impl<W: Widget, D: Directional> IndexMut<usize> for List<Vec<W>, D> {
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
&mut self.widgets[index]
}
}
}
struct ListIter<'a, W: Widget> {
list: &'a [W],
}
impl<'a, W: Widget> Iterator for ListIter<'a, W> {
type Item = &'a W;
fn next(&mut self) -> Option<Self::Item> {
if let Some((first, rest)) = self.list.split_first() {
self.list = rest;
Some(first)
} else {
None
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
let len = self.len();
(len, Some(len))
}
}
impl<'a, W: Widget> ExactSizeIterator for ListIter<'a, W> {
fn len(&self) -> usize {
self.list.len()
}
}
struct ListIterMut<'a, W: Widget> {
list: &'a mut [W],
}
impl<'a, W: Widget> Iterator for ListIterMut<'a, W> {
type Item = &'a mut W;
fn next(&mut self) -> Option<Self::Item> {
let list = std::mem::take(&mut self.list);
if let Some((first, rest)) = list.split_first_mut() {
self.list = rest;
Some(first)
} else {
None
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
let len = self.len();
(len, Some(len))
}
}
impl<'a, W: Widget> ExactSizeIterator for ListIterMut<'a, W> {
fn len(&self) -> usize {
self.list.len()
}
}