use std::{
ffi::CString,
sync::{Arc, LazyLock, Mutex},
};
use crate::{
draw_2d::DCtx,
types::{Align, GuiClose, GuiMouse, GuiOrient, GuiScroll, GuiState, KeyCode},
};
pub struct EvButton {
pub index: u32,
pub state: GuiState,
pub text: String,
}
impl EvButton {
pub(crate) fn from_ptr(ptr: *mut nappgui_sys::EvButton) -> EvButton {
if ptr.is_null() {
panic!("EvButton is null");
}
let evbutton = unsafe { &*ptr };
EvButton {
index: evbutton.index as _,
state: GuiState::try_from(evbutton.state).unwrap(),
text: unsafe { std::ffi::CStr::from_ptr(evbutton.text) }
.to_string_lossy()
.into_owned(),
}
}
}
pub struct EvSlider {
pub pos: f32,
pub incr: f32,
pub step: u32,
}
impl EvSlider {
pub(crate) fn from_ptr(ptr: *mut nappgui_sys::EvSlider) -> EvSlider {
if ptr.is_null() {
panic!("EvSlider is null");
}
let evslider = unsafe { &*ptr };
EvSlider {
pos: evslider.pos,
incr: evslider.incr,
step: evslider.step as _,
}
}
}
pub struct EvText {
pub text: String,
pub cpos: u32,
pub len: i32,
}
impl EvText {
pub(crate) fn from_ptr(ptr: *mut nappgui_sys::EvText) -> EvText {
if ptr.is_null() {
panic!("EvText is null");
}
let evtext = unsafe { &*ptr };
EvText {
text: unsafe { std::ffi::CStr::from_ptr(evtext.text) }
.to_string_lossy()
.into_owned(),
cpos: evtext.cpos as _,
len: evtext.len,
}
}
}
pub struct EvDraw {
pub ctx: DCtx,
pub x: f32,
pub y: f32,
pub width: f32,
pub height: f32,
}
impl EvDraw {
pub(crate) fn from_ptr(ptr: *mut nappgui_sys::EvDraw) -> EvDraw {
if ptr.is_null() {
panic!("EvDraw is null");
}
let evdraw = unsafe { &*ptr };
EvDraw {
ctx: DCtx::new(evdraw.ctx),
x: evdraw.x,
y: evdraw.y,
width: evdraw.width,
height: evdraw.height,
}
}
}
pub struct EvMouse {
pub x: f32,
pub y: f32,
pub lx: f32,
pub ly: f32,
pub button: GuiMouse,
pub count: u32,
pub modifiers: u32,
pub tag: u32,
}
impl EvMouse {
pub(crate) fn from_ptr(ptr: *mut nappgui_sys::EvMouse) -> EvMouse {
if ptr.is_null() {
panic!("EvMouse is null");
}
let evmouse = unsafe { &*ptr };
EvMouse {
x: evmouse.x,
y: evmouse.y,
lx: evmouse.lx,
ly: evmouse.ly,
button: GuiMouse::try_from(evmouse.button).unwrap(),
count: evmouse.count,
modifiers: evmouse.modifiers,
tag: evmouse.tag,
}
}
}
pub struct EvWheel {
pub x: f32,
pub y: f32,
pub dx: f32,
pub dy: f32,
pub dz: f32,
}
impl EvWheel {
pub(crate) fn from_ptr(ptr: *mut nappgui_sys::EvWheel) -> EvWheel {
if ptr.is_null() {
panic!("EvWheel is null");
}
let evwheel = unsafe { &*ptr };
EvWheel {
x: evwheel.x,
y: evwheel.y,
dx: evwheel.dx,
dy: evwheel.dy,
dz: evwheel.dz,
}
}
}
pub struct EvKey {
pub key: KeyCode,
pub modifiers: u32,
}
impl EvKey {
pub(crate) fn from_ptr(ptr: *mut nappgui_sys::EvKey) -> EvKey {
if ptr.is_null() {
panic!("EvKey is null");
}
let evkey = unsafe { &*ptr };
EvKey {
key: KeyCode::try_from(evkey.key).unwrap(),
modifiers: evkey.modifiers,
}
}
}
pub struct EvPos {
pub x: f32,
pub y: f32,
}
impl EvPos {
pub(crate) fn from_ptr(ptr: *mut nappgui_sys::EvPos) -> EvPos {
if ptr.is_null() {
panic!("EvPos is null");
}
let evpos = unsafe { &*ptr };
EvPos {
x: evpos.x,
y: evpos.y,
}
}
}
pub struct EvSize {
pub width: f32,
pub height: f32,
}
impl EvSize {
pub(crate) fn from_ptr(ptr: *mut nappgui_sys::EvSize) -> EvSize {
if ptr.is_null() {
panic!("EvSize is null");
}
let evresize = unsafe { &*ptr };
EvSize {
width: evresize.width,
height: evresize.height,
}
}
}
pub struct EvWinClose {
pub origin: GuiClose,
}
impl EvWinClose {
pub(crate) fn from_ptr(ptr: *mut nappgui_sys::EvWinClose) -> EvWinClose {
if ptr.is_null() {
panic!("EvWinClose is null");
}
let evclose = unsafe { &*ptr };
EvWinClose {
origin: GuiClose::try_from(evclose.origin).unwrap(),
}
}
}
pub struct EvMenu {
pub index: u32,
pub state: GuiState,
pub text: String,
}
impl EvMenu {
pub(crate) fn from_ptr(ptr: *mut nappgui_sys::EvMenu) -> EvMenu {
if ptr.is_null() {
panic!("EvMenu is null");
}
let evmenu = unsafe { &*ptr };
EvMenu {
index: evmenu.index,
state: GuiState::try_from(evmenu.state).unwrap(),
text: unsafe {
std::ffi::CStr::from_ptr(evmenu.text)
.to_string_lossy()
.into_owned()
},
}
}
}
pub struct EvScroll {
pub orient: GuiOrient,
pub scroll: GuiScroll,
pub cpos: f32,
}
impl EvScroll {
pub(crate) fn from_ptr(ptr: *mut nappgui_sys::EvScroll) -> EvScroll {
if ptr.is_null() {
panic!("EvScroll is null");
}
let evscroll = unsafe { &*ptr };
EvScroll {
orient: GuiOrient::try_from(evscroll.orient).unwrap(),
scroll: GuiScroll::try_from(evscroll.scroll).unwrap(),
cpos: evscroll.cpos,
}
}
}
pub struct EvTbPos {
pub col: u32,
pub row: u32,
}
impl EvTbPos {
pub(crate) fn from_ptr(ptr: *mut nappgui_sys::EvTbPos) -> EvTbPos {
if ptr.is_null() {
panic!("EvTbPos is null");
}
let evtbpos = unsafe { &*ptr };
EvTbPos {
col: evtbpos.col as _,
row: evtbpos.row as _,
}
}
}
pub struct EvTbRow {
pub sel: bool,
pub row: u32,
}
impl EvTbRow {
pub(crate) fn from_ptr(ptr: *mut nappgui_sys::EvTbRow) -> EvTbRow {
if ptr.is_null() {
panic!("EvTbRow is null");
}
let evtbrow = unsafe { &*ptr };
EvTbRow {
sel: evtbrow.sel != 0,
row: evtbrow.row as _,
}
}
}
pub struct EvTbRect {
pub stcol: u32,
pub edcol: u32,
pub strow: u32,
pub edrow: u32,
}
impl EvTbRect {
pub(crate) fn from_ptr(ptr: *mut nappgui_sys::EvTbRect) -> EvTbRect {
if ptr.is_null() {
panic!("EvTbRect is null");
}
let evtbrect = unsafe { &*ptr };
EvTbRect {
stcol: evtbrect.stcol as _,
edcol: evtbrect.edcol as _,
strow: evtbrect.strow as _,
edrow: evtbrect.edrow as _,
}
}
}
fn array_usize(array: *mut nappgui_sys::ArrStuint32_t) -> Option<Vec<usize>> {
if array.is_null() {
return None;
}
let array = unsafe { *array };
if array.content.is_null() {
return None;
}
let content = unsafe { *array.content };
let elem = &content.elem;
Some(elem.iter().map(|&x| x as _).collect())
}
pub struct EvTbSel {
pub sel: Vec<usize>,
}
impl EvTbSel {
pub(crate) fn from_ptr(ptr: *mut nappgui_sys::EvTbSel) -> EvTbSel {
if ptr.is_null() {
panic!("EvTbSel is null");
}
let evtbsel = unsafe { &*ptr };
EvTbSel {
sel: array_usize(evtbsel.sel).unwrap(),
}
}
}
pub struct EvTbCell {
pub text: String,
pub align: Align,
}
impl EvTbCell {
pub(crate) fn from_ptr(ptr: *mut nappgui_sys::EvTbCell) -> EvTbCell {
if ptr.is_null() {
panic!("EvTbCell is null");
}
let evtbcell = unsafe { &*ptr };
EvTbCell {
text: unsafe {
std::ffi::CStr::from_ptr(evtbcell.text)
.to_string_lossy()
.into_owned()
},
align: Align::try_from(evtbcell.align).unwrap(),
}
}
}
macro_rules! event_params {
($type:ty) => {
impl crate::core::event::NappGUIEventParams for $type {
fn type_() -> &'static str {
stringify!($type)
}
fn from_ptr(ptr: *mut std::ffi::c_void) -> Option<Self> {
if ptr.is_null() {
return None;
}
Some(Self::from_ptr(ptr as _))
}
}
};
}
event_params!(EvButton);
event_params!(EvSlider);
event_params!(EvText);
event_params!(EvDraw);
event_params!(EvMouse);
event_params!(EvWheel);
event_params!(EvKey);
event_params!(EvPos);
event_params!(EvSize);
event_params!(EvWinClose);
event_params!(EvMenu);
event_params!(EvScroll);
event_params!(EvTbPos);
event_params!(EvTbRow);
event_params!(EvTbRect);
event_params!(EvTbSel);
event_params!(EvTbCell);
macro_rules! event_params_core {
($type:ty, $type_name:literal) => {
impl crate::core::event::NappGUIEventParams for $type {
fn type_() -> &'static str {
$type_name
}
fn from_ptr(ptr: *mut std::ffi::c_void) -> Option<Self> {
if ptr.is_null() {
return None;
}
Some(unsafe { *(ptr as *mut $type) })
}
}
};
}
event_params_core!(bool, "bool_t");
fn take_str_4096(text: &str) -> [i8; 4096] {
let text = CString::new(text).unwrap();
let mut cross_text = [0i8; 4096];
let length = if text.as_bytes().len() < 4096 {
text.as_bytes().len()
} else {
4096
};
cross_text[..length].copy_from_slice(
text.as_bytes()
.iter()
.map(|&x| x as i8)
.collect::<Vec<i8>>()
.as_slice(),
);
cross_text
}
pub struct EvTextFilter {
pub apply: bool,
pub text: String,
pub cpos: u32,
}
impl crate::core::event::NappGUIEventResult for EvTextFilter {
type CrossType = nappgui_sys::EvTextFilter;
fn type_() -> &'static str {
"EvTextFilter"
}
fn to_cross_type(&self) -> Self::CrossType {
nappgui_sys::EvTextFilter {
apply: self.apply as _,
text: take_str_4096(&self.text),
cpos: self.cpos as _,
}
}
}
static TEMP_TEXT: LazyLock<Arc<Mutex<Option<CString>>>> =
LazyLock::new(|| Arc::new(Mutex::new(None)));
impl crate::core::event::NappGUIEventResult for EvTbCell {
type CrossType = nappgui_sys::EvTbCell;
fn to_cross_type(&self) -> Self::CrossType {
let mut text = TEMP_TEXT.lock().unwrap();
text.replace(CString::new(&*self.text).unwrap());
let text = text.as_ref().unwrap();
nappgui_sys::EvTbCell {
text: text.as_ptr(),
align: self.align as _,
}
}
}
macro_rules! event_results {
($type:ty, $cross_type:literal) => {
impl crate::core::event::NappGUIEventResult for $type {
type CrossType = $type;
fn type_() -> &'static str {
$cross_type
}
fn to_cross_type(&self) -> Self::CrossType {
*self
}
}
};
}
event_results!(bool, "bool_t");
event_results!(f32, "real32_t");
event_results!(u32, "u32_t");
pub enum EvTbDataParams {
TableNCols,
TableCell(EvTbPos),
}
pub enum EvTbDataResult {
TableNCols(u32),
TableCell(EvTbCell),
}
impl From<u32> for EvTbDataResult {
fn from(value: u32) -> Self {
Self::TableNCols(value)
}
}
impl From<EvTbCell> for EvTbDataResult {
fn from(value: EvTbCell) -> Self {
Self::TableCell(value)
}
}