use crate::app::widget::first_window;
use crate::enums::{CallbackReason, Event, Key, Shortcut};
use crate::prelude::*;
use crate::utils::FlString;
use fltk_sys::fl;
use std::{
cmp,
ffi::{CStr, CString},
mem,
os::raw,
panic,
};
pub type WindowPtr = *mut fltk_sys::window::Fl_Window;
pub fn event() -> Event {
unsafe { mem::transmute(fl::Fl_event()) }
}
pub fn event_key() -> Key {
unsafe { mem::transmute(fl::Fl_event_key()) }
}
pub fn event_original_key() -> Key {
unsafe { mem::transmute(fl::Fl_event_original_key()) }
}
pub fn event_key_down(key: Key) -> bool {
unsafe { fl::Fl_event_key_down(mem::transmute(key)) != 0 }
}
pub fn event_text() -> String {
unsafe {
let text = fl::Fl_event_text();
if text.is_null() {
String::from("")
} else {
CStr::from_ptr(text as *mut raw::c_char)
.to_string_lossy()
.to_string()
}
}
}
pub fn event_button() -> i32 {
unsafe { fl::Fl_event_button() }
}
#[repr(i32)]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub enum MouseButton {
Left = 1,
Middle = 2,
Right = 3,
Back = 4,
Forward = 5,
}
pub fn event_mouse_button() -> MouseButton {
unsafe { mem::transmute(fl::Fl_event_button()) }
}
pub fn event_clicks() -> bool {
unsafe { fl::Fl_event_clicks() != 0 }
}
pub fn event_clicks_num() -> i32 {
unsafe { fl::Fl_event_clicks() }
}
pub fn event_x() -> i32 {
unsafe { fl::Fl_event_x() }
}
pub fn event_y() -> i32 {
unsafe { fl::Fl_event_y() }
}
pub fn event_x_root() -> i32 {
unsafe { fl::Fl_event_x_root() }
}
pub fn event_y_root() -> i32 {
unsafe { fl::Fl_event_y_root() }
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum MouseWheel {
None,
Right,
Left,
Up,
Down,
}
pub fn event_dx() -> MouseWheel {
match 0.cmp(unsafe { &fl::Fl_event_dx() }) {
cmp::Ordering::Greater => MouseWheel::Left,
cmp::Ordering::Equal => MouseWheel::None,
cmp::Ordering::Less => MouseWheel::Right,
}
}
pub fn event_dy() -> MouseWheel {
match 0.cmp(unsafe { &fl::Fl_event_dy() }) {
cmp::Ordering::Greater => MouseWheel::Up,
cmp::Ordering::Equal => MouseWheel::None,
cmp::Ordering::Less => MouseWheel::Down,
}
}
pub fn event_dx_value() -> i32 {
unsafe { fl::Fl_event_dx() }
}
pub fn event_dy_value() -> i32 {
unsafe { fl::Fl_event_dy() }
}
pub fn event_coords() -> (i32, i32) {
unsafe { (fl::Fl_event_x(), fl::Fl_event_y()) }
}
pub fn event_is_click() -> bool {
unsafe { fl::Fl_event_is_click() != 0 }
}
pub fn event_length() -> i32 {
unsafe { fl::Fl_event_length() }
}
pub fn event_state() -> Shortcut {
unsafe { mem::transmute(fl::Fl_event_state()) }
}
pub fn event_inside_widget<Wid: WidgetExt>(wid: &Wid) -> bool {
let x = wid.x();
let y = wid.y();
let w = wid.width();
let h = wid.height();
unsafe { fl::Fl_event_inside(x, y, w, h) != 0 }
}
pub fn event_inside(x: i32, y: i32, w: i32, h: i32) -> bool {
unsafe { fl::Fl_event_inside(x, y, w, h) != 0 }
}
pub fn belowmouse<Wid: WidgetBase>() -> Option<Wid> {
unsafe {
let x = fl::Fl_belowmouse();
if x.is_null() {
None
} else {
Wid::from_dyn_widget_ptr(x as _)
}
}
}
pub fn set_belowmouse<Wid: WidgetExt>(w: &Wid) {
unsafe {
fl::Fl_set_belowmouse(w.as_widget_ptr() as _);
}
}
pub fn is_event_shift() -> bool {
unsafe { fl::Fl_event_shift() != 0 }
}
pub fn is_event_ctrl() -> bool {
unsafe { fl::Fl_event_ctrl() != 0 }
}
pub fn is_event_command() -> bool {
unsafe { fl::Fl_event_command() != 0 }
}
pub fn is_event_alt() -> bool {
unsafe { fl::Fl_event_alt() != 0 }
}
pub fn dnd() {
unsafe {
fl::Fl_dnd();
}
}
pub fn event_clipboard_image() -> Option<crate::image::RgbImage> {
unsafe {
let image = fl::Fl_event_clipboard();
if image.is_null() {
None
} else {
Some(crate::image::RgbImage::from_image_ptr(image as _))
}
}
}
#[derive(Debug, Clone)]
pub enum ClipboardEvent {
Text(String),
Image(Option<crate::image::RgbImage>),
}
pub fn event_clipboard() -> Option<ClipboardEvent> {
unsafe {
let txt = fl::Fl_event_clipboard_type();
let txt = CStr::from_ptr(txt as _).to_string_lossy().to_string();
if txt == "text/plain" {
Some(ClipboardEvent::Text(event_text()))
} else if txt == "image" {
Some(ClipboardEvent::Image(event_clipboard_image()))
} else {
None
}
}
}
#[allow(clippy::missing_safety_doc)]
pub unsafe fn handle_raw(event: Event, w: WindowPtr) -> bool {
fl::Fl_handle_(event.bits(), w as _) != 0
}
#[allow(clippy::missing_safety_doc)]
pub unsafe fn event_dispatch(f: fn(Event, WindowPtr) -> bool) {
fl::Fl_event_dispatch(mem::transmute(f));
}
pub fn get_mouse() -> (i32, i32) {
unsafe {
let mut x: i32 = 0;
let mut y: i32 = 0;
fl::Fl_get_mouse(&mut x, &mut y);
(x, y)
}
}
pub fn compose() -> Option<i32> {
unsafe {
let mut del = 0;
if fl::Fl_compose(&mut del) != 0 {
Some(del)
} else {
None
}
}
}
pub fn compose_reset() {
unsafe {
fl::Fl_compose_reset();
}
}
pub fn compose_state() -> i32 {
unsafe { fl::Fl_compose_state() }
}
pub fn copy(stuff: &str) {
unsafe {
fl::Fl_open_display();
let len = stuff.len();
let stuff = CString::safe_new(stuff);
fl::Fl_copy(stuff.as_ptr() as _, len as _, 1);
}
}
pub fn copy2(stuff: &str) {
unsafe {
fl::Fl_open_display();
let len = stuff.len();
let stuff = CString::safe_new(stuff);
fl::Fl_copy(stuff.as_ptr() as _, len as _, 0);
}
}
#[derive(Debug, Clone, Copy)]
pub enum ClipboardContent {
Text,
Image,
}
pub fn clipboard_contains(content: ClipboardContent) -> bool {
use ClipboardContent::*;
let txt = match content {
Text => "text/plain",
Image => "image",
};
let txt = CString::new(txt).unwrap();
unsafe { fl::Fl_clipboard_contains(txt.as_ptr() as _) != 0 }
}
pub fn paste<T>(widget: &T)
where
T: WidgetExt,
{
if clipboard_contains(ClipboardContent::Text) {
paste_text(widget)
} else if clipboard_contains(ClipboardContent::Image) {
paste_image(widget)
} else {
}
}
pub fn paste_text<T>(widget: &T)
where
T: WidgetExt,
{
unsafe {
fl::Fl_paste_text(widget.as_widget_ptr() as *mut fltk_sys::fl::Fl_Widget, 1);
}
}
pub fn paste_text2<T>(widget: &T)
where
T: WidgetExt,
{
unsafe {
fl::Fl_paste_text(widget.as_widget_ptr() as *mut fltk_sys::fl::Fl_Widget, 0);
}
}
pub fn paste_image<T>(widget: &T)
where
T: WidgetExt,
{
unsafe {
fl::Fl_paste_image(widget.as_widget_ptr() as *mut fltk_sys::fl::Fl_Widget, 1);
}
}
pub fn paste_image2<T>(widget: &T)
where
T: WidgetExt,
{
unsafe {
fl::Fl_paste_image(widget.as_widget_ptr() as *mut fltk_sys::fl::Fl_Widget, 0);
}
}
pub fn add_handler(cb: fn(Event) -> bool) {
unsafe {
let callback: Option<unsafe extern "C" fn(ev: raw::c_int) -> raw::c_int> =
Some(mem::transmute(move |ev| {
let _ = panic::catch_unwind(panic::AssertUnwindSafe(|| cb(ev) as i32));
}));
fl::Fl_add_handler(callback);
}
}
pub fn handle<I: Into<Event> + Copy + PartialEq + PartialOrd, W: WindowExt>(
msg: I,
w: &W,
) -> Result<bool, FltkError> {
let val = msg.into();
let ret = unsafe { fl::Fl_handle(val.bits(), w.as_widget_ptr() as _) != 0 };
Ok(ret)
}
pub fn handle_main<I: Into<Event> + Copy + PartialEq + PartialOrd>(
msg: I,
) -> Result<bool, FltkError> {
let val = msg.into();
first_window().map_or(
Err(FltkError::Internal(FltkErrorKind::FailedOperation)),
|win| {
let ret = unsafe { fl::Fl_handle(val.bits(), win.as_widget_ptr() as _) != 0 };
Ok(ret)
},
)
}
#[cfg(target_os = "macos")]
pub fn raw_open_callback(cb: Option<fn(*const raw::c_char)>) {
unsafe {
if let Some(cb) = cb {
fl::Fl_open_callback(Some(mem::transmute(cb)))
} else {
fl::Fl_open_callback(None)
}
}
}
pub fn callback_reason() -> CallbackReason {
unsafe { mem::transmute(fl::Fl_callback_reason()) }
}
#[cfg(target_os = "windows")]
pub fn fl_msg() -> *mut raw::c_void {
unsafe { fl::Fl_get_fl_msg() }
}