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}