use crate::bindings::*;
use bitflags::bitflags;
#[allow(warnings)]
mod bindings;
type FuttlCtx = bindings::futtl_ctx;
#[derive(Clone, Copy)]
pub struct Vec2 {
pub x: i32,
pub y: i32
}
impl Vec2 {
pub fn new(x: i32, y: i32) -> Vec2 {
Self { x, y }
}
}
pub struct FuttlWin {
pub ctx: FuttlCtx,
pub children: Vec<Box<FuttlBox>>,
}
pub struct FuttlBox {
pub ctx: FuttlCtx,
pub children: Vec<Box<FuttlBox>>,
pub owned_by_parent: bool,
}
#[derive(Clone, Copy)]
#[repr(u8)]
pub enum AnsiColor {
Black = bindings::ANSI_BLACK as u8,
Red = bindings::ANSI_RED as u8,
Green = bindings::ANSI_GREEN as u8,
Yellow = bindings::ANSI_YELLOW as u8,
Blue = bindings::ANSI_BLUE as u8,
Magenta = bindings::ANSI_MAGENTA as u8,
Cyan = bindings::ANSI_CYAN as u8,
White = bindings::ANSI_WHITE as u8,
BrightBlack = bindings::ANSI_BRIGHT_BLACK as u8,
BrightRed = bindings::ANSI_BRIGHT_RED as u8,
BrightGreen = bindings::ANSI_BRIGHT_GREEN as u8,
BrightYellow = bindings::ANSI_BRIGHT_YELLOW as u8,
BrightBlue = bindings::ANSI_BRIGHT_BLUE as u8,
BrightMagenta = bindings::ANSI_BRIGHT_MAGENTA as u8,
BrightCyan = bindings::ANSI_BRIGHT_CYAN as u8,
BrightWhite = bindings::ANSI_BRIGHT_WHITE as u8,
DefaultFG = bindings::ANSI_DEFAULT_FG as u8,
DefaultBG = bindings::ANSI_DEFAULT_BG as u8,
}
#[derive(Clone, Copy)]
pub enum FuttlColor {
Default,
RGB(u8, u8, u8),
ANSI(AnsiColor),
ANSI256(u8),
}
pub enum FuttlKey {
Up = bindings::FUTTL_KEY_UP as isize,
Down = bindings::FUTTL_KEY_DOWN as isize,
Left = bindings::FUTTL_KEY_LEFT as isize,
Right = bindings::FUTTL_KEY_RIGHT as isize,
Home = bindings::FUTTL_KEY_HOME as isize,
End = bindings::FUTTL_KEY_END as isize,
Delete = bindings::FUTTL_KEY_DELETE as isize,
Insert = bindings::FUTTL_KEY_INSERT as isize,
PageUp = bindings::FUTTL_KEY_PAGE_UP as isize,
PageDown = bindings::FUTTL_KEY_PAGE_DOWN as isize,
}
impl FuttlColor {
fn into_c_color(self) -> bindings::futtl_color {
match self {
Self::Default => bindings::futtl_color {
color_type: bindings::FUTTL_COLOR_DEFAULT as i32,
__bindgen_anon_1: bindings::futtl_color__bindgen_ty_1 { ansi: 0 },
},
Self::RGB(r, g, b) => bindings::futtl_color {
color_type: bindings::FUTTL_COLOR_RGB as i32,
__bindgen_anon_1: bindings::futtl_color__bindgen_ty_1 {
rgb: bindings::futtl_color__bindgen_ty_1__bindgen_ty_1 { r, g, b },
},
},
Self::ANSI(ansi) => bindings::futtl_color {
color_type: bindings::FUTTL_COLOR_ANSI as i32,
__bindgen_anon_1: bindings::futtl_color__bindgen_ty_1 { ansi: ansi as u8 },
},
Self::ANSI256(ansi256) => bindings::futtl_color {
color_type: bindings::FUTTL_COLOR_ANSI256 as i32,
__bindgen_anon_1: bindings::futtl_color__bindgen_ty_1 { ansi256 },
},
}
}
}
pub struct FuttlColorSet {
pub fg: FuttlColor,
pub bg: FuttlColor
}
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
}
pub enum CursStyle {
Hidden = FUTTL_CURS_HIDDEN as isize,
Visible = FUTTL_CURS_VISIBLE as isize
}
#[allow(dead_code)]
pub fn set_input_blocking(input_blocking: InputMode) {
unsafe {futtl_set_input_blocking(input_blocking as i32)}
}
pub fn flush() {
unsafe {futtl_flush()}
}
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 size = s.chars().count();
let old_curs: bindings::vec2 = self.ctx().curs_pos;
for (i, c) in s.chars().enumerate() {
if self.ctx().curs_pos.y != old_curs.y {
self.ctx().curs_pos = old_curs;
return (size - i).try_into().unwrap();
}
self.put_unicode(c as u32);
}
self.ctx().curs_pos = old_curs;
0
}
fn put_str(&mut self, s: &str) -> i32 {
let size = s.chars().count();
let old_curs: bindings::vec2 = self.ctx().curs_pos;
for (i, c) in s.chars().enumerate() {
if self.ctx().curs_pos.y != old_curs.y {
return (size - i).try_into().unwrap();
}
self.put_unicode(c as u32);
}
0
}
fn write_wrap_str(&mut self, s: &str) -> i32 {
let old_curs: bindings::vec2 = self.ctx().curs_pos;
for c in s.chars() {
self.put_unicode(c as u32);
}
self.ctx().curs_pos = old_curs;
0
}
fn put_wrap_str(&mut self, s: &str) -> i32 {
for c in s.chars() {
self.put_unicode(c as u32);
}
0
}
fn add_color(&mut self, cs: FuttlColorSet, idx: usize) {
if idx >= (self.ctx().color_count as usize) {
return;
}
let c_cs: bindings::futtl_color_set = bindings::futtl_color_set {
fg: cs.fg.into_c_color(),
bg: cs.bg.into_c_color(),
};
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 set_curs_style(&mut self, style: CursStyle) {
self.ctx().curs_visibility = style as i32;
}
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 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());
}
}
}
}
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)}
}
pub fn set_border(
&mut self,
top: u32,
right: u32,
bottom: u32,
left: u32,
top_right: u32,
bottom_right: u32,
bottom_left: u32,
top_left: u32,
color: i32,
) {
unsafe {futtl_box_set_border(self.ctx(), top, right, bottom, left, top_right, bottom_right, bottom_left, top_left, color)}
}
}
#[cfg(test)]
mod tests;