fltk/
terminal.rs

1use crate::enums::{Color, Font};
2use crate::prelude::*;
3use crate::utils::FlString;
4use fltk_sys::term::*;
5use std::{
6    ffi::{CStr, CString},
7    os::raw::c_char,
8};
9
10/// Creates a scrollable display widget to handle terminal-like behavior, such as
11/// logging events or debug information.
12/// Replaces `SimpleTerminal` widget
13///
14#[derive(Debug)]
15pub struct Terminal {
16    inner: crate::widget::WidgetTracker,
17    is_derived: bool,
18}
19
20crate::macros::widget::impl_widget_ext!(Terminal, Fl_Terminal);
21crate::macros::widget::impl_widget_base!(Terminal, Fl_Terminal);
22crate::macros::widget::impl_widget_default!(Terminal, Fl_Terminal);
23crate::macros::group::impl_group_ext!(Terminal, Fl_Terminal);
24
25///   Determines when `Fl_Terminal` calls `redraw()` if new text is added.
26/// `RATE_LIMITED` is the recommended setting, using `redraw_rate(float)` to determine
27/// the maximum rate of redraws.
28/// see `redraw_style()`, `redraw_rate()`
29#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
30pub struct RedrawStyle {
31    bits: u32,
32}
33
34impl RedrawStyle {
35    /// App must call `redraw()` as needed to update text to screen
36    pub const NoRedraw: RedrawStyle = RedrawStyle { bits: 0x0000 };
37    /// timer controlled redraws. (DEFAULT)
38    pub const RateLimited: RedrawStyle = RedrawStyle { bits: 0x0001 };
39    /// redraw triggered after *every* `append()` / `printf()` / etc. operation
40    pub const PerWrite: RedrawStyle = RedrawStyle { bits: 0x0002 };
41
42    /// Gets the inner representation
43    pub const fn bits(&self) -> u32 {
44        self.bits
45    }
46    /// Build a `RedrawStyle` enum with an arbitrary value.
47    pub const fn new(val: u32) -> Self {
48        RedrawStyle { bits: val }
49    }
50}
51
52bitflags::bitflags! {
53    /// Bits for the per-character attributes, which control text features
54    /// such as italic, bold, underlined text, etc.
55    /// Can be combined with | operator
56    #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
57    pub struct Attrib: u8 {
58        /// all attributes off
59        const Normal =  0x00 ;
60        /// bold text: uses bold font, color brighter than normal
61        const Bold = 0x01 ;
62        /// dim text; color slightly darker than normal
63        const Dim =  0x02 ;
64        /// italic font text
65        const Italic =  0x04 ;
66        /// underlined text
67        const Underline =  0x08 ;
68        /// <EM>(reserved for internal future use)</EM>
69        const _Reserved1 =   0x10 ;
70        /// inverse text; fg/bg color are swapped
71        const Inverse =   0x20 ;
72        /// <EM>(reserved for internal future use)</EM>
73        const _Reserved2 = 0x40 ;
74        /// strikeout text
75        const Strikeout = 0x80 ;
76    }
77}
78
79bitflags::bitflags! {
80    /// Output translation flags for special control character translations.
81    #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
82    pub struct OutFlags: u8 {
83        ///< no output translation
84        const OFF        = 0x00;
85        ///< carriage return generates a vertical line-feed (\\r -> \\n)
86        const CR_TO_LF   = 0x01;
87        ///< line-feed generates a carriage return (\\n -> \\r)
88        const LF_TO_CR   = 0x02;
89        ///< line-feed generates a carriage return line-feed (\\n -> \\r\\n)
90        const LF_TO_CRLF = 0x04;
91    }
92}
93
94///    'xterm color' values, used in `set_text_fg_color_xterm` and `set_text_bg_color_xterm`
95#[derive(Debug, Clone, Copy, PartialEq, Eq)]
96#[repr(u8)]
97#[allow(missing_docs)] // These color names are self-documenting
98#[non_exhaustive]
99pub enum XtermColor {
100    Black = 0,
101    Red = 1,
102    Green = 2,
103    Yellow = 3,
104    Blue = 4,
105    Magenta = 5,
106    Cyan = 6,
107    White = 7,
108}
109
110bitflags::bitflags! {
111    /// Per-character 8 bit flags (u8) used to manage special states for characters.
112    #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
113    pub struct CharFlags: u8 {
114        /// No flags
115        const NONE   = 0x00;
116        /// this char's fg color is an XTERM color; can be affected by Dim+Bold
117        const FG_XTERM   = 0x01;
118        /// this char's bg color is an XTERM color; can be affected by Dim+Bold
119        const BG_XTERM   = 0x02;
120        /// used internally for line re-wrap during screen resizing
121        const _EOL        = 0x04;
122        /// Reserved
123        const _RESV_A     = 0x08;
124        /// Reserved
125        const _RESV_B     = 0x10;
126        /// Reserved
127        const _RESV_C     = 0x20;
128        /// Reserved
129        const _RESV_D     = 0x40;
130        /// Reserved
131        const _RESV_E     = 0x80;
132    }
133}
134
135///    Controls behavior of scrollbar
136#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
137pub struct ScrollbarStyle {
138    bits: i32,
139}
140impl ScrollbarStyle {
141    /// Scrollbar is always invisible
142    pub const OFF: ScrollbarStyle = ScrollbarStyle { bits: 0 };
143    /// scrollbar is visible if widget has been resized in a way that hides some columns (default)
144    pub const AUTO: ScrollbarStyle = ScrollbarStyle { bits: 1 };
145    /// Scrollbar is always visible
146    pub const ON: ScrollbarStyle = ScrollbarStyle { bits: 2 };
147
148    /// Gets the inner representation
149    pub const fn bits(&self) -> i32 {
150        self.bits
151    }
152    /// Build a `HScrollbarStyle` with an arbitrary value.
153    pub const fn new(val: i32) -> Self {
154        ScrollbarStyle { bits: val }
155    }
156}
157
158impl std::fmt::Debug for ScrollbarStyle {
159    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
160        match *self {
161            ScrollbarStyle::OFF => write!(f, "ScrollbarStyle::OFF"),
162            ScrollbarStyle::ON => write!(f, "ScrollbarStyle::ON"),
163            ScrollbarStyle::AUTO => write!(f, "ScrollbarStyle::AUTO"),
164            _ => write!(f, "ScrollbarStyle::{}", self.bits()),
165        }
166    }
167}
168
169///    Class to manage the terminal's individual UTF-8 characters.
170///    Includes fg/bg color, attributes (BOLD, UNDERLINE..)
171/// *This is a low-level "protected" class in the fltk library*
172pub struct Utf8Char {
173    inner: *const Fl_Terminal_Utf8Char, // This points to a C++ Fl_Terminal::Utf8Char structure
174}
175
176impl std::fmt::Debug for Utf8Char {
177    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
178        let x = self.text_utf8();
179        write!(
180            f,
181            "Utf8Char {:?} '{}'  fg:{} bg:{} {:?}",
182            x,
183            std::str::from_utf8(x).unwrap(),
184            self.fgcolor(),
185            self.bgcolor(),
186            self.attrib()
187        )
188    }
189}
190
191///    Class to read characters from the terminal's buffer rows.
192///    Includes indexing access and iterators
193///    *This is a low-level "protected" class*
194pub struct BuffRow<'a> {
195    inner: *const Fl_Terminal_Utf8Char, // This points to an array of Fl_Terminal::Utf8Char
196    /// Parent terminal widget that owns this buffer
197    _parent: &'a Terminal,
198    /// Number of characters in the row
199    pub length: usize,
200    /// `sizeof(Fl_Terminal::Utf8Char)`
201    pub char_size: usize,
202}
203
204impl Terminal {
205    /// Returns whether the terminal is in ANSI mode.
206    pub fn ansi(&self) -> bool {
207        unsafe { Fl_Terminal_ansi(self.inner.widget() as _) != 0 }
208    }
209
210    /// Enable/disable ANSI mode. If true, ANSI and VT100/xterm codes will be processed.
211    /// If false, these codes won't be processed and will either be ignored or print the
212    /// error character "¿", depending on the value of `show_unknown()`.
213    pub fn set_ansi(&mut self, arg1: bool) {
214        unsafe { Fl_Terminal_set_ansi(self.inner.widget() as _, i32::from(arg1)) }
215    }
216
217    /// Appends text to the terminal at current cursor position using the current text color/attributes.
218    /// Redraws are managed automatically by default; see `redraw_style()`
219    pub fn append(&mut self, s: &str) {
220        let raw_s = CString::safe_new(s).into_raw();
221        unsafe {
222            Fl_Terminal_append(self.inner.widget() as _, raw_s as _);
223            // Take ownership of raw_s back so it will be dropped
224            let _raw_s = CString::from_raw(raw_s);
225        }
226    }
227
228    /// Appends data to the terminal at current cursor position using the current text color/attributes
229    /// Redraws are managed automatically by default; see `redraw_style()`
230    pub fn append_u8(&mut self, s: &[u8]) {
231        unsafe { Fl_Terminal_append_u8(self.inner.widget() as _, s.as_ptr() as _, s.len() as _) }
232    }
233
234    /// Appends text to the terminal at current cursor position using the current text color/attributes.
235    /// Slightly more efficient than `append_utf8`
236    /// Redraws are managed automatically by default; see `redraw_style()`
237    pub fn append_ascii(&mut self, s: &str) {
238        let raw_s = CString::safe_new(s).into_raw();
239        unsafe {
240            Fl_Terminal_append_ascii(self.inner.widget() as _, raw_s as _);
241            // Take ownership of raw_s back so it will be dropped
242            let _raw_s = CString::from_raw(raw_s);
243        }
244    }
245
246    /// Appends text to the terminal at current cursor position using the current text color/attributes.
247    /// Handles UTF-8 chars split across calls
248    /// Redraws are managed automatically by default; see `redraw_style()`
249    pub fn append_utf8(&mut self, s: &str) {
250        let raw_s = CString::safe_new(s).into_raw();
251        unsafe {
252            Fl_Terminal_append_utf8(self.inner.widget() as _, raw_s as _);
253            // Take ownership of raw_s back so it will be dropped
254            let _raw_s = CString::from_raw(raw_s);
255        }
256    }
257
258    /// Appends data to the terminal at current cursor position using the current text color/attributes
259    /// Handles UTF-8 chars split across calls
260    /// Redraws are managed automatically by default; see `redraw_style()`
261    pub fn append_utf8_u8(&mut self, s: &[u8]) {
262        unsafe {
263            Fl_Terminal_append_utf8_u8(self.inner.widget() as _, s.as_ptr() as _, s.len() as _);
264        }
265    }
266
267    /// Clears the screen to the current `textbgcolor()`, and homes the cursor.
268    pub fn clear(&mut self) {
269        unsafe { Fl_Terminal_clear(self.inner.widget() as _) }
270    }
271
272    /// Clear any current mouse selection.
273    pub fn clear_mouse_selection(&mut self) {
274        unsafe { Fl_Terminal_clear_mouse_selection(self.inner.widget() as _) }
275    }
276
277    ///  Clears the screen to a specific color `val` and homes the cursor.
278    /// Does not affect the value of `text_bg_color` or `text_bg_color_default`
279    pub fn clear_to_color(&mut self, val: Color) {
280        unsafe { Fl_Terminal_clear_to_color(self.inner.widget() as _, val.bits()) }
281    }
282
283    ///   Clear the terminal screen only; does not affect the cursor position.
284    ///
285    /// Also clears the current mouse selection.
286    ///
287    /// If `scroll_to_hist` is true, the screen is cleared by scrolling the
288    /// contents into the scrollback history, where it can be retrieved with the
289    /// scrollbar. If false, the screen is cleared
290    /// and the scrollback history is unchanged.
291    ///
292    /// Similar to the escape sequence `\<ESC\>[2J`.
293    pub fn clear_screen(&mut self, arg1: bool) {
294        unsafe { Fl_Terminal_clear_screen(self.inner.widget() as _, i32::from(arg1)) }
295    }
296
297    ///   Clear the terminal screen and home the cursor
298    ///
299    /// Also clears the current mouse selection.
300    ///
301    /// If `scroll_to_hist` is true, the screen is cleared by scrolling the
302    /// contents into the scrollback history, where it can be retrieved with the
303    /// scrollbar. If false, the screen is cleared
304    /// and the scrollback history is unchanged.
305    ///
306    /// Similar to the escape sequence `\<ESC\>[2J\<ESC\>[H`.
307    pub fn clear_screen_home(&mut self, arg1: bool) {
308        unsafe { Fl_Terminal_clear_screen_home(self.inner.widget() as _, i32::from(arg1)) }
309    }
310
311    /// Clears the scroll history buffer and adjusts scrollbar, forcing it to `redraw()`
312    pub fn clear_history(&mut self) {
313        unsafe { Fl_Terminal_clear_history(self.inner.widget() as _) }
314    }
315
316    /// Get the background color for the terminal's `Fl_Group::box()`.
317    pub fn color(&self) -> Color {
318        Color::from_rgbi(unsafe { Fl_Terminal_color(self.inner.widget() as _) })
319    }
320
321    /// Sets the background color for the terminal's `Fl_Group::box()`.
322    ///
323    /// If the `textbgcolor()` and `textbgcolor_default()` are set to the special
324    /// "see through" color 0xffffffff when any text was added, changing `color()`
325    /// affects the color that shows through behind that existing text.
326    ///
327    /// Otherwise, whatever specific background color was set for existing text will
328    ///  persist after changing `color()`.
329    ///
330    /// To see the effects of a change to `color()`, follow up with a call to `redraw()`.
331    ///
332    /// The default value is 0x0.
333    pub fn set_color(&mut self, color: Color) {
334        unsafe { Fl_Terminal_set_color(self.inner.widget() as _, color.bits()) }
335    }
336
337    /// Return the cursor's current column position on the screen.
338    pub fn cursor_col(&self) -> i32 {
339        unsafe { Fl_Terminal_cursor_col(self.inner.widget() as _) }
340    }
341
342    /// Set the cursor's current column position on the screen.
343    /// *This is a low-level "protected" function of the fltk library*
344    pub fn set_cursor_col(&mut self, val: i32) {
345        unsafe { Fl_Terminal_set_cursor_col(self.inner.widget() as _, val) }
346    }
347
348    /// Return the cursor's current row position on the screen.
349    pub fn cursor_row(&self) -> i32 {
350        unsafe { Fl_Terminal_cursor_row(self.inner.widget() as _) }
351    }
352
353    /// Set the cursor's current row position on the screen.
354    /// *This is a low-level "protected" function of the fltk library*
355    pub fn set_cursor_row(&mut self, val: i32) {
356        unsafe { Fl_Terminal_set_cursor_row(self.inner.widget() as _, val) }
357    }
358
359    /// Moves cursor up `count` lines.
360    ///  If cursor hits screen top, it either stops (does not wrap) if `do_scroll`
361    ///  is false, or scrolls down if `do_scroll` is true.
362    /// *This is a low-level "protected" function of the fltk library*
363    pub fn cursor_up(&mut self, count: i32, do_scroll: bool) {
364        unsafe { Fl_Terminal_cursor_up(self.inner.widget() as _, count, i32::from(do_scroll)) }
365    }
366
367    /// Moves cursor down `count` lines.
368    ///  If cursor hits screen bottom, it either stops (does not wrap) if `do_scroll`
369    ///  is false, or wraps and scrolls up if `do_scroll` is true.
370    /// *This is a low-level "protected" function of the fltk library*
371    pub fn cursor_down(&mut self, count: i32, do_scroll: bool) {
372        unsafe { Fl_Terminal_cursor_down(self.inner.widget() as _, count, i32::from(do_scroll)) }
373    }
374
375    /// Moves cursor left `count` columns, and cursor stops (does not wrap) if it hits screen edge.
376    /// *This is a low-level "protected" function of the fltk library*
377    pub fn cursor_left(&mut self, count: i32) {
378        unsafe { Fl_Terminal_cursor_left(self.inner.widget() as _, count) }
379    }
380
381    /// Moves cursor right `count` columns. If cursor hits right edge of screen,
382    ///  it either stops (does not wrap) if `do_scroll` is false, or wraps and
383    ///  scrolls up one line if `do_scroll` is true.
384    /// *This is a low-level "protected" function of the fltk library*
385    pub fn cursor_right(&mut self, count: i32, do_scroll: bool) {
386        unsafe { Fl_Terminal_cursor_right(self.inner.widget() as _, count, i32::from(do_scroll)) }
387    }
388
389    /// Scroll the selection up(+)/down(-) number of rows
390    /// *This is a low-level "protected" function of the fltk library*
391    pub fn scroll(&mut self, count: i32) {
392        unsafe { Fl_Terminal_scroll(self.inner.widget() as _, count) }
393    }
394
395    /// Clear from cursor to End Of Display (EOD), like "`<ESC>[J<ESC>[0J`".
396    pub fn clear_eod(&mut self) {
397        unsafe { Fl_Terminal_clear_eod(self.inner.widget() as _) }
398    }
399
400    /// Clear from cursor to End Of Line (EOL), like "`<ESC>[K`".
401    pub fn clear_eol(&mut self) {
402        unsafe { Fl_Terminal_clear_eol(self.inner.widget() as _) }
403    }
404
405    /// Clear entire line cursor is currently on.
406    pub fn clear_cur_line(&mut self) {
407        unsafe { Fl_Terminal_clear_cur_line(self.inner.widget() as _) }
408    }
409
410    /// Clear entire line for specified row.
411    pub fn clear_line(&mut self, drow: i32) {
412        unsafe { Fl_Terminal_clear_line(self.inner.widget() as _, drow) }
413    }
414
415    /// Clear from cursor to Start Of Display (EOD), like "`<ESC>[1J`".
416    pub fn clear_sod(&mut self) {
417        unsafe { Fl_Terminal_clear_sod(self.inner.widget() as _) }
418    }
419
420    /// Clear from cursor to Start Of Line (SOL), like "`<ESC>[1K`".
421    pub fn clear_sol(&mut self) {
422        unsafe { Fl_Terminal_clear_sol(self.inner.widget() as _) }
423    }
424
425    ///   Insert char `c` at the current cursor position for `rep` times.
426    ///   Works only for single-byte characters, `c` can't be multi-byte UTF-8.
427    ///   Does not wrap; characters at end of line are lost.
428    /// *This is a low-level "protected" function of the fltk library*
429    pub fn insert_char(&mut self, c: char, rep: i32) {
430        let c = if c.len_utf8() > 1 { b' ' } else { c as u8 };
431        unsafe { Fl_Terminal_insert_char(self.inner.widget() as _, c as c_char, rep) }
432    }
433
434    /// Insert char `c` for `rep` times at display row `drow` and column `dcol`.
435    ///   Works only for single-byte characters, `c` can't be multi-byte UTF-8.
436    ///   Does not wrap; characters at end of line are lost.
437    /// *This is a low-level "protected" function of the fltk library*
438    pub fn insert_char_eol(&mut self, c: char, drow: i32, dcol: i32, rep: i32) {
439        let c = if c.len_utf8() > 1 { b' ' } else { c as u8 };
440        unsafe {
441            Fl_Terminal_insert_char_eol(self.inner.widget() as _, c as c_char, drow, dcol, rep);
442        }
443    }
444
445    /// Insert `count` rows at current cursor position.
446    ///  Causes rows below to scroll down, and empty lines created.
447    ///  Lines deleted by scroll down are NOT moved into the scroll history.
448    /// *This is a low-level "protected" function of the fltk library*
449    pub fn insert_rows(&mut self, count: i32) {
450        unsafe { Fl_Terminal_insert_rows(self.inner.widget() as _, count) }
451    }
452
453    /// Delete char(s) at (`drow`,`dcol`) for `count` times.
454    pub fn delete_chars(&mut self, drow: i32, dcol: i32, count: i32) {
455        unsafe { Fl_Terminal_delete_chars(self.inner.widget() as _, drow, dcol, count) }
456    }
457
458    /// Delete char(s) at cursor position for `count` times.
459    pub fn delete_cur_chars(&mut self, count: i32) {
460        unsafe { Fl_Terminal_delete_cur_chars(self.inner.widget() as _, count) }
461    }
462
463    ///  Delete `count` rows at cursor position.
464    ///   Causes rows to scroll up, and empty lines created at bottom of screen.
465    ///    Lines deleted by scroll up are NOT moved into the scroll history.
466    /// *This is a low-level "protected" function of the fltk library*
467    pub fn delete_rows(&mut self, count: i32) {
468        unsafe { Fl_Terminal_delete_rows(self.inner.widget() as _, count) }
469    }
470
471    /// Get the cursor's background color used for the cursor itself.
472    pub fn cursor_bg_color(&self) -> Color {
473        Color::from_rgbi(unsafe { Fl_Terminal_cursor_bg_color(self.inner.widget() as _) })
474    }
475
476    /// Set the cursor's background color used for the cursor itself.
477    pub fn set_cursor_bg_color(&mut self, color: Color) {
478        unsafe { Fl_Terminal_set_cursor_bg_color(self.inner.widget() as _, color.bits()) }
479    }
480
481    /// Get the cursor's foreground color used for the cursor itself.
482    pub fn cursor_fg_color(&self) -> Color {
483        Color::from_rgbi(unsafe { Fl_Terminal_cursor_fg_color(self.inner.widget() as _) })
484    }
485
486    /// Set the cursor's foreground color used for the cursor itself.
487    pub fn set_cursor_fg_color(&mut self, color: Color) {
488        unsafe { Fl_Terminal_set_cursor_fg_color(self.inner.widget() as _, color.bits()) }
489    }
490
491    /// Get the current mouse selection. Returns `None` if no selection, or `Some([srow, scol, erow, ecol])` if there is a selection,
492    ///   where row and col represent start/end positions in the ring buffer.
493    /// *This is a low-level "protected" function of the fltk library*
494    pub fn get_selection(&self) -> Option<[i32; 4]> {
495        let mut retval: [i32; 4] = [0; 4];
496        let ret =
497            unsafe { Fl_Terminal_get_selection(self.inner.widget() as _, retval.as_mut_ptr()) };
498        if ret != 0 { Some(retval) } else { None }
499    }
500
501    /// Move cursor to the home position (top/left).
502    pub fn cursor_home(&mut self) {
503        unsafe { Fl_Terminal_cursor_home(self.inner.widget() as _) }
504    }
505
506    /// Return terminal's display width in columns of text characters.
507    pub fn display_columns(&self) -> i32 {
508        unsafe { Fl_Terminal_display_columns(self.inner.widget() as _) }
509    }
510
511    /// Set terminal's display width in columns of text characters.
512    /// Does not resize the terminal.
513    pub fn set_display_columns(&mut self, val: i32) {
514        unsafe { Fl_Terminal_set_display_columns(self.inner.widget() as _, val) }
515    }
516
517    /// Return terminal's display height in lines of text.
518    pub fn display_rows(&self) -> i32 {
519        unsafe { Fl_Terminal_display_rows(self.inner.widget() as _) }
520    }
521
522    /// Sets the terminal's scrollback history buffer size in lines of text (rows).
523    pub fn set_history_rows(&mut self, arg1: i32) {
524        unsafe { Fl_Terminal_set_history_rows(self.inner.widget() as _, arg1) }
525    }
526
527    /// Gets the terminal's scrollback history buffer size in lines of text (rows).
528    pub fn history_rows(&self) -> i32 {
529        unsafe { Fl_Terminal_history_rows(self.inner.widget() as _) }
530    }
531
532    /// Returns how many lines are "in use" by the screen history buffer.
533    pub fn history_use(&self) -> i32 {
534        unsafe { Fl_Terminal_history_use(self.inner.widget() as _) }
535    }
536
537    /// Set the bottom margin
538    pub fn set_margin_bottom(&mut self, arg1: i32) {
539        unsafe { Fl_Terminal_set_margin_bottom(self.inner.widget() as _, arg1) }
540    }
541
542    /// Return the bottom margin
543    pub fn margin_bottom(&self) -> i32 {
544        unsafe { Fl_Terminal_margin_bottom(self.inner.widget() as _) }
545    }
546
547    /// Set the left margin
548    pub fn set_margin_left(&mut self, arg1: i32) {
549        unsafe { Fl_Terminal_set_margin_left(self.inner.widget() as _, arg1) }
550    }
551
552    /// Return the left margin
553    pub fn margin_left(&self) -> i32 {
554        unsafe { Fl_Terminal_margin_left(self.inner.widget() as _) }
555    }
556
557    /// Set the right margin
558    pub fn set_margin_right(&mut self, arg1: i32) {
559        unsafe { Fl_Terminal_set_margin_right(self.inner.widget() as _, arg1) }
560    }
561
562    /// Return the right margin
563    pub fn margin_right(&self) -> i32 {
564        unsafe { Fl_Terminal_margin_right(self.inner.widget() as _) }
565    }
566
567    /// Set the top margin
568    pub fn set_margin_top(&mut self, arg1: i32) {
569        unsafe { Fl_Terminal_set_margin_top(self.inner.widget() as _, arg1) }
570    }
571
572    /// Return the top margin
573    pub fn margin_top(&self) -> i32 {
574        unsafe { Fl_Terminal_margin_top(self.inner.widget() as _) }
575    }
576
577    /// Given a height in pixels, return number of rows that "fits" into that area.
578    /// *This is a low-level "protected" function of the fltk library*
579    pub fn h_to_row(&self, pix: i32) -> i32 {
580        unsafe { Fl_Terminal_h_to_row(self.inner.widget() as _, pix) }
581    }
582
583    /// Given a width in pixels, return number of columns that "fits" into that area.
584    /// *This is a low-level "protected" function of the fltk library*
585    pub fn w_to_col(&self, pix: i32) -> i32 {
586        unsafe { Fl_Terminal_w_to_col(self.inner.widget() as _, pix) }
587    }
588
589    /// Sets the combined output translation flags to `val`.
590    ///
591    /// `val` can be sensible combinations of the `OutFlags` bit flags.
592    ///
593    /// The default is `LF_TO_CRLF`, so that \\n will generate both carriage-return (CR)
594    /// and line-feed (LF).
595    ///
596    /// For \\r and \\n to be handled literally, use `output_translate(Terminal::OutFlags::OFF)`;
597    /// To disable all output translations, use 0 or `Terminal::OutFlags::OFF`.
598    pub fn set_output_translate(&mut self, val: OutFlags) {
599        unsafe { Fl_Terminal_set_output_translate(self.inner.widget() as _, u32::from(val.bits())) }
600    }
601
602    /// Return the current combined output translation flags.
603    pub fn output_translate(&self) -> OutFlags {
604        let result = unsafe { Fl_Terminal_output_translate(self.inner.widget() as _) as i32 };
605        OutFlags::from_bits(result as u8)
606            .unwrap_or_else(|| panic!("Unknown OutFlags value {result} from output_translate"))
607    }
608
609    /// Prints single ASCII char `c` at current cursor position, and advances the cursor.
610    /// - `c` must be ASCII, not utf-8
611    /// - Does not trigger redraws
612    pub fn print_char(&mut self, c: char) {
613        unsafe { Fl_Terminal_print_char(self.inner.widget() as _, c as std::os::raw::c_char) }
614    }
615
616    ///   Prints single UTF-8 char `c` at current cursor position, and advances the cursor if the character
617    ///   is printable. Handles ASCII and control codes (CR, LF, etc).
618    ///
619    ///  The character is displayed at the current cursor position
620    ///  using the current text color/attributes.
621    ///
622    /// Handles control codes and can be used to construct ANSI/XTERM escape sequences.
623    /// - `c` must be a single char only (whether UTF-8 or ASCII)
624    /// - `c` can be an ASCII character, though not as efficent as `print_char()`
625    /// - Invalid UTF-8 chars show the error character (¿) depending on `show_unknown(bool)`.
626    /// - Does not trigger redraws
627    pub fn print_char_utf8(&mut self, c: char) {
628        let txt = c.to_string();
629        unsafe {
630            Fl_Terminal_print_char_utf8(
631                self.inner.widget() as _,
632                txt.as_ptr() as _,
633                txt.len() as _,
634            );
635        }
636    }
637
638    /// Print the ASCII character `c` at the terminal's display position `(drow,dcol)`.
639    ///   The character MUST be printable (in range 0x20 - 0x7e), and is displayed
640    ///   using the current text color/attributes. Characters outside that range are either
641    ///   ignored or print the error character (¿), depending on `show_unknown(bool)`.
642    ///
643    /// No range checking is done on drow,dcol:
644    /// - drow must be in range `0..(display_rows()-1)`
645    /// - dcol must be in range `0..(display_columns()-1)`
646    /// - Does not trigger redraws
647    /// - Does NOT handle control codes, ANSI or XTERM escape sequences.
648    pub fn plot_char(&mut self, c: char, row: i32, col: i32) {
649        unsafe {
650            Fl_Terminal_plot_char(
651                self.inner.widget() as _,
652                c as std::os::raw::c_char,
653                row,
654                col,
655            );
656        }
657    }
658
659    /// Print a single UTF-8 character len at display position `(drow,dcol)`.
660    /// The character is displayed using the current text color/attributes.
661    ///
662    /// This is a very low level method.
663    /// No range checking is done on drow,dcol:
664    /// -  drow must be in range `0..(display_rows()-1)`
665    /// -  dcol must be in range `0..(display_columns()-1)`
666    /// - Does not trigger redraws
667    /// - Does not handle ANSI or XTERM escape sequences
668    /// - Invalid UTF-8 chars show the error character (¿) depending on `show_unknown(bool)`.
669    pub fn plot_char_utf8(&mut self, c: char, drow: i32, dcol: i32) {
670        let txt = c.to_string();
671        unsafe {
672            Fl_Terminal_plot_char_utf8(
673                self.inner.widget() as _,
674                txt.as_ptr() as _,
675                txt.len() as _,
676                drow,
677                dcol,
678            );
679        }
680    }
681
682    /// Set the maximum rate redraw speed in floating point seconds if `redraw_style()` is set to `RATE_LIMITED`.
683    pub fn set_redraw_rate(&mut self, set: f32) {
684        unsafe { Fl_Terminal_set_redraw_rate(self.inner.widget() as _, set) }
685    }
686
687    /// Get max rate redraw speed in floating point seconds.
688    pub fn redraw_rate(&self) -> f32 {
689        unsafe { Fl_Terminal_redraw_rate(self.inner.widget() as _) }
690    }
691
692    /// Set how Terminal manages screen redrawing.
693    pub fn set_redraw_style(&mut self, set: RedrawStyle) {
694        unsafe { Fl_Terminal_set_redraw_style(self.inner.widget() as _, set.bits() as i32) }
695    }
696
697    /// Get the redraw style.
698    pub fn redraw_style(&self) -> RedrawStyle {
699        let result = unsafe { Fl_Terminal_redraw_style(self.inner.widget() as _) as u32 };
700        RedrawStyle::new(result) // Construct a style with the given value
701    }
702
703    /// Resets terminal to default colors, clears screen, history and mouse selection, homes cursor, resets tabstops.
704    pub fn reset_terminal(&mut self) {
705        unsafe { Fl_Terminal_reset_terminal(self.inner.widget() as _) }
706    }
707
708    /// Returns the scrollbar's actual "trough size", which is the width of `FL_VERTICAL`
709    /// scrollbars, or height of `FL_HORIZONTAL` scrollbars.
710    ///
711    /// If `scrollbar_size()` is zero (default), then the value of the global `Fl::scrollbar_size()`
712    /// is returned, which is the default global scrollbar size for the entire application.
713    pub fn scrollbar_actual_size(&self) -> i32 {
714        unsafe { Fl_Terminal_scrollbar_actual_size(self.inner.widget() as _) }
715    }
716
717    ///   Get current pixel size of all the scrollbar's troughs for this widget,
718    ///   or zero if the global `Fl::scrollbar_size()` is being used (default).
719    ///
720    ///   If this value returns *zero*, this widget's scrollbars are using the
721    ///   global `Fl::scrollbar_size()`, in which case use `scrollbar_actual_size()`
722    ///   to get the actual (effective) pixel scrollbar size being used.
723    ///
724    ///   __returns__ Scrollbar trough size in pixels, or 0 if the global `Fl::scrollbar_size()` is being used.
725    pub fn scrollbar_size(&self) -> i32 {
726        unsafe { Fl_Terminal_scrollbar_size(self.inner.widget() as _) }
727    }
728
729    /// Set the width of the both horizontal and vertical scrollbar's trough to `val`, in pixels.
730    /// If this value is zero (default), this widget will use fltk's master `scrollbar_size()` value
731    pub fn set_scrollbar_size(&mut self, val: i32) {
732        unsafe { Fl_Terminal_set_scrollbar_size(self.inner.widget() as _, val) }
733    }
734
735    /// Get mouse selection background color.
736    pub fn selection_bg_color(&self) -> Color {
737        Color::from_rgbi(unsafe { Fl_Terminal_selection_bg_color(self.inner.widget() as _) })
738    }
739
740    /// Returns the vertical scrollbar
741    pub fn scrollbar(&self) -> crate::valuator::Scrollbar {
742        unsafe {
743            let ptr = Fl_Terminal_scrollbar(self.inner.widget() as _);
744            assert!(!ptr.is_null());
745            crate::valuator::Scrollbar::from_widget_ptr(ptr as *mut fltk_sys::widget::Fl_Widget)
746        }
747    }
748
749    /// Returns the horizontal scrollbar
750    pub fn hscrollbar(&self) -> crate::valuator::Scrollbar {
751        unsafe {
752            let ptr = Fl_Terminal_hscrollbar(self.inner.widget() as _);
753            assert!(!ptr.is_null());
754            crate::valuator::Scrollbar::from_widget_ptr(ptr as *mut fltk_sys::widget::Fl_Widget)
755        }
756    }
757
758    /// Get the horizontal scrollbar behavior style.
759    ///
760    ///  This determines when the scrollbar is visible.
761    ///
762    /// Value will be one of the `Fl_Terminal::HScrollbarStyle` enum values.
763    pub fn hscrollbar_style(&self) -> ScrollbarStyle {
764        unsafe { ScrollbarStyle::new(Fl_Terminal_hscrollbar_style(self.inner.widget() as _)) }
765    }
766
767    ///   Set the scrollbar behavior style.
768    ///
769    ///  This determines when the scrollbar is visible.
770    ///
771    ///  |   `ScrollbarStyle` enum    | Description                                           |
772    ///  |---------------------------|-------------------------------------------------------|
773    ///  |   ON                      | Scrollbar is always displayed.             |
774    ///  |   OFF                     | Scrollbar is never displayed.              |
775    ///  |   AUTO                    | Scrollbar is displayed whenever the widget has been resized so that some of the text is hidden. |
776    ///
777    ///  The default style is AUTO
778    pub fn set_hscrollbar_style(&mut self, val: ScrollbarStyle) {
779        unsafe { Fl_Terminal_set_hscrollbar_style(self.inner.widget() as _, val.bits()) }
780    }
781
782    /// Set mouse selection background color.
783    pub fn set_selection_bg_color(&mut self, color: Color) {
784        unsafe { Fl_Terminal_set_selection_bg_color(self.inner.widget() as _, color.bits()) }
785    }
786
787    /// Get mouse selection foreground color.
788    pub fn selection_fg_color(&self) -> Color {
789        Color::from_rgbi(unsafe { Fl_Terminal_selection_fg_color(self.inner.widget() as _) })
790    }
791
792    /// Set mouse selection foreground color.
793    pub fn set_selection_fg_color(&mut self, color: Color) {
794        unsafe { Fl_Terminal_set_selection_fg_color(self.inner.widget() as _, color.bits()) }
795    }
796
797    /// Return the "show unknown" flag. if true, show unknown chars as '¿'
798    pub fn show_unknown(&self) -> bool {
799        unsafe { Fl_Terminal_show_unknown(self.inner.widget() as _) != 0 }
800    }
801
802    /// Set the "show unknown" flag. if true, show unknown chars as '¿' (default off)
803    pub fn set_show_unknown(&mut self, arg1: bool) {
804        unsafe { Fl_Terminal_set_show_unknown(self.inner.widget() as _, i32::from(arg1)) }
805    }
806
807    /// Return the text attribute bits (underline, inverse, etc) for subsequent appends.
808    pub fn text_attrib(&self) -> Attrib {
809        // Attrib::from_bits( unsafe { Fl_Terminal_text_attrib(self.inner.widget()) as _ } ).unwrap()
810        let result = unsafe { Fl_Terminal_text_attrib(self.inner.widget() as _) };
811        Attrib::from_bits(result).unwrap_or_else(|| panic!("Unknown Attrib value {result}"))
812    }
813
814    /// Set text attribute bits (underline, inverse, etc) for subsequent appends.
815    pub fn set_text_attrib(&mut self, arg1: Attrib) {
816        unsafe { Fl_Terminal_set_text_attrib(self.inner.widget() as _, arg1.bits()) }
817    }
818
819    /// Set text background color to fltk color val.
820    /// Use this for temporary color changes, similar to \<ESC\>[48;2;{R};{G};{B}m
821    ///
822    /// This setting does not affect the 'default' text colors used by \<ESC\>[0m, \<ESC\>c, `reset_terminal()`, etc.
823    /// To change both the current and default bg color, also use `text_bg_color_default(Fl_Color)`.
824    pub fn set_text_bg_color(&mut self, color: Color) {
825        unsafe { Fl_Terminal_set_text_bg_color(self.inner.widget() as _, color.bits()) }
826    }
827
828    /// Get the text background color.
829    pub fn text_bg_color(&self) -> Color {
830        Color::from_rgbi(unsafe { Fl_Terminal_text_bg_color(self.inner.widget() as _) })
831    }
832
833    /// Set the default text background color used by \<ESC\>c, \<ESC\>[0m, and `reset_terminal()`.
834    /// Does not affect the 'current' text fg color; use `set_text_bg_color(Fl_Color)` to set that.
835    pub fn set_text_bg_color_default(&mut self, color: Color) {
836        unsafe { Fl_Terminal_set_text_bg_color_default(self.inner.widget() as _, color.bits()) }
837    }
838
839    /// Return the default text background color.
840    pub fn text_bg_color_default(&self) -> Color {
841        Color::from_rgbi(unsafe { Fl_Terminal_text_bg_color_default(self.inner.widget() as _) })
842    }
843
844    /// Sets the background text color as one of the 8 'xterm color' values.
845    ///
846    /// This will be the background color used for all newly printed text, similar to the \<ESC\>[#m escape sequence, where # is between 40 and 47.
847    ///
848    /// This color will be reset to the default bg color if `reset_terminal()` is called, or by \<ESC\>c, \<ESC\>[0m, etc.
849    ///
850    /// The xterm color intensity values can be influenced by the Dim/Bold/Normal modes (which can be set with e.g. \<ESC\>[1m, `textattrib()`, etc), so the actual RGB values of these colors allow room for Dim/Bold to influence their brightness. For instance, "Normal Red" is not full brightness to allow "Bold Red" to be brighter. This goes for all colors except 'Black', which is not influenced by Dim or Bold; Black is always Black.
851    ///
852    /// These background colors are slightly dimmer than the corresponding xterm foregroumd colors.
853    ///
854    /// The 8 color xterm values are:
855    /// 0 = Black, 1 = Red, 2 = Green, 3 = Yellow, 4 = Blue,5 = Magenta, 6 = Cyan, 7 = White
856    pub fn set_text_bg_color_xterm(&mut self, color: XtermColor) {
857        unsafe { Fl_Terminal_set_text_bg_color_xterm(self.inner.widget() as _, color as u8) }
858    }
859    ///  Set the text color for the terminal.
860    ///  This is a convenience method that sets *both* `textfgcolor()` and `textfgcolor_default()`,
861    ///  ensuring both are set to the same value.
862    pub fn set_text_color(&mut self, color: Color) {
863        unsafe { Fl_Terminal_set_text_color(self.inner.widget() as _, color.bits()) }
864    }
865    /// Set text foreground drawing color to fltk color val.
866    /// Use this for temporary color changes, similar to \<ESC\>[38;2;{R};{G};{B}m
867    ///
868    /// This setting does not affect the 'default' text colors used by \<ESC\>[0m, \<ESC\>c, `reset_terminal()`, etc.
869    /// To change both the current and default fg color, also use `textfgcolor_default(Fl_Color)`
870    pub fn set_text_fg_color(&mut self, color: Color) {
871        unsafe { Fl_Terminal_set_text_fg_color(self.inner.widget() as _, color.bits()) }
872    }
873
874    /// Get the text foreground color.
875    pub fn text_fg_color(&self) -> Color {
876        Color::from_rgbi(unsafe { Fl_Terminal_text_fg_color(self.inner.widget() as _) })
877    }
878
879    /// Set the default text foreground color used by \<ESC\>c, \<ESC\>[0m, and `reset_terminal()`.
880    /// Does not affect the 'current' text fg color; use `set_text_fg_color(Fl_Color)` to set that.
881    pub fn set_text_fg_color_default(&mut self, color: Color) {
882        unsafe { Fl_Terminal_set_text_fg_color_default(self.inner.widget() as _, color.bits()) }
883    }
884
885    /// Return the default text foreground color.
886    pub fn text_fg_color_default(&self) -> Color {
887        Color::from_rgbi(unsafe { Fl_Terminal_text_fg_color_default(self.inner.widget() as _) })
888    }
889
890    /// Sets the foreground text color as one of the 8 'xterm color' values.
891    ///
892    /// This will be the foreground color used for all newly printed text, similar to the \<ESC\>[#m escape sequence, where # is between 30 and 37.
893    ///
894    /// This color will be reset to the default bg color if `reset_terminal()` is called, or by \<ESC\>c, \<ESC\>[0m, etc.
895    ///
896    /// The xterm color intensity values can be influenced by the Dim/Bold/Normal modes (which can be set with e.g. \<ESC\>[1m, `textattrib()`, etc), so the actual RGB values of these colors allow room for Dim/Bold to influence their brightness. For instance, "Normal Red" is not full brightness to allow "Bold Red" to be brighter. This goes for all colors except 'Black', which is not influenced by Dim or Bold; Black is always Black.
897    ///
898    /// The 8 color xterm values are:
899    /// 0 = Black, 1 = Red, 2 = Green, 3 = Yellow, 4 = Blue,5 = Magenta, 6 = Cyan, 7 = White
900    pub fn set_text_fg_color_xterm(&mut self, color: XtermColor) {
901        unsafe { Fl_Terminal_set_text_fg_color_xterm(self.inner.widget() as _, color as u8) }
902    }
903
904    /// Get the text font
905    pub fn text_font(&self) -> Font {
906        Font::by_index(unsafe { Fl_Terminal_text_font(self.inner.widget() as _) } as usize)
907    }
908
909    /// Sets the font used for all text displayed in the terminal.
910    /// This affects all existing text (in display and history) as well as any newly printed text.
911    /// Only monospace fonts are recommended.
912    pub fn set_text_font(&mut self, font: Font) {
913        unsafe { Fl_Terminal_set_text_font(self.inner.widget() as _, font.bits()) }
914    }
915
916    /// Return text font size used to draw all text in the terminal.
917    pub fn text_size(&self) -> i32 {
918        unsafe { Fl_Terminal_text_size(self.inner.widget() as _) }
919    }
920
921    /// Sets the font size used for all text displayed in the terminal.
922    /// This affects all existing text (in display and history) as well as any newly printed text.
923    /// Changing this will affect the `display_rows()` and `display_columns()`.
924    pub fn set_text_size(&mut self, val: i32) {
925        unsafe { Fl_Terminal_set_text_size(self.inner.widget() as _, val) }
926    }
927
928    /// Return a string copy of all lines in the terminal (including history).
929    ///
930    /// If `lines_below_cursor` is false, lines below the cursor on down
931    /// to the bottom of the display are ignored, and not included in the returned string.
932    ///
933    ///  If `lines_below_cursor` is true, then all lines in the display are returned
934    ///  including any below the cursor, even if all are blank.
935    ///
936    ///  Example use:
937    ///  ```
938    ///      use fltk::{prelude::*, terminal::Terminal};
939    ///      let mut tty = Terminal::new(0, 0, 400, 300, None);
940    ///      
941    ///      let s = tty.text(true);   // get a copy of the terminal's contents
942    ///      println!("Terminal's contents:\n{}", s);
943    ///  ```
944    pub fn text(&self, lines_below_cursor: bool) -> String {
945        unsafe {
946            let ptr = Fl_Terminal_text(self.inner.widget() as _, i32::from(lines_below_cursor));
947            assert!(!ptr.is_null()); // Sanity check
948            let result = CStr::from_ptr(ptr).to_string_lossy().to_string().clone();
949            Fl_free_str(ptr);
950            result
951        }
952    }
953
954    /// Return text selection (for `copy()/paste()` operations)
955    pub fn selection_text(&self) -> Option<String> {
956        assert!(self.is_derived);
957        unsafe {
958            let ptr = Fl_Terminal_selection_text(self.inner.widget() as _);
959            if ptr.is_null() {
960                None
961            } else {
962                let result = CStr::from_ptr(ptr).to_string_lossy().to_string();
963                Fl_free_str(ptr);
964                Some(result)
965            }
966        }
967    }
968
969    ///  Return byte length of all UTF-8 chars in selection, or 0 if no selection.
970    ///  NOTE: Length includes trailing white on each line.
971    pub fn selection_text_len(&self) -> i32 {
972        unsafe { Fl_Terminal_selection_text_len(self.inner.widget() as _) }
973    }
974
975    // Various methods to access the ring buffer
976
977    ///  Return the ending row# in the display area.
978    pub fn disp_erow(&self) -> i32 {
979        unsafe { Fl_Terminal_disp_erow(self.inner.widget() as _) }
980    }
981
982    /// Return the starting row# in the display area.
983    pub fn disp_srow(&self) -> i32 {
984        unsafe { Fl_Terminal_disp_srow(self.inner.widget() as _) }
985    }
986
987    /// Return the ending row# of the scrollback history.
988    pub fn hist_erow(&self) -> i32 {
989        unsafe { Fl_Terminal_hist_erow(self.inner.widget() as _) }
990    }
991
992    /// Return the starting row# of the scrollback history.
993    pub fn hist_srow(&self) -> i32 {
994        unsafe { Fl_Terminal_hist_srow(self.inner.widget() as _) }
995    }
996
997    /// Return number of rows in use by the scrollback history.
998    pub fn hist_use(&self) -> i32 {
999        unsafe { Fl_Terminal_hist_use(self.inner.widget() as _) }
1000    }
1001
1002    /// Return the starting row of the \"in use\" scrollback history.
1003    pub fn hist_use_srow(&self) -> i32 {
1004        unsafe { Fl_Terminal_hist_use_srow(self.inner.widget() as _) }
1005    }
1006
1007    /// Is global row/column inside the current mouse selection?
1008    /// *This is a low-level "protected" function of the fltk library*
1009    pub fn is_inside_selection(&self, row: i32, col: i32) -> bool {
1010        unsafe { Fl_Terminal_is_inside_selection(self.inner.widget() as _, row, col) != 0 }
1011    }
1012
1013    /// Returns true if there's a mouse selection.
1014    pub fn is_selection(&self) -> bool {
1015        unsafe { Fl_Terminal_is_selection(self.inner.widget() as _) != 0 }
1016    }
1017
1018    /// Returns the current offset into the ring buffer.
1019    pub fn offset(&self) -> i32 {
1020        unsafe { Fl_Terminal_offset(self.inner.widget() as _) }
1021    }
1022
1023    /// Return the ending row# in the ring buffer (Always ring_rows()-1)
1024    pub fn ring_erow(&self) -> i32 {
1025        unsafe { Fl_Terminal_ring_erow(self.inner.widget() as _) }
1026    }
1027
1028    /// Return the starting row# in the ring buffer (Always 0)
1029    pub fn ring_srow(&self) -> i32 {
1030        unsafe { Fl_Terminal_ring_srow(self.inner.widget() as _) }
1031    }
1032
1033    /// Return the number of rows in the ring buffer.
1034    pub fn ring_rows(&self) -> i32 {
1035        unsafe { Fl_Terminal_ring_rows(self.inner.widget() as _) }
1036    }
1037
1038    /// Return the `Utf8Char` for character under cursor.
1039    pub fn u8c_cursor(&self) -> Utf8Char {
1040        unsafe {
1041            let x = self.inner.widget();
1042            let utf8_p = Fl_Terminal_u8c_cursor(x as _);
1043            Utf8Char { inner: utf8_p }
1044        }
1045    }
1046
1047    /// Return u8c for beginning of row drow of the display.
1048    /// *This is a low-level "protected" function of the fltk library*
1049    pub fn u8c_disp_row(&self, drow: i32) -> BuffRow {
1050        // Fl_Terminal_u8c_disp_row returns pointer to the first C++ Utf8Char object,
1051        //  which becomes the `inner` element in the Rust BuffRow object
1052        let row_p = unsafe { Fl_Terminal_u8c_disp_row(self.inner.widget() as _, drow) };
1053        BuffRow::new(row_p, self)
1054    }
1055
1056    /// Return u8c for beginning of row hrow inside the scrollback history.
1057    /// *This is a low-level "protected" function of the fltk library*
1058    pub fn u8c_hist_row(&self, hrow: i32) -> BuffRow {
1059        // Fl_Terminal_u8c_hist_row returns pointer to the first C++ Utf8Char object,
1060        //  which becomes the `inner` element in the Rust BuffRow object
1061        let row_p = unsafe { Fl_Terminal_u8c_hist_row(self.inner.widget() as _, hrow) };
1062        BuffRow::new(row_p, self)
1063    }
1064
1065    /// Return u8c for beginning of row hurow inside the 'in use' part of the\n scrollback history.
1066    /// *This is a low-level "protected" function of the fltk library*
1067    pub fn u8c_hist_use_row(&self, hurow: i32) -> BuffRow {
1068        // Fl_Terminal_u8c_hist_use_row returns pointer to the first  C++ Utf8Char object,
1069        //  which becomes the `inner` element in the Rust BuffRow object
1070        let row_p = unsafe { Fl_Terminal_u8c_hist_use_row(self.inner.widget() as _, hurow) };
1071        BuffRow::new(row_p, self)
1072    }
1073
1074    /// Return u8c for beginning of row grow in the ring buffer.
1075    /// *This is a low-level "protected" function of the fltk library*
1076    pub fn u8c_ring_row(&self, grow: i32) -> BuffRow {
1077        // Fl_Terminal_u8c_ring_use_row returns pointer to the first  C++ Utf8Char object,
1078        //  which becomes the `inner` element in the Rust BuffRow object
1079        let row_p = unsafe { Fl_Terminal_u8c_ring_row(self.inner.widget() as _, grow) };
1080        BuffRow::new(row_p, self)
1081    }
1082}
1083
1084// So far only implementing "getter" methods. Todo: methods to modify Utf8Char
1085impl Utf8Char {
1086    /// Construct a new `Utf8Char`, single-byte only. This is really only useful for testing.
1087    ///  'c' must be "printable" ASCII in the range (0x20 <= c <= 0x7e).
1088    ///     Anything outside of that is silently ignored.
1089    ///
1090    /// Allocated `Utf8Char` will never be deleted.
1091    pub fn new(c: u8) -> Self {
1092        unsafe {
1093            let u8c = Fl_Terminal_Utf8Char_new_obj(c);
1094            Utf8Char { inner: u8c }
1095        }
1096    }
1097
1098    /// Return the actual displayed color of char `u8c` possibly influenced by BOLD or DIM if the char is from Xterm.
1099    ///    BG color will be derived from the widget color if a widget is specified and the color is `TransparentBg`,
1100    ///    and that won't be influenced by charflag attributes.
1101    pub fn attr_bgcolor(&self, term: Option<&Terminal>) -> Color {
1102        Color::from_rgbi(match term {
1103            None => unsafe { Fl_Terminal_Utf8Char_attr_bgcolor(self.inner, std::ptr::null()) },
1104            Some(t) => unsafe {
1105                Fl_Terminal_Utf8Char_attr_bgcolor(self.inner, t.inner.widget() as _)
1106            },
1107        })
1108    }
1109
1110    // /// Return the actual displayed color of char `u8c` possibly influenced by BOLD or DIM if the char is from Xterm.
1111    // ///    If a `grp` widget is specified (i.e. not `None`), don't let the color be
1112    // ///    influenced by the attribute bits *if* it matches the `grp` widget's own `color()`.
1113    // pub fn attr_color(&self, grp: Option<*const Fl_Widget>) -> Color {
1114    //     Color::from_rgbi(match grp {
1115    //         None => unsafe { Fl_Terminal_Utf8Char_attr_color(self.inner, std::ptr::null()) },
1116    //         Some(g) => unsafe { Fl_Terminal_Utf8Char_attr_color(self.inner, g) },
1117    //     })
1118    // }
1119
1120    /// Return the actual displayed fg color of char `u8c` possibly influenced by BOLD or DIM if the char is from Xterm.
1121    ///    If a `term` widget is specified (i.e. not `None`), don't let the color be
1122    ///    influenced by the attribute bits *if* it matches the `term` widget's own `color()`.
1123    pub fn attr_fgcolor(&self, term: Option<&Terminal>) -> Color {
1124        Color::from_rgbi(match term {
1125            None => unsafe { Fl_Terminal_Utf8Char_attr_fgcolor(self.inner, std::ptr::null()) },
1126            Some(t) => unsafe {
1127                Fl_Terminal_Utf8Char_attr_fgcolor(self.inner, t.inner.widget() as _)
1128            },
1129        })
1130    }
1131
1132    /// Return the attributes for this character.
1133    pub fn attrib(&self) -> Attrib {
1134        let result = unsafe { Fl_Terminal_Utf8Char_attrib(self.inner) };
1135        Attrib::from_bits(result).unwrap_or_else(|| panic!("Unknown Attrib value {result}"))
1136    }
1137
1138    /// Return the background color for this character.
1139    pub fn bgcolor(&self) -> Color {
1140        Color::from_rgbi(unsafe { Fl_Terminal_Utf8Char_bgcolor(self.inner) })
1141    }
1142
1143    /// Return the foreground color for this character.
1144    pub fn fgcolor(&self) -> Color {
1145        let result = unsafe { Fl_Terminal_Utf8Char_fgcolor(self.inner) };
1146        Color::from_rgbi(result)
1147    }
1148
1149    /// Return the xterm `CharFlags` bits
1150    pub fn charflags(&self) -> CharFlags {
1151        let result = unsafe { i32::from(Fl_Terminal_Utf8Char_charflags(self.inner)) };
1152        CharFlags::from_bits(result as u8)
1153            .unwrap_or_else(|| panic!("Unknown CharFlags value {result}"))
1154    }
1155
1156    /// Returns true if the character text in this struct matches the given ASCII character
1157    pub fn is_char(&self, c: u8) -> bool {
1158        let result = unsafe { Fl_Terminal_Utf8Char_is_char(self.inner, c as c_char) as i32 };
1159        result != 0
1160    }
1161
1162    /// Return the length of this character in bytes (UTF-8 can be multibyte)
1163    pub fn length(&self) -> usize {
1164        unsafe { Fl_Terminal_Utf8Char_length(self.inner) as usize }
1165    }
1166
1167    /// Return the maximum length in bytes of a UTF-8 character
1168    pub fn max_utf8(&self) -> usize {
1169        unsafe { Fl_Terminal_Utf8Char_max_utf8(self.inner) as usize }
1170    }
1171
1172    /// Return the width of this character in floating point pixels.
1173    ///
1174    ///    WARNING: Uses current font, so assumes font and `font_size`
1175    ///             have already been set to current font!
1176    pub fn pwidth(&self) -> f64 {
1177        unsafe { Fl_Terminal_Utf8Char_pwidth(self.inner) as f64 }
1178    }
1179
1180    /// Return the width of this character in integer pixels.
1181    ///
1182    ///    WARNING: Uses current font, so assumes font and `font_size`
1183    ///             have already been set to current font!
1184    pub fn pwidth_int(&self) -> usize {
1185        unsafe { Fl_Terminal_Utf8Char_pwidth_int(self.inner) as usize }
1186    }
1187
1188    /// Return the UTF-8 text string for this character.
1189    pub fn text_utf8(&self) -> &[u8] {
1190        unsafe {
1191            let ptr = Fl_Terminal_Utf8Char_text_utf8(self.inner);
1192            let len = Fl_Terminal_Utf8Char_length(self.inner);
1193            std::slice::from_raw_parts(ptr, len as usize)
1194        }
1195    }
1196
1197    // Note: Fl_Terminal_Utf8Char_size() is used internally but not exposed to user Rust programs
1198}
1199
1200impl<'a> BuffRow<'a> {
1201    /// Generate a new `BuffRow` object based on a pointer from C++ `Fl_Terminal`
1202    pub fn new(ptr: *const Fl_Terminal_Utf8Char, parent: &'a Terminal) -> Self {
1203        unsafe {
1204            BuffRow {
1205                // inner is the pointer to the first C++ Utf8Char in the row
1206                inner: ptr,
1207                _parent: parent,
1208                // length: (i + 1) as usize,
1209                length: parent.display_columns() as usize,
1210                char_size: Fl_Terminal_Utf8Char_size() as usize,
1211            }
1212        }
1213    }
1214
1215    /// Trim trailing blanks off of `BuffRow` object.
1216    /// Does not affect the data in the `RingBuff`, just this object's access.
1217    #[must_use]
1218    pub fn trim(mut self) -> Self {
1219        unsafe {
1220            let mut last_char = self.inner.add((self.length - 1) * self.char_size);
1221            let c = Utf8Char { inner: last_char };
1222            // If the last character is a blank, trim the length back.
1223            if c.text_utf8() == b" " {
1224                // Record the attributes etc of the last character
1225                let attr = c.attrib();
1226                let fg = c.fgcolor();
1227                let bg = c.bgcolor();
1228                self.length -= 1; // Already checked the last character
1229                while self.length > 0 {
1230                    last_char = last_char.sub(self.char_size);
1231                    let c = Utf8Char { inner: last_char };
1232                    if c.text_utf8() != b" "
1233                        || c.attrib() != attr
1234                        || c.fgcolor() != fg
1235                        || c.bgcolor() != bg
1236                    {
1237                        break; // Found a non-blank character or one with attrib changes
1238                    }
1239                    self.length -= 1;
1240                }
1241            }
1242        }
1243        self
1244    }
1245
1246    /// Index into row array of `Utf8Char`
1247    pub fn col(&self, idx: usize) -> Utf8Char {
1248        assert!((idx <= self.length), "Index {idx} out of range");
1249        unsafe {
1250            let base = self.inner;
1251            Utf8Char {
1252                inner: base.add(idx * self.char_size),
1253            }
1254        }
1255    }
1256
1257    /// Iterator object to step through a sequence of `Utf8Char` in a `BuffRow`
1258    pub fn iter(&self) -> BuffRowIter {
1259        BuffRowIter::new(self, self.length)
1260    }
1261}
1262
1263/// Iterator object to step through a sequence of `Utf8Char` in a `BuffRow`
1264pub struct BuffRowIter<'a> {
1265    parent: &'a BuffRow<'a>,
1266    ptr: *const Fl_Terminal_Utf8Char, // This points to an array of Fl_Terminal::Utf8Char
1267    end: *const Fl_Terminal_Utf8Char, // points just past the ptr array end
1268}
1269
1270impl<'a> BuffRowIter<'a> {
1271    fn new(parent: &'a BuffRow, len: usize) -> BuffRowIter<'a> {
1272        unsafe {
1273            BuffRowIter {
1274                parent,
1275                ptr: parent.inner,
1276                end: parent.inner.add(len * parent.char_size),
1277            }
1278        }
1279    }
1280}
1281
1282impl Iterator for BuffRowIter<'_> {
1283    type Item = Utf8Char;
1284    fn next(&mut self) -> Option<Self::Item> {
1285        if self.ptr < self.end {
1286            let result = Utf8Char { inner: self.ptr };
1287            unsafe {
1288                self.ptr = self.ptr.add(self.parent.char_size);
1289            }
1290            Some(result)
1291        } else {
1292            None
1293        }
1294    }
1295}
1296
1297impl<'a> IntoIterator for &'a BuffRow<'_> {
1298    type Item = Utf8Char;
1299    type IntoIter = BuffRowIter<'a>;
1300    fn into_iter(self) -> Self::IntoIter {
1301        self.iter()
1302    }
1303}