use kas::layout::{DynGridStorage, GridCellInfo, GridDimensions};
use kas::layout::{GridSetter, GridSolver, RulesSetter, RulesSolver};
use kas::{CellCollection, layout, prelude::*};
use std::ops::{Index, IndexMut};
#[macro_export]
macro_rules! grid {
( $($tt:tt)* ) => {
$crate::Grid::new( ::kas::cell_collection! { $($tt)* } )
};
}
#[impl_self]
mod Grid {
#[widget]
pub struct Grid<C: CellCollection> {
core: widget_core!(),
layout: DynGridStorage,
dim: GridDimensions,
#[collection]
widgets: C,
}
impl Layout for Self {
fn size_rules(&mut self, cx: &mut SizeCx, axis: AxisInfo) -> SizeRules {
let mut solver = GridSolver::<Vec<_>, Vec<_>, _>::new(axis, self.dim, &mut self.layout);
for n in 0..self.widgets.len() {
if let Some((info, child)) =
self.widgets.cell_info(n).zip(self.widgets.get_mut_tile(n))
{
solver.for_child(&mut self.layout, info, |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 mut setter = GridSetter::<Vec<_>, Vec<_>, _>::new(rect, self.dim, &mut self.layout);
for n in 0..self.widgets.len() {
if let Some((info, child)) =
self.widgets.cell_info(n).zip(self.widgets.get_mut_tile(n))
{
child.set_rect(cx, setter.child_rect(&mut self.layout, info), hints);
}
}
}
fn draw(&self, mut draw: DrawCx) {
for n in (0..self.widgets.len()).rev() {
if let Some(child) = self.widgets.get_tile(n) {
child.draw(draw.re());
}
}
}
}
impl Tile for Self {
fn role(&self, _: &mut dyn RoleCx) -> Role<'_> {
Role::None
}
}
impl Events for Self {
type Data = C::Data;
fn probe(&self, coord: Coord) -> Id {
for n in 0..self.widgets.len() {
if let Some(child) = self.widgets.get_tile(n) {
if let Some(id) = child.try_probe(coord) {
return id;
}
}
}
self.id()
}
}
}
impl<C: CellCollection> Grid<C> {
#[inline]
pub fn new(widgets: C) -> Self {
Grid {
core: Default::default(),
layout: Default::default(),
dim: widgets.grid_dimensions(),
widgets,
}
}
#[inline]
pub fn dimensions(&self) -> GridDimensions {
self.dim
}
#[inline]
pub fn layout_storage(&mut self) -> &mut (impl layout::GridStorage + use<C>) {
&mut self.layout
}
}
impl<W: Widget> Grid<Vec<(GridCellInfo, W)>> {
pub fn build<F: FnOnce(GridBuilder<W>)>(f: F) -> Self {
let mut grid = Grid::new(vec![]);
f(GridBuilder(&mut grid.widgets));
grid.dim = grid.widgets.grid_dimensions();
grid
}
pub fn is_empty(&self) -> bool {
self.widgets.is_empty()
}
pub fn len(&self) -> usize {
self.widgets.len()
}
pub fn get(&self, index: usize) -> Option<&W> {
self.widgets.get(index).map(|t| &t.1)
}
pub fn get_mut(&mut self, index: usize) -> Option<&mut W> {
self.widgets.get_mut(index).map(|t| &mut t.1)
}
pub fn iter(&self) -> impl Iterator<Item = &(GridCellInfo, W)> {
ListIter {
list: &self.widgets,
}
}
pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut (GridCellInfo, W)> {
ListIterMut {
list: &mut self.widgets,
}
}
}
pub struct GridBuilder<'a, W: Widget>(&'a mut Vec<(GridCellInfo, W)>);
impl<'a, W: Widget> GridBuilder<'a, W> {
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
pub fn len(&self) -> usize {
self.0.len()
}
pub fn capacity(&self) -> usize {
self.0.capacity()
}
pub fn reserve(&mut self, additional: usize) {
self.0.reserve(additional);
}
pub fn clear(&mut self) {
self.0.clear();
}
pub fn push(&mut self, info: GridCellInfo, widget: W) {
self.0.push((info, widget));
}
pub fn push_cell(&mut self, col: u32, row: u32, widget: W) {
let info = GridCellInfo::new(col, row);
self.push(info, widget);
}
#[must_use]
pub fn with_cell(self, col: u32, row: u32, widget: W) -> Self {
self.with_cell_span(col, row, 1, 1, widget)
}
pub fn push_cell_span(&mut self, col: u32, row: u32, col_span: u32, row_span: u32, widget: W) {
let info = GridCellInfo {
col,
last_col: col + col_span - 1,
row,
last_row: row + row_span - 1,
};
self.push(info, widget);
}
#[must_use]
pub fn with_cell_span(
mut self,
col: u32,
row: u32,
col_span: u32,
row_span: u32,
widget: W,
) -> Self {
self.push_cell_span(col, row, col_span, row_span, widget);
self
}
pub fn pop(&mut self) -> Option<(GridCellInfo, W)> {
self.0.pop()
}
pub fn insert(&mut self, index: usize, info: GridCellInfo, widget: W) {
self.0.insert(index, (info, widget));
}
pub fn remove(&mut self, index: usize) -> (GridCellInfo, W) {
self.0.remove(index)
}
pub fn replace(&mut self, index: usize, info: GridCellInfo, widget: W) -> (GridCellInfo, W) {
let mut item = (info, widget);
std::mem::swap(&mut item, &mut self.0[index]);
item
}
pub fn extend<T: IntoIterator<Item = (GridCellInfo, W)>>(&mut self, iter: T) {
self.0.extend(iter);
}
pub fn resize_with<F: Fn(usize) -> (GridCellInfo, W)>(&mut self, len: usize, f: F) {
let l0 = self.0.len();
if l0 > len {
self.0.truncate(len);
} else if l0 < len {
self.0.reserve(len);
for i in l0..len {
self.0.push(f(i));
}
}
}
pub fn retain<F: FnMut(&(GridCellInfo, W)) -> bool>(&mut self, f: F) {
self.0.retain(f);
}
pub fn find_child_cell(&self, col: u32, row: u32) -> Option<usize> {
for (i, (info, _)) in self.0.iter().enumerate() {
if info.col <= col && col <= info.last_col && info.row <= row && row <= info.last_row {
return Some(i);
}
}
None
}
pub fn iter(&self) -> impl Iterator<Item = &(GridCellInfo, W)> {
ListIter { list: self.0 }
}
pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut (GridCellInfo, W)> + use<'_, W> {
ListIterMut { list: self.0 }
}
}
impl<W: Widget> FromIterator<(GridCellInfo, W)> for Grid<Vec<(GridCellInfo, W)>> {
#[inline]
fn from_iter<T>(iter: T) -> Self
where
T: IntoIterator<Item = (GridCellInfo, W)>,
{
Self::new(iter.into_iter().collect())
}
}
impl<W: Widget> Index<usize> for Grid<Vec<(GridCellInfo, W)>> {
type Output = (GridCellInfo, W);
fn index(&self, index: usize) -> &Self::Output {
&self.widgets[index]
}
}
impl<W: Widget> IndexMut<usize> for Grid<Vec<(GridCellInfo, W)>> {
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
&mut self.widgets[index]
}
}
struct ListIter<'a, W: Widget> {
list: &'a [(GridCellInfo, W)],
}
impl<'a, W: Widget> Iterator for ListIter<'a, W> {
type Item = &'a (GridCellInfo, 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 [(GridCellInfo, W)],
}
impl<'a, W: Widget> Iterator for ListIterMut<'a, W> {
type Item = &'a mut (GridCellInfo, 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()
}
}