use crate::image::Image;
pub use crate::prelude::*;
use fltk_sys::text::*;
use std::{
ffi::{CStr, CString},
mem,
os::raw,
};
#[derive(Debug)]
pub struct TextBuffer {
_inner: *mut Fl_Text_Buffer,
}
impl TextBuffer {
pub fn default() -> Self {
unsafe {
let text_buffer = Fl_Text_Buffer_new();
assert!(!text_buffer.is_null());
TextBuffer {
_inner: text_buffer,
}
}
}
pub unsafe fn delete(&mut self) {
Fl_Text_Buffer_delete(self._inner)
}
pub unsafe fn from_ptr(ptr: *mut Fl_Text_Buffer) -> Self {
TextBuffer { _inner: ptr }
}
pub unsafe fn as_ptr(&self) -> *mut Fl_Text_Buffer {
self._inner
}
pub fn set_text(&mut self, txt: &str) {
unsafe {
let txt = CString::new(txt).unwrap();
Fl_Text_Buffer_set_text(self._inner, txt.as_ptr())
}
}
pub fn text(&self) -> String {
unsafe {
let text = Fl_Text_Buffer_text(self._inner);
assert!(!text.is_null());
CString::from_raw(text as *mut raw::c_char)
.to_string_lossy()
.to_string()
}
}
pub fn append(&mut self, text: &str) {
let text = CString::new(text).unwrap();
unsafe { Fl_Text_Buffer_append(self._inner, text.as_ptr()) }
}
pub fn length(&self) -> u32 {
unsafe { Fl_Text_Buffer_length(self._inner) as u32 }
}
pub fn remove(&mut self, start: u32, end: u32) {
debug_assert!(
start <= std::i32::MAX as u32,
"u32 entries must be < std::i32::MAX for compatibility!"
);
debug_assert!(
end <= std::i32::MAX as u32,
"u32 entries must be < std::i32::MAX for compatibility!"
);
unsafe {
Fl_Text_Buffer_remove(self._inner, start as i32, end as i32);
}
}
pub fn text_range(&self, start: u32, end: u32) -> Option<String> {
debug_assert!(
start <= std::i32::MAX as u32,
"u32 entries must be < std::i32::MAX for compatibility!"
);
debug_assert!(
end <= std::i32::MAX as u32,
"u32 entries must be < std::i32::MAX for compatibility!"
);
unsafe {
let x = Fl_Text_Buffer_text_range(self._inner, start as i32, end as i32);
if x.is_null() {
None
} else {
Some(
CString::from_raw(x as *mut raw::c_char)
.to_string_lossy()
.to_string(),
)
}
}
}
pub fn insert(&mut self, pos: u32, text: &str) {
debug_assert!(
pos <= std::i32::MAX as u32,
"u32 entries must be < std::i32::MAX for compatibility!"
);
let text = CString::new(text).unwrap();
unsafe { Fl_Text_Buffer_insert(self._inner, pos as i32, text.as_ptr()) }
}
pub fn replace(&mut self, start: u32, end: u32, text: &str) {
debug_assert!(
start <= std::i32::MAX as u32,
"u32 entries must be < std::i32::MAX for compatibility!"
);
debug_assert!(
end <= std::i32::MAX as u32,
"u32 entries must be < std::i32::MAX for compatibility!"
);
let text = CString::new(text).unwrap();
unsafe { Fl_Text_Buffer_replace(self._inner, start as i32, end as i32, text.as_ptr()) }
}
pub fn copy(&mut self, source_buf: &TextBuffer, start: u32, end: u32, to: u32) {
debug_assert!(
start <= std::i32::MAX as u32,
"u32 entries must be < std::i32::MAX for compatibility!"
);
debug_assert!(
end <= std::i32::MAX as u32,
"u32 entries must be < std::i32::MAX for compatibility!"
);
debug_assert!(
to <= std::i32::MAX as u32,
"u32 entries must be < std::i32::MAX for compatibility!"
);
unsafe {
Fl_Text_Buffer_copy(
self._inner,
source_buf.as_ptr(),
start as i32,
end as i32,
to as i32,
)
}
}
pub fn undo(&mut self) -> Result<(), FltkError> {
unsafe {
match Fl_Text_Buffer_undo(self._inner, std::ptr::null_mut()) {
0 => Err(FltkError::Unknown(String::from("Failed to undo"))),
_ => Ok(()),
}
}
}
pub fn can_undo(&mut self, flag: bool) {
unsafe { Fl_Text_Buffer_canUndo(self._inner, flag as i8) }
}
pub fn load_file(&mut self, path: &std::path::Path) -> Result<(), FltkError> {
if !path.exists() {
return Err(FltkError::Internal(FltkErrorKind::ResourceNotFound));
}
let path = path.to_str().unwrap();
let path = CString::new(path)?;
unsafe {
match Fl_Text_Buffer_loadfile(self._inner, path.as_ptr(), 0) {
0 => Err(FltkError::Internal(FltkErrorKind::ResourceNotFound)),
_ => Ok(()),
}
}
}
pub fn tab_distance(&self) -> u32 {
unsafe { Fl_Text_Buffer_tab_distance(self._inner) as u32 }
}
pub fn set_tab_distance(&mut self, tab_dist: u32) {
debug_assert!(
tab_dist <= std::i32::MAX as u32,
"u32 entries must be < std::i32::MAX for compatibility!"
);
unsafe { Fl_Text_Buffer_set_tab_distance(self._inner, tab_dist as i32) }
}
pub fn select(&mut self, start: u32, end: u32) {
debug_assert!(
start <= std::i32::MAX as u32,
"u32 entries must be < std::i32::MAX for compatibility!"
);
debug_assert!(
end <= std::i32::MAX as u32,
"u32 entries must be < std::i32::MAX for compatibility!"
);
unsafe { Fl_Text_Buffer_select(self._inner, start as i32, end as i32) }
}
pub fn selected(&self) -> bool {
unsafe {
match Fl_Text_Buffer_selected(self._inner) {
0 => false,
_ => true,
}
}
}
pub fn unselect(&mut self) {
unsafe { Fl_Text_Buffer_unselect(self._inner) }
}
pub fn selection_position(&mut self) -> Option<(u32, u32)> {
unsafe {
let start: *mut raw::c_int = std::ptr::null_mut();
let end: *mut raw::c_int = std::ptr::null_mut();
let ret = Fl_Text_Buffer_selection_position(self._inner, start, end);
if ret != 0 {
let x = (*start as u32, *end as u32);
Some(x)
} else {
None
}
}
}
pub fn selection_text(&mut self) -> String {
unsafe {
let x = Fl_Text_Buffer_selection_text(self._inner);
assert!(!x.is_null());
CString::from_raw(x as *mut raw::c_char)
.to_string_lossy()
.to_string()
}
}
pub fn remove_selection(&mut self) {
unsafe { Fl_Text_Buffer_remove_selection(self._inner) }
}
pub fn replace_selection(&mut self, text: &str) {
let text = CString::new(text).unwrap();
unsafe { Fl_Text_Buffer_replace_selection(self._inner, text.as_ptr()) }
}
pub fn highlight(&mut self, start: u32, end: u32) {
debug_assert!(
start <= std::i32::MAX as u32,
"u32 entries must be < std::i32::MAX for compatibility!"
);
debug_assert!(
end <= std::i32::MAX as u32,
"u32 entries must be < std::i32::MAX for compatibility!"
);
unsafe { Fl_Text_Buffer_highlight(self._inner, start as i32, end as i32) }
}
pub fn is_highlighted(&mut self) -> bool {
unsafe {
match Fl_Text_Buffer_is_highlighted(self._inner) {
0 => false,
_ => true,
}
}
}
pub fn unhighlight(&mut self) {
unsafe { Fl_Text_Buffer_unhighlight(self._inner) }
}
pub fn highlight_position(&mut self) -> Option<(u32, u32)> {
unsafe {
let start: *mut raw::c_int = std::ptr::null_mut();
let end: *mut raw::c_int = std::ptr::null_mut();
let ret = Fl_Text_Buffer_highlight_position(self._inner, start, end);
if ret != 0 {
let x = (*start as u32, *end as u32);
Some(x)
} else {
None
}
}
}
pub fn highlight_text(&mut self) -> String {
unsafe {
let x = Fl_Text_Buffer_highlight_text(self._inner);
assert!(!x.is_null());
CString::from_raw(x as *mut raw::c_char)
.to_string_lossy()
.to_string()
}
}
pub fn line_text(&self, pos: u32) -> String {
debug_assert!(
pos <= std::i32::MAX as u32,
"u32 entries must be < std::i32::MAX for compatibility!"
);
unsafe {
let x = Fl_Text_Buffer_line_text(self._inner, pos as i32);
assert!(!x.is_null());
CString::from_raw(x as *mut raw::c_char)
.to_string_lossy()
.to_string()
}
}
pub fn line_start(&self, pos: u32) -> u32 {
debug_assert!(
pos <= std::i32::MAX as u32,
"u32 entries must be < std::i32::MAX for compatibility!"
);
unsafe { Fl_Text_Buffer_line_start(self._inner, pos as i32) as u32 }
}
pub fn word_start(&self, pos: u32) -> u32 {
debug_assert!(
pos <= std::i32::MAX as u32,
"u32 entries must be < std::i32::MAX for compatibility!"
);
unsafe { Fl_Text_Buffer_word_start(self._inner, pos as i32) as u32 }
}
pub fn word_end(&self, pos: u32) -> u32 {
debug_assert!(
pos <= std::i32::MAX as u32,
"u32 entries must be < std::i32::MAX for compatibility!"
);
unsafe { Fl_Text_Buffer_word_end(self._inner, pos as i32) as u32 }
}
pub fn count_lines(&self, start: u32, end: u32) -> u32 {
debug_assert!(
start <= std::i32::MAX as u32,
"u32 entries must be < std::i32::MAX for compatibility!"
);
debug_assert!(
end <= std::i32::MAX as u32,
"u32 entries must be < std::i32::MAX for compatibility!"
);
unsafe { Fl_Text_Buffer_count_lines(self._inner, start as i32, end as i32) as u32 }
}
pub fn call_modify_callbacks(&mut self) {
unsafe { Fl_Text_Buffer_call_modify_callbacks(self._inner) }
}
pub fn add_modify_callback(&mut self, cb: Box<dyn FnMut(u32, u32, u32, u32, &str)>) {
unsafe {
unsafe extern "C" fn shim(
pos: raw::c_int,
inserted: raw::c_int,
deleted: raw::c_int,
restyled: raw::c_int,
deleted_text: *const raw::c_char,
data: *mut raw::c_void,
) {
let mut temp = String::from("");
if !deleted_text.is_null() {
temp = CStr::from_ptr(deleted_text).to_string_lossy().to_string();
}
let a: *mut Box<dyn FnMut(u32, u32, u32, u32, &str)> = mem::transmute(data);
let f: &mut (dyn FnMut(u32, u32, u32, u32, &str)) = &mut **a;
f(
pos as u32,
inserted as u32,
deleted as u32,
restyled as u32,
&temp,
)
}
let a: *mut Box<dyn FnMut(u32, u32, u32, u32, &str)> = Box::into_raw(Box::new(cb));
let data: *mut raw::c_void = mem::transmute(a);
let callback: Fl_Text_Modify_Cb = Some(shim);
Fl_Text_Buffer_add_modify_callback(self._inner, callback, data);
}
}
pub fn remove_modify_callback(&mut self, cb: Box<dyn FnMut(u32, u32, u32, u32, &str)>) {
unsafe {
unsafe extern "C" fn shim(
pos: raw::c_int,
inserted: raw::c_int,
deleted: raw::c_int,
restyled: raw::c_int,
deleted_text: *const raw::c_char,
data: *mut raw::c_void,
) {
let mut temp = String::from("");
if !deleted_text.is_null() {
temp = CStr::from_ptr(deleted_text).to_string_lossy().to_string();
}
let a: *mut Box<dyn FnMut(u32, u32, u32, u32, &str)> = mem::transmute(data);
let f: &mut (dyn FnMut(u32, u32, u32, u32, &str)) = &mut **a;
f(
pos as u32,
inserted as u32,
deleted as u32,
restyled as u32,
&temp,
)
}
let a: *mut Box<dyn FnMut(u32, u32, u32, u32, &str)> = Box::into_raw(Box::new(cb));
let data: *mut raw::c_void = mem::transmute(a);
let callback: Fl_Text_Modify_Cb = Some(shim);
Fl_Text_Buffer_remove_modify_callback(self._inner, callback, data);
}
}
}
unsafe impl Sync for TextBuffer {}
unsafe impl Send for TextBuffer {}
impl Clone for TextBuffer {
fn clone(&self) -> TextBuffer {
let mut temp = TextBuffer::default();
temp.copy(self, 0, 0, self.length());
temp
}
}
#[derive(WidgetExt, DisplayExt, Debug)]
pub struct TextDisplay {
_inner: *mut Fl_Text_Display,
_tracker: *mut fltk_sys::fl::Fl_Widget_Tracker,
}
#[derive(WidgetExt, DisplayExt, Debug)]
pub struct TextEditor {
_inner: *mut Fl_Text_Editor,
_tracker: *mut fltk_sys::fl::Fl_Widget_Tracker,
}
#[derive(WidgetExt, DisplayExt, Debug)]
pub struct SimpleTerminal {
_inner: *mut Fl_Simple_Terminal,
_tracker: *mut fltk_sys::fl::Fl_Widget_Tracker,
}
#[derive(Debug, Clone, Copy)]
pub struct StyleTableEntry {
pub color: Color,
pub font: Font,
pub size: u32,
}
impl TextEditor {
pub fn new(x: i32, y: i32, w: i32, h: i32, buf: &mut TextBuffer) -> TextEditor {
let temp = CString::new("").unwrap();
unsafe {
let text_editor = Fl_Text_Editor_new(x, y, w, h, temp.into_raw() as *const raw::c_char);
assert!(!text_editor.is_null());
let tracker =
fltk_sys::fl::Fl_Widget_Tracker_new(text_editor as *mut fltk_sys::fl::Fl_Widget);
assert!(!tracker.is_null());
let mut x = TextEditor {
_inner: text_editor,
_tracker: tracker,
};
x.set_buffer(buf);
x
}
}
pub fn default(buf: &mut TextBuffer) -> TextEditor {
let temp = CString::new("").unwrap();
unsafe {
let text_editor = Fl_Text_Editor_new(0, 0, 0, 0, temp.into_raw() as *const raw::c_char);
assert!(!text_editor.is_null());
let tracker =
fltk_sys::fl::Fl_Widget_Tracker_new(text_editor as *mut fltk_sys::fl::Fl_Widget);
assert!(!tracker.is_null());
let mut x = TextEditor {
_inner: text_editor,
_tracker: tracker,
};
x.set_buffer(buf);
x
}
}
pub fn copy(&self) {
assert!(!self.was_deleted());
unsafe {
kf_copy(self._inner);
}
}
pub fn cut(&self) {
assert!(!self.was_deleted());
unsafe {
kf_cut(self._inner);
}
}
pub fn paste(&self) {
assert!(!self.was_deleted());
unsafe {
kf_paste(self._inner);
}
}
pub fn undo(&self) {
assert!(!self.was_deleted());
unsafe {
kf_undo(self._inner);
}
}
}
impl TextDisplay {
pub fn new(x: i32, y: i32, w: i32, h: i32, buf: &mut TextBuffer) -> TextDisplay {
let temp = CString::new("").unwrap();
unsafe {
let text_display =
Fl_Text_Display_new(x, y, w, h, temp.into_raw() as *const raw::c_char);
assert!(!text_display.is_null(),);
let tracker =
fltk_sys::fl::Fl_Widget_Tracker_new(text_display as *mut fltk_sys::fl::Fl_Widget);
assert!(!tracker.is_null());
let mut x = TextDisplay {
_inner: text_display,
_tracker: tracker,
};
x.set_buffer(buf);
x
}
}
pub fn default(buf: &mut TextBuffer) -> TextDisplay {
let temp = CString::new("").unwrap();
unsafe {
let text_display =
Fl_Text_Display_new(0, 0, 0, 0, temp.into_raw() as *const raw::c_char);
assert!(!text_display.is_null(),);
let tracker =
fltk_sys::fl::Fl_Widget_Tracker_new(text_display as *mut fltk_sys::fl::Fl_Widget);
assert!(!tracker.is_null());
let mut x = TextDisplay {
_inner: text_display,
_tracker: tracker,
};
x.set_buffer(buf);
x
}
}
}
impl SimpleTerminal {
pub fn new(x: i32, y: i32, w: i32, h: i32, buf: &mut TextBuffer) -> SimpleTerminal {
let temp = CString::new("").unwrap();
unsafe {
let simple_terminal =
Fl_Simple_Terminal_new(x, y, w, h, temp.into_raw() as *const raw::c_char);
assert!(!simple_terminal.is_null(),);
let tracker = fltk_sys::fl::Fl_Widget_Tracker_new(
simple_terminal as *mut fltk_sys::fl::Fl_Widget,
);
assert!(!tracker.is_null());
let mut x = SimpleTerminal {
_inner: simple_terminal,
_tracker: tracker,
};
x.set_buffer(buf);
x
}
}
pub fn default(buf: &mut TextBuffer) -> SimpleTerminal {
let temp = CString::new("").unwrap();
unsafe {
let simple_terminal =
Fl_Simple_Terminal_new(0, 0, 0, 0, temp.into_raw() as *const raw::c_char);
assert!(!simple_terminal.is_null(),);
let tracker = fltk_sys::fl::Fl_Widget_Tracker_new(
simple_terminal as *mut fltk_sys::fl::Fl_Widget,
);
assert!(!tracker.is_null());
let mut x = SimpleTerminal {
_inner: simple_terminal,
_tracker: tracker,
};
x.set_buffer(buf);
x
}
}
}
#[cfg(test)]
mod editor {
#[test]
fn buffer() {}
}