#![allow(clippy::needless_doctest_main)]
use fltk::{prelude::*, *};
use std::cell::RefCell;
use std::collections::HashMap;
use std::ops::Range;
use std::rc::Rc;
pub struct GridRange {
start: usize,
end: usize,
}
impl GridRange {
pub fn len(&self) -> usize {
self.end - self.start
}
}
impl From<Range<usize>> for GridRange {
fn from(val: Range<usize>) -> Self {
Self {
start: val.start,
end: val.end,
}
}
}
impl From<usize> for GridRange {
fn from(val: usize) -> Self {
(val..val + 1).into()
}
}
#[derive(Debug, Clone)]
pub struct Grid {
table: table::Table,
widgets: Rc<RefCell<HashMap<(i32, i32, i32, i32), widget::Widget>>>,
}
impl Default for Grid {
fn default() -> Self {
Grid::new(0, 0, 0, 0, None)
}
}
impl Grid {
pub fn new<S: Into<Option<&'static str>>>(x: i32, y: i32, w: i32, h: i32, label: S) -> Self {
let mut table = table::Table::new(x, y, w, h, label);
table.set_frame(enums::FrameType::NoBox);
table.set_scrollbar_size(-1);
table.end();
Self {
table,
widgets: Rc::new(RefCell::new(HashMap::default())),
}
}
pub fn default_fill() -> Self {
let g = Grid::default();
Self {
table: g.table.size_of_parent().center_of_parent(),
widgets: Rc::new(RefCell::new(HashMap::default())),
}
}
pub fn set_layout(&mut self, rows: i32, cols: i32) {
self.table.set_rows(rows);
self.table.set_cols(cols);
let parent = self.table.parent().unwrap();
self.table.set_row_height_all(parent.h() / rows);
self.table.set_col_width_all(parent.w() / cols);
}
pub fn insert_ext<W: 'static + Clone + WidgetExt>(
&mut self,
widget: &mut W,
row: i32,
col: i32,
row_span: i32,
col_span: i32,
) {
if let Some((x, y, w, h)) = self.table.find_cell(table::TableContext::Cell, row, col) {
widget.resize(x, y, w * row_span, h * col_span);
self.table.add(widget);
self.widgets
.borrow_mut()
.insert((row, col, row_span, col_span), unsafe {
widget.into_widget()
});
}
}
pub fn insert<W: 'static + Clone + WidgetExt>(
&mut self,
widget: &mut W,
row: impl Into<GridRange>,
col: impl Into<GridRange>,
) {
let row = row.into();
let col = col.into();
self.insert_ext(widget, row.start as _, col.start as _, row.len() as _, col.len() as _);
}
pub fn remove<W: WidgetExt>(&mut self, widget: &W) {
self.widgets
.borrow_mut()
.retain(|_, v| unsafe { v.as_widget_ptr() != widget.as_widget_ptr() });
self.table.remove(widget);
}
pub fn resize(&mut self, x: i32, y: i32, w: i32, h: i32) {
self.table.resize(x, y, w, h);
let rows = self.table.rows();
let cols = self.table.cols();
let parent = self.table.parent().unwrap();
self.table.set_row_height_all(parent.h() / rows);
self.table.set_col_width_all(parent.w() / cols);
for wi in &mut self.widgets.borrow_mut().iter_mut() {
if let Some((x, y, w, h)) =
self.table
.find_cell(table::TableContext::Cell, wi.0 .0, wi.0 .1)
{
wi.1.resize(x, y, w * wi.0 .2, h * wi.0 .3);
}
}
}
pub fn debug(&mut self, flag: bool) {
if flag {
self.table.draw_cell(move |_, ctx, row, col, x, y, w, h| {
if ctx == table::TableContext::Cell {
draw::set_font(enums::Font::Helvetica, 14);
draw::set_draw_color(enums::Color::Red);
draw::draw_rect(x, y, w, h);
draw::draw_text2(
&format!("{},{}", row, col),
x,
y,
w,
h,
enums::Align::Center,
);
}
});
}
}
}