use fltk::{enums, group::Group, prelude::{GroupExt, WidgetBase, WidgetExt, WidgetType}, widget::Widget, widget_extends};
use std::{
mem,
};
#[repr(i32)]
#[derive(fltk_derive::WidgetType, Debug, Copy, Clone, PartialEq)]
pub enum FlexType {
Row = 0,
Column,
}
#[derive(Debug, Clone)]
pub struct Flex {
grp: Group,
dir: FlexType,
margin: i32,
pad: i32,
setsized: Vec<Widget>,
debug: bool,
}
widget_extends!(Flex, Group, grp);
impl Default for Flex {
fn default() -> Flex {
let dir = FlexType::Row;
let margin = 0;
let pad = 5;
let grp = Group::default().size_of_parent();
Flex {
grp,
dir,
margin,
pad,
setsized: Vec::new(),
debug: false,
}
}
}
impl Flex {
pub fn new<T: Into<Option<&'static str>>>(x: i32, y: i32, w: i32, h: i32, label: T) -> Flex {
let dir = FlexType::Row;
let margin = 0;
let pad = 5;
let grp = Group::new(x, y, w, h, label);
Self {
grp,
dir,
margin,
pad,
setsized: Vec::new(),
debug: false,
}
}
pub fn set_type<T: WidgetType>(&mut self, typ: T) {
self.dir = FlexType::from_i32(typ.to_i32());
}
pub fn get_type<T: WidgetType>(&self) -> T {
T::from_i32(self.dir.to_i32())
}
pub fn column(mut self) -> Self {
self.set_type(FlexType::Column);
self
}
pub fn row(mut self) -> Self {
self.set_type(FlexType::Row);
self
}
pub fn end(&mut self) {
self.grp.end();
self.resize(self.grp.x(), self.grp.y(), self.grp.w(), self.grp.h());
}
pub fn recalc(&mut self) {
self.end();
}
pub fn set_size<W: WidgetExt>(&mut self, wid: &mut W, size: i32) {
wid.resize(0, 0, size, size);
for i in 0..self.setsized.len() {
if unsafe { self.setsized[i].as_widget_ptr() == wid.as_widget_ptr() } {
return;
}
}
self.setsized
.push(unsafe { Widget::from_widget_ptr(wid.as_widget_ptr()) });
}
pub fn resize(&mut self, x: i32, y: i32, w: i32, h: i32) {
self.widget_resize(x, y, w, h);
if self.dir == FlexType::Column {
self.resize_col(x, y, w, h);
} else {
self.resize_row(x, y, w, h);
}
}
pub fn debug(&mut self, flag: bool) {
self.debug = flag;
if flag {
self.grp.set_frame(enums::FrameType::BorderBox);
self.grp.set_color(enums::Color::Red);
} else {
self.grp.set_frame(enums::FrameType::NoBox);
self.grp.set_color(enums::Color::BackGround);
}
}
pub fn set_margin(&mut self, margin: i32) {
self.margin = margin;
}
pub fn set_pad(&mut self, pad: i32) {
self.pad = pad;
}
pub fn margin(&self) -> i32 {
self.margin
}
pub fn pad(&self) -> i32 {
self.pad
}
fn is_set_size<W: WidgetExt>(&self, wid: &W) -> bool {
for i in 0..self.setsized.len() {
if unsafe { wid.as_widget_ptr() == self.setsized[i].as_widget_ptr() } {
return true;
}
}
return false;
}
fn resize_row(&mut self, x: i32, y: i32, w: i32, h: i32) {
let cc = self.grp.children();
let mut pad_w = w - self.margin * 2;
for _i in 0..cc {
pad_w -= 5;
}
let mut cx = x + self.margin;
let mut nrs = 0;
for i in 0..cc {
let c = self.grp.child(i).unwrap();
if self.is_set_size(&c) {
nrs += c.w();
}
}
for i in 0..cc {
let mut c = self.grp.child(i).unwrap();
if self.is_set_size(&c) {
c.resize(cx, y + self.margin, c.w(), h - self.margin * 2);
} else {
c.resize(
cx,
y + self.margin,
(pad_w - nrs) / (cc - self.setsized.len() as i32),
h - self.margin * 2,
);
}
cx += c.w() + self.pad;
}
}
fn resize_col(&mut self, x: i32, y: i32, w: i32, h: i32) {
let cc = self.grp.children();
if cc - self.setsized.len() as i32 == 0 {
return;
}
let mut pad_h = h - self.margin * 2;
for _i in 0..cc {
pad_h -= self.pad;
}
let mut cy = y + self.margin;
let mut nrs = 0;
for i in 0..cc {
let c = self.grp.child(i).unwrap();
if self.is_set_size(&c) {
nrs += c.h();
}
}
for i in 0..cc {
let mut c = self.grp.child(i).unwrap();
if self.is_set_size(&c) {
c.resize(x + self.margin, cy, w - self.margin * 2, c.h());
} else {
c.resize(
x + self.margin,
cy,
w - self.margin * 2,
(pad_h - nrs) / (cc - self.setsized.len() as i32),
);
}
cy += c.h() + self.pad;
}
}
}