1#![allow(deprecated)]
2
3use crate::enums::{Color, Font, Key};
4use crate::prelude::*;
5use crate::utils::FlString;
6use fltk_sys::text::*;
7use std::{
8 ffi::{CStr, CString},
9 os::raw,
10};
11
12unsafe extern "C" fn text_modify_shim(
14 pos: raw::c_int,
15 inserted: raw::c_int,
16 deleted: raw::c_int,
17 restyled: raw::c_int,
18 deleted_text: *const raw::c_char,
19 data: *mut raw::c_void,
20) {
21 let temp = if deleted_text.is_null() {
22 String::from("")
23 } else {
24 CStr::from_ptr(deleted_text).to_string_lossy().to_string()
25 };
26 let a: *mut Box<dyn FnMut(i32, i32, i32, i32, &str)> =
27 data as *mut Box<dyn for<'r> FnMut(i32, i32, i32, i32, &'r str)>;
28 let f: &mut (dyn FnMut(i32, i32, i32, i32, &str)) = &mut **a;
29 let _ = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
30 f(pos, inserted, deleted, restyled, &temp)
31 }));
32}
33
34unsafe extern "C" fn text_predelete_shim(
35 pos: raw::c_int,
36 deleted: raw::c_int,
37 data: *mut raw::c_void,
38) {
39 let a: *mut Box<dyn FnMut(i32, i32)> = data as *mut Box<dyn FnMut(i32, i32)>;
40 let f: &mut (dyn FnMut(i32, i32)) = &mut **a;
41 let _ = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| f(pos, deleted)));
42}
43
44type BufWrapper = std::rc::Rc<*mut Fl_Text_Buffer>;
45
46#[repr(i32)]
48#[derive(Debug, Copy, Clone, PartialEq, Eq)]
49pub enum Cursor {
50 Normal,
52 Caret,
54 Dim,
56 Block,
58 Heavy,
60 Simple,
62}
63
64#[derive(Debug)]
66pub struct TextBuffer {
67 inner: BufWrapper,
68}
69
70impl std::default::Default for TextBuffer {
71 fn default() -> TextBuffer {
73 unsafe {
74 let text_buffer = Fl_Text_Buffer_new();
75 assert!(!text_buffer.is_null());
76 TextBuffer {
77 inner: BufWrapper::new(text_buffer),
78 }
79 }
80 }
81}
82
83impl TextBuffer {
84 pub unsafe fn delete(buf: Self) {
88 assert!(!buf.inner.is_null());
89 unsafe {
90 Fl_Text_Buffer_delete(*buf.inner);
91 }
92 }
93
94 pub unsafe fn delete_buffer(buf: Self) {
98 Self::delete(buf)
99 }
100
101 pub unsafe fn from_ptr(ptr: *mut Fl_Text_Buffer) -> Self {
105 assert!(!ptr.is_null());
106 let inner = BufWrapper::from(ptr);
107 let ptr = BufWrapper::into_raw(inner);
108 BufWrapper::increment_strong_count(ptr);
109 let inner = BufWrapper::from_raw(ptr);
110 TextBuffer { inner }
111 }
112
113 pub unsafe fn as_ptr(&self) -> *mut Fl_Text_Buffer {
117 let ptr = BufWrapper::into_raw(BufWrapper::clone(&self.inner));
118 BufWrapper::increment_strong_count(ptr);
119 let inner = BufWrapper::from_raw(ptr);
120 *inner
121 }
122
123 pub fn set_text(&mut self, txt: &str) {
125 assert!(!self.inner.is_null());
126 unsafe {
127 let txt = CString::safe_new(txt);
128 Fl_Text_Buffer_set_text(*self.inner, txt.as_ptr())
129 }
130 }
131
132 pub fn text(&self) -> String {
134 assert!(!self.inner.is_null());
135 unsafe {
136 let text = Fl_Text_Buffer_text(*self.inner);
137 assert!(!text.is_null());
138 CStr::from_ptr(text as *mut raw::c_char)
139 .to_string_lossy()
140 .to_string()
141 }
142 }
143
144 pub fn append(&mut self, text: &str) {
162 assert!(!self.inner.is_null());
163 let text = CString::safe_new(text);
164 unsafe { Fl_Text_Buffer_append(*self.inner, text.as_ptr()) }
165 }
166
167 pub fn append2(&mut self, text: &[u8]) {
169 assert!(!self.inner.is_null());
170 unsafe { Fl_Text_Buffer_append2(*self.inner, text.as_ptr() as _, text.len() as _) }
171 }
172
173 pub fn length(&self) -> i32 {
175 assert!(!self.inner.is_null());
176 unsafe { Fl_Text_Buffer_length(*self.inner) }
177 }
178
179 pub fn remove(&mut self, start: i32, end: i32) {
181 assert!(!self.inner.is_null());
182 unsafe {
183 Fl_Text_Buffer_remove(*self.inner, start, end);
184 }
185 }
186
187 pub fn text_range(&self, start: i32, end: i32) -> Option<String> {
189 assert!(!self.inner.is_null());
190 unsafe {
191 let x = Fl_Text_Buffer_text_range(*self.inner, start, end);
192 if x.is_null() {
193 None
194 } else {
195 Some(
196 CStr::from_ptr(x as *mut raw::c_char)
197 .to_string_lossy()
198 .to_string(),
199 )
200 }
201 }
202 }
203
204 pub fn insert(&mut self, pos: i32, text: &str) {
206 assert!(!self.inner.is_null());
207 let text = CString::safe_new(text);
208 unsafe { Fl_Text_Buffer_insert(*self.inner, pos, text.as_ptr()) }
209 }
210
211 pub fn replace(&mut self, start: i32, end: i32, text: &str) {
213 assert!(!self.inner.is_null());
214 assert!(end >= start);
215 let text = CString::safe_new(text);
216 unsafe { Fl_Text_Buffer_replace(*self.inner, start, end, text.as_ptr()) }
217 }
218
219 pub fn copy_from(&mut self, source_buf: &TextBuffer, start: i32, end: i32, to: i32) {
221 assert!(!self.inner.is_null());
222 unsafe { Fl_Text_Buffer_copy(*self.inner, *source_buf.inner, start, end, to) }
223 }
224
225 pub fn copy(&self) -> TextBuffer {
227 assert!(!self.inner.is_null());
228 let mut temp = TextBuffer::default();
229 temp.copy_from(self, 0, 0, self.length());
230 temp
231 }
232
233 pub fn undo(&mut self) -> Result<(), FltkError> {
237 assert!(!self.inner.is_null());
238 unsafe {
239 match Fl_Text_Buffer_undo(*self.inner, std::ptr::null_mut()) {
240 0 => Err(FltkError::Unknown(String::from("Failed to undo"))),
241 _ => Ok(()),
242 }
243 }
244 }
245
246 pub fn redo(&mut self) -> Result<i32, FltkError> {
251 assert!(!self.inner.is_null());
252 unsafe {
253 let mut i = 0;
254 match Fl_Text_Buffer_redo(*self.inner, &mut i) {
255 0 => Err(FltkError::Unknown(String::from("Failed to redo"))),
256 _ => Ok(i),
257 }
258 }
259 }
260
261 pub fn can_undo(&mut self, flag: bool) {
263 assert!(!self.inner.is_null());
264 unsafe { Fl_Text_Buffer_canUndo(*self.inner, flag as raw::c_char) }
265 }
266
267 pub fn get_can_undo(&mut self) -> bool {
269 assert!(!self.inner.is_null());
270 unsafe { Fl_Text_Buffer_can_undo(*self.inner) != 0 }
271 }
272
273 pub fn can_redo(&mut self) -> bool {
275 assert!(!self.inner.is_null());
276 unsafe { Fl_Text_Buffer_can_redo(*self.inner) != 0 }
277 }
278
279 pub fn load_file<P: AsRef<std::path::Path>>(&mut self, path: P) -> Result<(), FltkError> {
283 assert!(!self.inner.is_null());
284 if !path.as_ref().exists() {
285 return Err(FltkError::Internal(FltkErrorKind::ResourceNotFound));
286 }
287 let path = path
288 .as_ref()
289 .to_str()
290 .ok_or_else(|| FltkError::Unknown(String::from("Failed to convert path to string")))?;
291 let path = CString::new(path)?;
292 unsafe {
293 match Fl_Text_Buffer_load_file(*self.inner, path.as_ptr()) {
294 0 => Ok(()),
295 _ => Err(FltkError::Internal(FltkErrorKind::ResourceNotFound)),
296 }
297 }
298 }
299
300 pub fn save_file<P: AsRef<std::path::Path>>(&mut self, path: P) -> Result<(), FltkError> {
304 assert!(!self.inner.is_null());
305 let path = path
306 .as_ref()
307 .to_str()
308 .ok_or_else(|| FltkError::Unknown(String::from("Failed to convert path to string")))?;
309 let path = CString::new(path)?;
310 unsafe {
311 match Fl_Text_Buffer_save_file(*self.inner, path.as_ptr()) {
312 0 => Ok(()),
313 _ => Err(FltkError::Internal(FltkErrorKind::ResourceNotFound)),
314 }
315 }
316 }
317
318 pub fn insert_file<P: AsRef<std::path::Path>>(
322 &mut self,
323 path: P,
324 pos: i32,
325 buflen: i32,
326 ) -> Result<(), FltkError> {
327 assert!(!self.inner.is_null());
328 let path_ref = path.as_ref();
329 if !path_ref.exists() {
330 return Err(FltkError::Internal(FltkErrorKind::ResourceNotFound));
331 }
332 let path = path_ref
333 .to_str()
334 .ok_or_else(|| FltkError::Unknown(String::from("Failed to convert path to string")))?;
335 let path = CString::new(path)?;
336 unsafe {
337 match Fl_Text_Buffer_insertfile(*self.inner, path.as_ptr(), pos, buflen) {
338 0 => Ok(()),
339 _ => Err(FltkError::Internal(FltkErrorKind::FailedOperation)),
340 }
341 }
342 }
343
344 pub fn append_file<P: AsRef<std::path::Path>>(
348 &mut self,
349 path: P,
350 buflen: i32,
351 ) -> Result<(), FltkError> {
352 assert!(!self.inner.is_null());
353 let path_ref = path.as_ref();
354 if !path_ref.exists() {
355 return Err(FltkError::Internal(FltkErrorKind::ResourceNotFound));
356 }
357 let path = path_ref
358 .to_str()
359 .ok_or_else(|| FltkError::Unknown(String::from("Failed to convert path to string")))?;
360 let path = CString::new(path)?;
361 unsafe {
362 match Fl_Text_Buffer_appendfile(*self.inner, path.as_ptr(), buflen) {
363 0 => Ok(()),
364 _ => Err(FltkError::Internal(FltkErrorKind::FailedOperation)),
365 }
366 }
367 }
368
369 pub fn output_file<P: AsRef<std::path::Path>>(
373 &mut self,
374 path: P,
375 start: i32,
376 end: i32,
377 buflen: i32,
378 ) -> Result<(), FltkError> {
379 assert!(!self.inner.is_null());
380 let path_ref = path.as_ref();
381 let path = path_ref
382 .to_str()
383 .ok_or_else(|| FltkError::Unknown(String::from("Failed to convert path to string")))?;
384 let path = CString::new(path)?;
385 unsafe {
386 match Fl_Text_Buffer_outputfile(*self.inner, path.as_ptr(), start, end, buflen) {
387 0 => Ok(()),
388 _ => Err(FltkError::Internal(FltkErrorKind::FailedOperation)),
389 }
390 }
391 }
392
393 pub fn tab_distance(&self) -> i32 {
395 assert!(!self.inner.is_null());
396 unsafe { Fl_Text_Buffer_tab_distance(*self.inner) }
397 }
398
399 pub fn set_tab_distance(&mut self, tab_dist: i32) {
401 assert!(!self.inner.is_null());
402 unsafe { Fl_Text_Buffer_set_tab_distance(*self.inner, tab_dist) }
403 }
404
405 pub fn select(&mut self, start: i32, end: i32) {
407 assert!(!self.inner.is_null());
408 unsafe { Fl_Text_Buffer_select(*self.inner, start, end) }
409 }
410
411 pub fn selected(&self) -> bool {
413 assert!(!self.inner.is_null());
414 unsafe { Fl_Text_Buffer_selected(*self.inner) != 0 }
415 }
416
417 pub fn unselect(&mut self) {
419 assert!(!self.inner.is_null());
420 unsafe { Fl_Text_Buffer_unselect(*self.inner) }
421 }
422
423 pub fn selection_position(&self) -> Option<(i32, i32)> {
425 assert!(!self.inner.is_null());
426 unsafe {
427 let mut start = 0;
428 let mut end = 0;
429 let ret =
430 Fl_Text_Buffer_selection_position(*self.inner, &mut start as _, &mut end as _);
431 if ret == 0 {
432 None
433 } else {
434 let x = (start, end);
435 Some(x)
436 }
437 }
438 }
439
440 pub fn selection_text(&self) -> String {
442 assert!(!self.inner.is_null());
443 unsafe {
444 let x = Fl_Text_Buffer_selection_text(*self.inner);
445 assert!(!x.is_null());
446 CStr::from_ptr(x as *mut raw::c_char)
447 .to_string_lossy()
448 .to_string()
449 }
450 }
451
452 pub fn remove_selection(&mut self) {
454 assert!(!self.inner.is_null());
455 unsafe { Fl_Text_Buffer_remove_selection(*self.inner) }
456 }
457
458 pub fn replace_selection(&mut self, text: &str) {
460 assert!(!self.inner.is_null());
461 let text = CString::safe_new(text);
462 unsafe { Fl_Text_Buffer_replace_selection(*self.inner, text.as_ptr()) }
463 }
464
465 pub fn secondary_select(&mut self, start: i32, end: i32) {
467 assert!(!self.inner.is_null());
468 unsafe { Fl_Text_Buffer_secondary_select(*self.inner, start, end) }
469 }
470
471 pub fn secondary_selected(&self) -> bool {
473 assert!(!self.inner.is_null());
474 unsafe { Fl_Text_Buffer_secondary_selected(*self.inner) != 0 }
475 }
476
477 pub fn secondary_unselect(&mut self) {
479 assert!(!self.inner.is_null());
480 unsafe { Fl_Text_Buffer_secondary_unselect(*self.inner) }
481 }
482
483 pub fn secondary_selection_position(&self) -> Option<(i32, i32)> {
485 assert!(!self.inner.is_null());
486 unsafe {
487 let mut start = 0;
488 let mut end = 0;
489 let ret = Fl_Text_Buffer_secondary_selection_position(
490 *self.inner,
491 &mut start as _,
492 &mut end as _,
493 );
494 if ret == 0 {
495 None
496 } else {
497 let x = (start, end);
498 Some(x)
499 }
500 }
501 }
502
503 pub fn secondary_selection_text(&self) -> String {
505 assert!(!self.inner.is_null());
506 unsafe {
507 let x = Fl_Text_Buffer_secondary_selection_text(*self.inner);
508 assert!(!x.is_null());
509 CStr::from_ptr(x as *mut raw::c_char)
510 .to_string_lossy()
511 .to_string()
512 }
513 }
514
515 pub fn remove_secondary_selection(&mut self) {
517 assert!(!self.inner.is_null());
518 unsafe { Fl_Text_Buffer_remove_secondary_selection(*self.inner) }
519 }
520
521 pub fn replace_secondary_selection(&mut self, text: &str) {
523 assert!(!self.inner.is_null());
524 let text = CString::safe_new(text);
525 unsafe { Fl_Text_Buffer_replace_secondary_selection(*self.inner, text.as_ptr()) }
526 }
527
528 pub fn highlight(&mut self, start: i32, end: i32) {
530 assert!(!self.inner.is_null());
531 unsafe { Fl_Text_Buffer_highlight(*self.inner, start, end) }
532 }
533
534 pub fn is_highlighted(&self) -> bool {
536 assert!(!self.inner.is_null());
537 unsafe { Fl_Text_Buffer_is_highlighted(*self.inner) != 0 }
538 }
539
540 pub fn unhighlight(&mut self) {
542 assert!(!self.inner.is_null());
543 unsafe { Fl_Text_Buffer_unhighlight(*self.inner) }
544 }
545
546 pub fn highlight_position(&self) -> Option<(i32, i32)> {
548 assert!(!self.inner.is_null());
549 unsafe {
550 let mut start = 0;
551 let mut end = 0;
552 let ret =
553 Fl_Text_Buffer_highlight_position(*self.inner, &mut start as _, &mut end as _);
554 if ret == 0 {
555 None
556 } else {
557 let x = (start, end);
558 Some(x)
559 }
560 }
561 }
562
563 pub fn highlight_text(&self) -> String {
565 assert!(!self.inner.is_null());
566 unsafe {
567 let x = Fl_Text_Buffer_highlight_text(*self.inner);
568 assert!(!x.is_null());
569 CStr::from_ptr(x as *mut raw::c_char)
570 .to_string_lossy()
571 .to_string()
572 }
573 }
574
575 pub fn line_text(&self, pos: i32) -> String {
577 assert!(!self.inner.is_null());
578 unsafe {
579 let x = Fl_Text_Buffer_line_text(*self.inner, pos);
580 assert!(!x.is_null());
581 CStr::from_ptr(x as *mut raw::c_char)
582 .to_string_lossy()
583 .to_string()
584 }
585 }
586
587 pub fn line_start(&self, pos: i32) -> i32 {
589 assert!(!self.inner.is_null());
590 unsafe { Fl_Text_Buffer_line_start(*self.inner, pos) }
591 }
592
593 pub fn line_end(&self, pos: i32) -> i32 {
595 assert!(!self.inner.is_null());
596 unsafe { Fl_Text_Buffer_line_end(*self.inner, pos) }
597 }
598
599 pub fn word_start(&self, pos: i32) -> i32 {
601 assert!(!self.inner.is_null());
602 unsafe { Fl_Text_Buffer_word_start(*self.inner, pos) }
603 }
604
605 pub fn word_end(&self, pos: i32) -> i32 {
607 assert!(!self.inner.is_null());
608 unsafe { Fl_Text_Buffer_word_end(*self.inner, pos) }
609 }
610
611 pub fn count_lines(&self, start: i32, end: i32) -> i32 {
613 assert!(!self.inner.is_null());
614 unsafe { Fl_Text_Buffer_count_lines(*self.inner, start, end) }
615 }
616
617 pub fn call_modify_callbacks(&mut self) {
619 assert!(!self.inner.is_null());
620 unsafe { Fl_Text_Buffer_call_modify_callbacks(*self.inner) }
621 }
622
623 pub fn call_predelete_callbacks(&mut self) {
625 assert!(!self.inner.is_null());
626 unsafe { Fl_Text_Buffer_call_predelete_callbacks(*self.inner) }
627 }
628
629 pub fn add_modify_callback<F: FnMut(i32, i32, i32, i32, &str) + 'static>(&mut self, cb: F) {
633 assert!(!self.inner.is_null());
634 unsafe {
635 let a: *mut Box<dyn FnMut(i32, i32, i32, i32, &str)> =
636 Box::into_raw(Box::new(Box::new(cb)));
637 let data: *mut raw::c_void = a as *mut std::ffi::c_void;
638 let callback: Fl_Text_Modify_Cb = Some(text_modify_shim);
639 Fl_Text_Buffer_add_modify_callback(*self.inner, callback, data);
640 }
641 }
642
643 pub fn remove_modify_callback<F: FnMut(i32, i32, i32, i32, &str) + 'static>(&mut self, cb: F) {
647 assert!(!self.inner.is_null());
648 unsafe {
649 let a: *mut Box<dyn FnMut(i32, i32, i32, i32, &str)> =
650 Box::into_raw(Box::new(Box::new(cb)));
651 let data: *mut raw::c_void = a as *mut std::ffi::c_void;
652 let callback: Fl_Text_Modify_Cb = Some(text_modify_shim);
653 Fl_Text_Buffer_remove_modify_callback(*self.inner, callback, data);
654 }
655 }
656
657 pub fn add_predelete_callback<F: FnMut(i32, i32) + 'static>(&mut self, cb: F) {
660 assert!(!self.inner.is_null());
661 unsafe {
662 let a: *mut Box<dyn FnMut(i32, i32)> = Box::into_raw(Box::new(Box::new(cb)));
663 let data: *mut raw::c_void = a as *mut std::ffi::c_void;
664 let callback: Fl_Text_Predelete_Cb = Some(text_predelete_shim);
665 Fl_Text_Buffer_add_predelete_callback(*self.inner, callback, data);
666 }
667 }
668
669 pub fn remove_predelete_callback<F: FnMut(i32, i32) + 'static>(&mut self, cb: F) {
672 assert!(!self.inner.is_null());
673 unsafe {
674 let a: *mut Box<dyn FnMut(i32, i32)> = Box::into_raw(Box::new(Box::new(cb)));
675 let data: *mut raw::c_void = a as *mut std::ffi::c_void;
676 let callback: Fl_Text_Predelete_Cb = Some(text_predelete_shim);
677 Fl_Text_Buffer_remove_predelete_callback(*self.inner, callback, data);
678 }
679 }
680
681 pub fn search_forward(
683 &self,
684 start_pos: i32,
685 search_string: &str,
686 match_case: bool,
687 ) -> Option<i32> {
688 unsafe {
689 let search_string = CString::safe_new(search_string);
690 let mut found_pos = 0;
691 let ret = Fl_Text_Buffer_search_forward(
692 *self.inner,
693 start_pos,
694 search_string.as_ptr() as _,
695 &mut found_pos as _,
696 match_case as _,
697 );
698 if ret == 0 {
699 None
700 } else {
701 Some(found_pos)
702 }
703 }
704 }
705
706 pub fn search_backward(
708 &self,
709 start_pos: i32,
710 search_string: &str,
711 match_case: bool,
712 ) -> Option<i32> {
713 unsafe {
714 let search_string = CString::safe_new(search_string);
715 let mut found_pos = 0;
716 let ret = Fl_Text_Buffer_search_backward(
717 *self.inner,
718 start_pos,
719 search_string.as_ptr() as _,
720 &mut found_pos as _,
721 match_case as _,
722 );
723 if ret == 0 {
724 None
725 } else {
726 Some(found_pos)
727 }
728 }
729 }
730
731 pub fn find_char_forward(&self, start_pos: i32, search_char: char) -> Option<i32> {
733 unsafe {
734 let mut found_pos = 0;
735 let ret = Fl_Text_Buffer_findchar_forward(
736 *self.inner,
737 start_pos,
738 search_char as _,
739 &mut found_pos as _,
740 );
741 if ret == 0 {
742 None
743 } else {
744 Some(found_pos)
745 }
746 }
747 }
748
749 pub fn find_char_backward(&self, start_pos: i32, search_char: char) -> Option<i32> {
751 unsafe {
752 let mut found_pos = 0;
753 let ret = Fl_Text_Buffer_findchar_backward(
754 *self.inner,
755 start_pos,
756 search_char as _,
757 &mut found_pos as _,
758 );
759 if ret == 0 {
760 None
761 } else {
762 Some(found_pos)
763 }
764 }
765 }
766
767 pub fn char_at(&self, pos: i32) -> Option<char> {
769 assert!(!self.inner.is_null());
770 unsafe {
771 let ch = Fl_Text_Buffer_char_at(*self.inner, pos);
772 std::char::from_u32(ch)
773 }
774 }
775
776 pub fn byte_at(&self, pos: i32) -> u8 {
778 assert!(!self.inner.is_null());
779 unsafe { Fl_Text_Buffer_byte_at(*self.inner, pos) as u8 }
780 }
781
782 pub unsafe fn address(&self, pos: i32) -> *const raw::c_char {
786 assert!(!self.inner.is_null());
787 Fl_Text_Buffer_address(*self.inner as *const _, pos)
788 }
789
790 pub unsafe fn address_mut(&mut self, pos: i32) -> *mut raw::c_char {
794 assert!(!self.inner.is_null());
795 Fl_Text_Buffer_address2(*self.inner, pos)
796 }
797
798 pub fn utf8_align(&self, pos: i32) -> i32 {
800 assert!(!self.inner.is_null());
801 unsafe { Fl_Text_Buffer_utf8_align(*self.inner as *const _, pos) }
802 }
803
804 pub fn is_word_separator(&self, pos: i32) -> bool {
806 assert!(!self.inner.is_null());
807 unsafe { Fl_Text_Buffer_is_word_separator(*self.inner as *const _, pos) != 0 }
808 }
809}
810
811#[cfg(not(feature = "single-threaded"))]
812unsafe impl Sync for TextBuffer {}
813
814#[cfg(not(feature = "single-threaded"))]
815unsafe impl Send for TextBuffer {}
816
817impl PartialEq for TextBuffer {
818 fn eq(&self, other: &Self) -> bool {
819 self.inner == other.inner
820 }
821}
822
823impl Eq for TextBuffer {}
824
825impl Clone for TextBuffer {
826 fn clone(&self) -> TextBuffer {
827 assert!(!self.inner.is_null());
828 TextBuffer {
829 inner: BufWrapper::clone(&self.inner),
830 }
831 }
832}
833
834impl Drop for TextBuffer {
835 fn drop(&mut self) {
836 assert!(!self.inner.is_null());
837 if BufWrapper::strong_count(&self.inner) == 1 {
838 unsafe {
839 Fl_Text_Buffer_delete(*self.inner);
840 }
841 }
842 }
843}
844
845#[repr(i32)]
847#[derive(Debug, Copy, Clone, PartialEq, Eq)]
848pub enum WrapMode {
849 None,
851 AtColumn,
853 AtPixel,
855 AtBounds,
857}
858
859#[repr(i32)]
861#[derive(Debug, Copy, Clone, PartialEq, Eq)]
862pub enum DragType {
863 None = -2,
865 StartDnd = -1,
867 Char = 0,
869 Word = 1,
871 Line = 2,
873}
874
875#[derive(Debug)]
877pub struct TextDisplay {
878 inner: crate::widget::WidgetTracker,
879 is_derived: bool,
880}
881
882crate::macros::widget::impl_widget_ext!(TextDisplay, Fl_Text_Display);
883crate::macros::widget::impl_widget_base!(TextDisplay, Fl_Text_Display);
884crate::macros::widget::impl_widget_default!(TextDisplay);
885crate::macros::display::impl_display_ext!(TextDisplay, Fl_Text_Display);
886
887#[derive(Debug)]
889pub struct TextEditor {
890 inner: crate::widget::WidgetTracker,
891 is_derived: bool,
892}
893
894crate::macros::widget::impl_widget_ext!(TextEditor, Fl_Text_Editor);
895crate::macros::widget::impl_widget_base!(TextEditor, Fl_Text_Editor);
896crate::macros::widget::impl_widget_default!(TextEditor);
897crate::macros::display::impl_display_ext!(TextEditor, Fl_Text_Editor);
898
899pub type TextEditorPtr = *mut Fl_Text_Editor;
901
902#[deprecated(
903 since = "1.5.0",
904 note = "please use `fltk::terminal::Terminal` instead"
905)]
906#[derive(Debug)]
914pub struct SimpleTerminal {
915 inner: crate::widget::WidgetTracker,
916 is_derived: bool,
917}
918
919crate::macros::widget::impl_widget_ext!(SimpleTerminal, Fl_Simple_Terminal);
920crate::macros::widget::impl_widget_base!(SimpleTerminal, Fl_Simple_Terminal);
921crate::macros::widget::impl_widget_default!(SimpleTerminal);
922crate::macros::display::impl_display_ext!(SimpleTerminal, Fl_Simple_Terminal);
923
924#[derive(Debug, Clone, Copy, PartialEq, Eq)]
926#[repr(u32)]
927#[non_exhaustive]
928pub enum TextAttr {
929 None = 0x0000,
931 BgColor = 0x0001,
933 BgColorExt = 0x0003,
935 Underline = 0x0004,
937 Grammar = 0x0008,
939 Spelling = 0x000C,
941 StrikeThrough = 0x0010,
943}
944
945#[derive(Debug, Clone, Copy, PartialEq, Eq)]
947pub struct StyleTableEntry {
948 pub color: Color,
950 pub font: Font,
952 pub size: i32,
954}
955
956impl Default for StyleTableEntry {
957 fn default() -> Self {
958 Self {
959 color: Color::Foreground,
960 font: Font::Helvetica,
961 size: crate::app::font_size(),
962 }
963 }
964}
965
966#[derive(Debug, Clone, Copy, PartialEq, Eq)]
968pub struct StyleTableEntryExt {
969 pub color: Color,
971 pub font: Font,
973 pub size: i32,
975 pub attr: TextAttr,
977 pub bgcolor: Color,
979}
980
981impl Default for StyleTableEntryExt {
982 fn default() -> Self {
983 Self {
984 color: Color::Foreground,
985 font: Font::Helvetica,
986 size: crate::app::font_size(),
987 attr: TextAttr::None,
988 bgcolor: Color::Background2,
989 }
990 }
991}
992
993impl TextEditor {
994 pub const AnyState: crate::enums::Shortcut = crate::enums::Shortcut::from_i32(-1);
996
997 pub fn set_insert_mode(&mut self, b: bool) {
999 assert!(self.has_buffer());
1000 unsafe { Fl_Text_Editor_set_insert_mode(self.inner.widget() as _, b as i32) }
1001 }
1002
1003 pub fn insert_mode(&self) -> bool {
1005 assert!(self.has_buffer());
1006 unsafe { Fl_Text_Editor_insert_mode(self.inner.widget() as _) != 0 }
1007 }
1008
1009 pub fn set_tab_nav(&mut self, val: bool) {
1011 assert!(self.has_buffer());
1012 unsafe { Fl_Text_Editor_set_tab_nav(self.inner.widget() as _, val as i32) }
1013 }
1014
1015 pub fn tab_nav(&self) -> bool {
1017 assert!(self.has_buffer());
1018 unsafe { Fl_Text_Editor_tab_nav(self.inner.widget() as _) != 0 }
1019 }
1020
1021 pub fn copy(&self) {
1023 assert!(self.has_buffer());
1024 unsafe {
1025 Fl_Text_Editor_kf_copy(self.inner.widget() as _);
1026 }
1027 }
1028
1029 pub fn cut(&self) {
1031 assert!(self.has_buffer());
1032 unsafe {
1033 Fl_Text_Editor_kf_cut(self.inner.widget() as _);
1034 }
1035 }
1036
1037 pub fn paste(&self) {
1039 assert!(self.has_buffer());
1040 unsafe {
1041 Fl_Text_Editor_kf_paste(self.inner.widget() as _);
1042 }
1043 }
1044
1045 pub fn undo(&self) {
1047 assert!(self.has_buffer());
1048 unsafe {
1049 Fl_Text_Editor_kf_undo(self.inner.widget() as _);
1050 }
1051 }
1052
1053 pub fn redo(&self) {
1055 assert!(self.has_buffer());
1056 unsafe {
1057 Fl_Text_Editor_kf_redo(self.inner.widget() as _);
1058 }
1059 }
1060
1061 pub fn kf_default(&mut self, c: Key) {
1063 assert!(self.has_buffer());
1064 unsafe {
1065 Fl_Text_Editor_kf_default(c.bits(), self.inner.widget() as _);
1066 }
1067 }
1068
1069 pub fn kf_ignore(&mut self, c: Key) {
1071 assert!(self.has_buffer());
1072 unsafe {
1073 Fl_Text_Editor_kf_ignore(c.bits(), self.inner.widget() as _);
1074 }
1075 }
1076
1077 pub fn kf_backspace(&mut self) {
1079 assert!(self.has_buffer());
1080 unsafe {
1081 Fl_Text_Editor_kf_backspace(self.inner.widget() as _);
1082 }
1083 }
1084
1085 pub fn kf_enter(&mut self) {
1087 assert!(self.has_buffer());
1088 unsafe {
1089 Fl_Text_Editor_kf_enter(self.inner.widget() as _);
1090 }
1091 }
1092
1093 pub fn kf_move(&mut self, c: Key) {
1095 assert!(self.has_buffer());
1096 unsafe {
1097 Fl_Text_Editor_kf_move(c.bits(), self.inner.widget() as _);
1098 }
1099 }
1100
1101 pub fn kf_shift_move(&mut self, c: Key) {
1103 assert!(self.has_buffer());
1104 unsafe {
1105 Fl_Text_Editor_kf_shift_move(c.bits(), self.inner.widget() as _);
1106 }
1107 }
1108
1109 pub fn kf_ctrl_move(&mut self, c: Key) {
1111 assert!(self.has_buffer());
1112 unsafe {
1113 Fl_Text_Editor_kf_ctrl_move(c.bits(), self.inner.widget() as _);
1114 }
1115 }
1116
1117 pub fn kf_c_s_move(&mut self, c: Key) {
1119 assert!(self.has_buffer());
1120 unsafe {
1121 Fl_Text_Editor_kf_c_s_move(c.bits(), self.inner.widget() as _);
1122 }
1123 }
1124
1125 pub fn kf_meta_move(&mut self, c: Key) {
1127 assert!(self.has_buffer());
1128 unsafe {
1129 Fl_Text_Editor_kf_meta_move(c.bits(), self.inner.widget() as _);
1130 }
1131 }
1132
1133 pub fn kf_m_s_move(&mut self, c: Key) {
1135 assert!(self.has_buffer());
1136 unsafe {
1137 Fl_Text_Editor_kf_m_s_move(c.bits(), self.inner.widget() as _);
1138 }
1139 }
1140
1141 pub fn kf_home(&mut self) {
1143 assert!(self.has_buffer());
1144 unsafe {
1145 Fl_Text_Editor_kf_home(self.inner.widget() as _);
1146 }
1147 }
1148
1149 pub fn kf_end(&mut self) {
1151 assert!(self.has_buffer());
1152 unsafe {
1153 Fl_Text_Editor_kf_end(self.inner.widget() as _);
1154 }
1155 }
1156
1157 pub fn kf_left(&mut self) {
1159 assert!(self.has_buffer());
1160 unsafe {
1161 Fl_Text_Editor_kf_left(self.inner.widget() as _);
1162 }
1163 }
1164
1165 pub fn kf_up(&mut self) {
1167 assert!(self.has_buffer());
1168 unsafe {
1169 Fl_Text_Editor_kf_up(self.inner.widget() as _);
1170 }
1171 }
1172
1173 pub fn kf_right(&mut self) {
1175 assert!(self.has_buffer());
1176 unsafe {
1177 Fl_Text_Editor_kf_right(self.inner.widget() as _);
1178 }
1179 }
1180
1181 pub fn kf_down(&mut self) {
1183 assert!(self.has_buffer());
1184 unsafe {
1185 Fl_Text_Editor_kf_down(self.inner.widget() as _);
1186 }
1187 }
1188
1189 pub fn kf_page_up(&mut self) {
1191 assert!(self.has_buffer());
1192 unsafe {
1193 Fl_Text_Editor_kf_page_up(self.inner.widget() as _);
1194 }
1195 }
1196
1197 pub fn kf_page_down(&mut self) {
1199 assert!(self.has_buffer());
1200 unsafe {
1201 Fl_Text_Editor_kf_page_down(self.inner.widget() as _);
1202 }
1203 }
1204
1205 pub fn kf_insert(&mut self) {
1207 assert!(self.has_buffer());
1208 unsafe {
1209 Fl_Text_Editor_kf_insert(self.inner.widget() as _);
1210 }
1211 }
1212
1213 pub fn kf_delete(&mut self) {
1215 assert!(self.has_buffer());
1216 unsafe {
1217 Fl_Text_Editor_kf_delete(self.inner.widget() as _);
1218 }
1219 }
1220
1221 pub fn kf_select_all(&mut self) {
1223 assert!(self.has_buffer());
1224 unsafe {
1225 Fl_Text_Editor_kf_select_all(self.inner.widget() as _);
1226 }
1227 }
1228
1229 pub fn add_key_binding(
1231 &mut self,
1232 key: crate::enums::Key,
1233 shortcut: crate::enums::Shortcut,
1234 cb: fn(key: crate::enums::Key, editor: TextEditorPtr) -> i32,
1235 ) {
1236 unsafe {
1237 Fl_Text_Editor_add_key_binding(
1238 self.inner.widget() as _,
1239 key.bits(),
1240 shortcut.bits(),
1241 std::mem::transmute(Some(cb)),
1242 );
1243 }
1244 }
1245
1246 pub fn remove_key_binding(&mut self, key: crate::enums::Key, shortcut: crate::enums::Shortcut) {
1248 unsafe {
1249 Fl_Text_Editor_remove_key_binding(
1250 self.inner.widget() as _,
1251 key.bits(),
1252 shortcut.bits(),
1253 );
1254 }
1255 }
1256}
1257
1258impl SimpleTerminal {
1259 pub fn set_stay_at_bottom(&mut self, arg1: bool) {
1261 assert!(self.has_buffer());
1262 unsafe { Fl_Simple_Terminal_set_stay_at_bottom(self.inner.widget() as _, arg1 as i32) }
1263 }
1264
1265 pub fn stay_at_bottom(&self) -> bool {
1267 assert!(self.has_buffer());
1268 unsafe { Fl_Simple_Terminal_stay_at_bottom(self.inner.widget() as _) != 0 }
1269 }
1270
1271 pub fn set_history_lines(&mut self, arg1: i32) {
1273 assert!(self.has_buffer());
1274 unsafe { Fl_Simple_Terminal_set_history_lines(self.inner.widget() as _, arg1) }
1275 }
1276
1277 pub fn history_lines(&self) -> i32 {
1279 assert!(self.has_buffer());
1280 unsafe { Fl_Simple_Terminal_history_lines(self.inner.widget() as _) }
1281 }
1282
1283 pub fn set_ansi(&mut self, val: bool) {
1285 assert!(self.has_buffer());
1286 unsafe { Fl_Simple_Terminal_set_ansi(self.inner.widget() as _, val as i32) }
1287 }
1288
1289 pub fn ansi(&self) -> bool {
1291 assert!(self.has_buffer());
1292 unsafe { Fl_Simple_Terminal_ansi(self.inner.widget() as _) != 0 }
1293 }
1294
1295 pub fn append(&mut self, s: &str) {
1297 assert!(self.has_buffer());
1298 let raw_s = CString::safe_new(s).into_raw();
1299 unsafe {
1300 Fl_Simple_Terminal_append(self.inner.widget() as _, raw_s as _);
1301 let _raw_s = CString::from_raw(raw_s);
1303 }
1304 }
1305
1306 pub fn append2(&mut self, s: &[u8]) {
1308 assert!(self.has_buffer());
1309 unsafe {
1310 Fl_Simple_Terminal_append2(self.inner.widget() as _, s.as_ptr() as _, s.len() as _)
1311 }
1312 }
1313
1314 pub fn set_text(&mut self, s: &str) {
1316 assert!(self.has_buffer());
1317 let raw_s = CString::safe_new(s).into_raw();
1318 unsafe {
1319 Fl_Simple_Terminal_set_text(self.inner.widget() as _, raw_s as _);
1320 let _raw_s = CString::from_raw(raw_s);
1322 }
1323 }
1324
1325 pub fn set_bytes(&mut self, s: &[u8]) {
1327 assert!(self.has_buffer());
1328 unsafe {
1329 Fl_Simple_Terminal_set_text2(self.inner.widget() as _, s.as_ptr() as _, s.len() as _)
1330 }
1331 }
1332
1333 pub fn text(&self) -> String {
1335 assert!(self.has_buffer());
1336 unsafe {
1337 let ptr = Fl_Simple_Terminal_text(self.inner.widget() as _);
1338 assert!(!ptr.is_null());
1339 CStr::from_ptr(ptr as *mut raw::c_char)
1340 .to_string_lossy()
1341 .to_string()
1342 }
1343 }
1344
1345 pub fn clear(&mut self) {
1347 assert!(self.has_buffer());
1348 unsafe { Fl_Simple_Terminal_clear(self.inner.widget() as _) }
1349 }
1350
1351 pub fn remove_lines(&mut self, start: i32, count: i32) {
1353 assert!(self.has_buffer());
1354 unsafe { Fl_Simple_Terminal_remove_lines(self.inner.widget() as _, start, count) }
1355 }
1356}