use crate::bindings::*;
use std::ffi::CString;
use bitflags::bitflags;
#[allow(warnings)]
mod bindings;
type FuttlCtx = bindings::futtl_ctx;
pub struct FuttlWin {
ctx: FuttlCtx,
children: Vec<Box<FuttlBox>>
}
pub struct FuttlBox {
ctx: FuttlCtx,
children: Vec<Box<FuttlBox>>,
owned_by_parent: bool,
}
#[derive(Clone, Copy)]
pub struct FuttlColor {
pub r: u8,
pub g: u8,
pub b: u8
}
pub struct FuttlColorSet {
pub fg: FuttlColor,
pub bg: FuttlColor
}
impl FuttlColor {
pub fn new(r: u8, g: u8, b: u8) -> Self {
Self { r, g, b }
}
}
impl FuttlColorSet {
pub fn new(fg: FuttlColor, bg: FuttlColor) -> Self {
Self { fg, bg }
}
}
bitflags! {
#[repr(transparent)]
pub struct Attr: i32 {
const NONE = FUTTL_ATTR_NONE as i32;
const BOLD = FUTTL_ATTR_BOLD as i32;
const DIM = FUTTL_ATTR_DIM as i32;
const ITALIC = FUTTL_ATTR_ITALIC as i32;
const UNDERLINE = FUTTL_ATTR_UNDERLINE as i32;
const BLINK = FUTTL_ATTR_BLINK as i32;
const INVERSE = FUTTL_ATTR_INVERSE as i32;
const HIDDEN = FUTTL_ATTR_HIDDEN as i32;
const STRIKETHROUGH = FUTTL_ATTR_STRIKETHROUGH as i32;
const IGNORE_BG = FUTTL_ATTR_IGNORE_BG as i32;
const IGNORE_FG = FUTTL_ATTR_IGNORE_FG as i32;
const IGNORE_COLOR = FUTTL_ATTR_IGNORE_COLOR as i32;
const ALL = FUTTL_ATTR_ALL as i32;
}
}
pub enum InputMode {
Blocking = FUTTL_INPUT_BLOCKING as isize,
NonBlocking = FUTTL_INPUT_NONBLOCKING as isize
}
#[allow(dead_code)]
pub fn set_input_blocking(input_blocking: InputMode) {
unsafe {futtl_set_input_blocking(input_blocking as i32)}
}
pub trait Futtl {
fn ctx(&mut self) -> &mut FuttlCtx;
fn children(&mut self) -> &mut Vec<Box<FuttlBox>>;
fn get_char(&mut self) -> char {
unsafe {bindings::futtl_get_char(self.ctx()) as u8 as char}
}
fn write_char(&mut self, c: char) {
unsafe {bindings::futtl_write_char(self.ctx(), c as i8)}
}
fn put_char(&mut self, c: char) {
unsafe {bindings::futtl_put_char(self.ctx(), c as i8)}
}
fn write_unicode(&mut self, c: u32) {
unsafe {bindings::futtl_write_unicode(self.ctx(), c)}
}
fn put_unicode(&mut self, c: u32) {
unsafe {bindings::futtl_put_unicode(self.ctx(), c)}
}
fn write_str(&mut self, s: &str) -> i32 {
let c_str = CString::new(s).unwrap();
unsafe {bindings::futtl_write_str(self.ctx(), c_str.as_ptr())}
}
fn put_str(&mut self, s: &str) -> i32 {
let c_str = CString::new(s).unwrap();
unsafe {bindings::futtl_put_str(self.ctx(), c_str.as_ptr())}
}
fn write_wrap_str(&mut self, s: &str) {
let c_str = CString::new(s).unwrap();
unsafe {bindings::futtl_write_wrap_str(self.ctx(), c_str.as_ptr())}
}
fn put_wrap_str(&mut self, s: &str) {
let c_str = CString::new(s).unwrap();
unsafe {bindings::futtl_put_wrap_str(self.ctx(), c_str.as_ptr())}
}
fn add_color(&mut self, cs: FuttlColorSet, idx: usize) {
if idx >= (self.ctx().color_count as usize) {
return;
}
let c_fg: bindings::futtl_color = bindings::futtl_color {
r: cs.fg.r,
g: cs.fg.g,
b: cs.fg.b,
};
let c_bg: bindings::futtl_color = bindings::futtl_color {
r: cs.bg.r,
g: cs.bg.g,
b: cs.bg.b,
};
let c_cs: bindings::futtl_color_set = bindings::futtl_color_set {
fg: c_fg,
bg: c_bg
};
unsafe {
*self.ctx().colors.add(idx) = c_cs;
}
}
fn set_color(&mut self, idx: usize) {
unsafe {futtl_set_color(self.ctx(), idx as i32)}
}
fn add_attribute(&mut self, attribute: Attr) {
unsafe {futtl_add_attribute(self.ctx(), attribute.bits())}
}
fn remove_attribute(&mut self, attribute: Attr) {
unsafe {futtl_remove_attribute(self.ctx(), attribute.bits())}
}
fn clear(&mut self) {
unsafe {futtl_clear(self.ctx())}
}
fn set_curs(&mut self, x: i32, y: i32) -> i32 {
unsafe {futtl_set_curs(self.ctx(), x, y)}
}
fn get_in(&mut self) -> i32 {
unsafe {futtl_get_in(self.ctx())}
}
fn add_child(&mut self, child: &mut FuttlBox) -> i32 {
unsafe {futtl_add_child(self.ctx(), child.ctx() as *mut FuttlCtx)}
}
fn remove_child(&mut self, index: usize) -> i32 {
if index >= self.children().len() {
return -1;
}
let result = unsafe {
futtl_remove_child(
self.ctx() as *mut FuttlCtx,
self.children()[index].ctx().child_index
)
};
if result == 0 {
let mut child = self.children().remove(index);
child.owned_by_parent = false;
}
result
}
fn create_box(&mut self, width: i32, height: i32) -> usize {
let mut child = Box::new(FuttlBox {
ctx: unsafe { std::mem::zeroed() },
children: Vec::new(),
owned_by_parent: true,
});
unsafe {
bindings::futtl_box_init(
&mut child.ctx,
width,
height,
self.ctx() as *mut FuttlCtx,
);
}
self.children().push(child);
self.children().len() - 1
}
}
impl Futtl for FuttlWin {
fn ctx(&mut self) -> &mut FuttlCtx {
&mut self.ctx
}
fn children(&mut self) -> &mut Vec<Box<FuttlBox>> {
&mut self.children
}
}
impl Futtl for FuttlBox {
fn ctx(&mut self) -> &mut FuttlCtx {
&mut self.ctx
}
fn children(&mut self) -> &mut Vec<Box<FuttlBox>> {
&mut self.children
}
}
impl FuttlWin {
pub fn get_ctx(&mut self) -> &mut FuttlCtx {
self.ctx()
}
pub fn init(&mut self, color_count: i32, default_attribute: i32) {
unsafe {
bindings::futtl_init(
self.ctx(),
color_count,
default_attribute,
);
}
}
pub fn new(color_count: i32, default_attribute: Attr) -> Self {
let mut this = Self {
ctx: unsafe {std::mem::zeroed::<FuttlCtx>()},
children: Vec::new(),
};
this.init(color_count, default_attribute.bits());
this
}
pub fn show(&mut self) {
unsafe {futtl_show(self.ctx())}
}
}
impl FuttlBox {
pub fn get_ctx(&mut self) -> &mut FuttlCtx {
self.ctx()
}
pub fn init(&mut self, width: i32, height: i32, parent: &mut dyn Futtl) {
unsafe {
bindings::futtl_box_init(
self.ctx(),
width,
height,
parent.ctx(),
);
}
}
pub fn show(&mut self, x: i32, y: i32) {
unsafe {futtl_box_show(self.ctx(),x ,y)}
}
}
impl Drop for FuttlWin {
fn drop(&mut self) {
unsafe {
bindings::futtl_deinit(self.ctx());
}
}
}
impl Drop for FuttlBox {
fn drop(&mut self) {
if !self.owned_by_parent {
unsafe {
bindings::futtl_box_deinit(self.ctx());
}
}
}
}
#[cfg(test)]
mod tests;