use std::cell::Cell;
use std::ops::Drop;
use std::os::unix::io::RawFd;
use std::ptr;
use newt_sys::*;
use crate::callbacks::HelpCallback;
use crate::component::Component;
use crate::error::{Error,Result};
use crate::widgets::VerticalScrollbar;
use crate::private::{Child,Nullify};
use crate::private::funcs::*;
mod constants;
use self::constants::*;
mod exit_reason;
pub use self::exit_reason::ExitReason;
#[derive(Component)]
pub struct Form<'a>
{
co: Cell<newtComponent>,
added_to_parent: Cell<bool>,
components: Vec<&'a dyn Component>
}
#[derive(Component)]
struct BaseComponent {
co: Cell<newtComponent>,
added_to_parent: Cell<bool>
}
#[repr(C)]
pub enum FDFlags {
Read = NEWT_FD_READ as isize,
Write = NEWT_FD_WRITE as isize,
Except = NEWT_FD_EXCEPT as isize
}
impl<'a> Form<'a>
{
pub fn new(scrollbar: Option<&VerticalScrollbar>, flags: i32) -> Form<'a> {
let scrollbar = if let Some(scrollbar) = scrollbar {
scrollbar.co()
} else {
ptr::null_mut()
};
let co = unsafe { newtForm(scrollbar, ptr::null_mut(), flags) };
if co.is_null() {
malloc_failure();
}
Form {
co: Cell::new(co),
added_to_parent: Cell::new(false),
components: Vec::new()
}
}
pub fn new_with_help_callback<F, T>(scrollbar: Option<&VerticalScrollbar>,
flags: i32,
function: F,
data: Option<T>)
-> (Form<'a>, Box<HelpCallback<'a, F, T>>)
where
F: Fn(&Form, Option<&T>)
{
HelpCallback::new(scrollbar, flags, data, function)
}
pub(crate) fn new_co(co: newtComponent) -> Form<'a> {
Form {
co: Cell::new(co),
components: Vec::new(),
added_to_parent: Cell::new(false)
}
}
#[cfg(feature = "asm")]
pub(crate) fn add_refs(&mut self, components: Vec<&'a dyn Component>) {
let len = components.len();
self.components.reserve(len);
for co in components.iter() {
self.components.push(*co);
}
}
pub fn add_component(&mut self, component: &'a dyn Component)
-> Result<()>
{
component.add_to_parent()?;
self.components.push(component);
unsafe { newtFormAddComponent(self.co(), component.co()); }
Ok(())
}
pub fn add_components<'t>(&mut self, components: &'t [&'a dyn Component])
-> Result<()>
{
let len = components.len();
self.components.reserve(len);
for component in components.iter() {
self.add_component(*component)?;
}
Ok(())
}
pub fn take_component<T>(&mut self, component: T)
-> Result<()>
where
T: Component
{
component.add_to_parent()?;
unsafe { newtFormAddComponent(self.co(), component.co()); }
Ok(())
}
pub fn set_height(&self, height: i32) {
unsafe { newtFormSetHeight(self.co(), height); }
}
pub fn set_width(&self, width: i32) {
unsafe { newtFormSetWidth(self.co(), width); }
}
pub fn set_size(&self) {
unsafe { newtFormSetSize(self.co()); }
}
pub fn add_hot_key(&self, key: i32) {
unsafe { newtFormAddHotKey(self.co(), key); }
}
pub fn set_timer(&self, millisecs: i32) {
unsafe { newtFormSetTimer(self.co(), millisecs); }
}
pub fn watch_fd(&self, fd: RawFd, flags: FDFlags) {
unsafe { newtFormWatchFd(self.co(), fd, flags as i32); }
}
pub fn get_current(&self) -> Box<dyn Component> {
Box::new(BaseComponent {
co: unsafe { Cell::new(newtFormGetCurrent(self.co())) },
added_to_parent: Cell::new(true)
})
}
pub fn set_current(&self, subcomponent: &dyn Component) {
unsafe { newtFormSetCurrent(self.co(), subcomponent.co()); }
}
pub fn set_background(&self, color: i32) {
unsafe { newtFormSetBackground(self.co(), color); }
}
pub fn get_scroll_position(&self) -> i32 {
unsafe { newtFormGetScrollPosition(self.co()) }
}
pub fn set_scroll_position(&self, position: i32) {
unsafe { newtFormSetScrollPosition(self.co(), position); }
}
pub fn run(&self) -> Result<ExitReason> {
use self::ExitReason::{HotKey,Component,FDReady,Timer};
let mut es = newtExitStruct {
reason: NEWT_EXIT_HOTKEY,
u: newtExitStructUnion { watch: 0 }
};
unsafe {
newtFormRun(self.co(), &mut es);
match es.reason {
NEWT_EXIT_HOTKEY => Ok(HotKey(es.u.key)),
NEWT_EXIT_COMPONENT => Ok(
Component(Box::new(BaseComponent {
co: Cell::new(es.u.co),
added_to_parent: Cell::new(true)
}))
),
NEWT_EXIT_FDREADY => Ok(FDReady(es.u.watch)),
NEWT_EXIT_TIMER => Ok(Timer),
NEWT_EXIT_ERROR => Err(Error::FormRun),
_ => panic!("Unexpected newt exit reason.")
}
}
}
pub fn draw(&self) {
unsafe { newtDrawForm(self.co()); }
}
}
impl<'a> Drop for Form<'a>
{
fn drop(&mut self) {
if !self.added_to_parent() {
unsafe { newtFormDestroy(self.co()); }
self.nullify();
}
for component in self.components.iter() {
component.nullify();
}
}
}