Color

Struct Color 

Source
pub struct Color { /* private fields */ }
Expand description

Defines colors used by FLTK. Colors are stored as RGBI values, the last being the index for FLTK colors in this enum. Colors in this enum don’t have an RGB stored. However, custom colors have an RGB, and don’t have an index. The RGBI can be acquired by casting the color to u32 and formatting it to 0x{08x}. The last 2 digits are the hexadecimal representation of the color in this enum. For example, Color::White, has a hex of 0x000000ff, ff being the 255 value of this enum. A custom color like Color::from_u32(0x646464), will have an representation as 0x64646400, of which the final 00 indicates that it is not stored in this enum. For convenience, the fmt::Display trait is implemented so that the name of the Color is shown when there is one, otherwise the RGB value is given.

Implementations§

Source§

impl Color

Source

pub const ForeGround: Color

ForeGround, label colors

Source

pub const Foreground: Color

Foreground, label colors

Source

pub const BackGround2: Color

BackGround2, Is the color inside input, output and text display widgets

Source

pub const Background2: Color

Background2, Is the color inside input, output and text display widgets

Source

pub const Inactive: Color

Inactive

Source

pub const Selection: Color

Selection

Source

pub const Free: Color

Free

Source

pub const Gray0: Color

Gray0

Source

pub const GrayRamp: Color

GrayRamp

Source

pub const Dark3: Color

Dark3

Source

pub const Dark2: Color

Dark2

Source

pub const Dark1: Color

Dark1

Source

pub const FrameDefault: Color

FrameDefault

Source

pub const BackGround: Color

BackGround

Source

pub const Background: Color

Background

Source

pub const Light1: Color

Light1

Source

pub const Light2: Color

Light2

Source

pub const Light3: Color

Light3

Source

pub const Black: Color

Black

Source

pub const Red: Color

Red

Source

pub const Green: Color

Green

Source

pub const Yellow: Color

Yellow

Source

pub const Blue: Color

Blue

Source

pub const Magenta: Color

Magenta

Source

pub const Cyan: Color

Cyan

Source

pub const DarkRed: Color

DarkRed

Source

pub const DarkGreen: Color

DarkGreen

Source

pub const DarkYellow: Color

DarkYellow

Source

pub const DarkBlue: Color

DarkBlue

Source

pub const DarkMagenta: Color

DarkMagenta

Source

pub const DarkCyan: Color

DarkCyan

Source

pub const White: Color

White

Source

pub const XtermBlack: Color

ANSI/xterm Black, not part of FLTK’s colormap

Source

pub const XtermRed: Color

ANSI/xterm Red, not part of FLTK’s colormap

Source

pub const XtermGreen: Color

ANSI/xterm Green, not part of FLTK’s colormap

Source

pub const XtermYellow: Color

ANSI/xterm Yellow, not part of FLTK’s colormap

Source

pub const XtermBlue: Color

ANSI/xterm Blue, not part of FLTK’s colormap

Source

pub const XtermMagenta: Color

ANSI/xterm Magenta, not part of FLTK’s colormap

Source

pub const XtermCyan: Color

ANSI/xterm Cyan, not part of FLTK’s colormap

Source

pub const XtermWhite: Color

ANSI/xterm White, not part of FLTK’s colormap

Source

pub const XtermBgRed: Color

ANSI/xterm background Red, not part of FLTK’s colormap

Source

pub const XtermBgGreen: Color

ANSI/xterm background Green, not part of FLTK’s colormap

Source

pub const XtermBgYellow: Color

ANSI/xterm background Yelllow, not part of FLTK’s colormap

Source

pub const XtermBgBlue: Color

ANSI/xterm background Blue, not part of FLTK’s colormap

Source

pub const XtermBgMagenta: Color

ANSI/xterm background Magenta, not part of FLTK’s colormap

Source

pub const XtermBgCyan: Color

ANSI/xterm background Cyan, not part of FLTK’s colormap

Source

pub const XtermBgWhite: Color

ANSI/xterm background White, not part of FLTK’s colormap

Source

pub const TransparentBg: Color

Special background color value that lets the Terminal widget’s box() color show through behind the text. Not part of FLTK’s colormap

Source

pub const fn bits(&self) -> u32

Gets the inner color representation

Source

pub const fn from_rgb(r: u8, g: u8, b: u8) -> Color

Returns a color from RGB

Examples found in repository?
examples/flex.rs (line 10)
3fn main() {
4    let a = app::App::default().with_scheme(app::Scheme::Gtk);
5    let mut win = window::Window::default().with_size(640, 480);
6    let mut col = group::Flex::default_fill().column();
7    main_panel(&mut col);
8    col.end();
9    win.resizable(&col);
10    win.set_color(enums::Color::from_rgb(250, 250, 250));
11    win.end();
12    win.show();
13    win.size_range(600, 400, 0, 0);
14    a.run().unwrap();
15}
16
17fn buttons_panel(parent: &mut group::Flex) {
18    frame::Frame::default();
19    let w = frame::Frame::default().with_label("Welcome to Flex Login");
20
21    let mut urow = group::Flex::default().row();
22    {
23        frame::Frame::default()
24            .with_label("Username:")
25            .with_align(enums::Align::Inside | enums::Align::Right);
26        let username = input::Input::default();
27
28        urow.fixed(&username, 180);
29        urow.end();
30    }
31
32    let mut prow = group::Flex::default().row();
33    {
34        frame::Frame::default()
35            .with_label("Password:")
36            .with_align(enums::Align::Inside | enums::Align::Right);
37        let password = input::Input::default();
38
39        prow.fixed(&password, 180);
40        prow.end();
41    }
42
43    let pad = frame::Frame::default();
44
45    let mut brow = group::Flex::default().row();
46    {
47        frame::Frame::default();
48        let reg = create_button("Register");
49        let login = create_button("Login");
50
51        brow.fixed(&reg, 80);
52        brow.fixed(&login, 80);
53        brow.end();
54    }
55
56    let b = frame::Frame::default();
57
58    frame::Frame::default();
59
60    parent.fixed(&w, 60);
61    parent.fixed(&urow, 30);
62    parent.fixed(&prow, 30);
63    parent.fixed(&pad, 1);
64    parent.fixed(&brow, 30);
65    parent.fixed(&b, 30);
66}
67
68fn middle_panel(parent: &mut group::Flex) {
69    frame::Frame::default();
70
71    let mut frame = frame::Frame::default().with_label("Image");
72    frame.set_frame(enums::FrameType::BorderBox);
73    frame.set_color(enums::Color::from_rgb(0, 200, 0));
74    let spacer = frame::Frame::default();
75
76    let mut bp = group::Flex::default().column();
77    buttons_panel(&mut bp);
78    bp.end();
79
80    frame::Frame::default();
81
82    parent.fixed(&frame, 200);
83    parent.fixed(&spacer, 10);
84    parent.fixed(&bp, 300);
85}
86
87fn main_panel(parent: &mut group::Flex) {
88    frame::Frame::default();
89
90    let mut mp = group::Flex::default().row();
91    middle_panel(&mut mp);
92    mp.end();
93
94    frame::Frame::default();
95
96    parent.fixed(&mp, 200);
97}
98
99fn create_button(caption: &str) -> button::Button {
100    let mut btn = button::Button::default().with_label(caption);
101    btn.set_color(enums::Color::from_rgb(225, 225, 225));
102    btn
103}
More examples
Hide additional examples
examples/shapedwindow_taskbar.rs (line 35)
17fn main() {
18    let app = app::App::default();
19
20    // Act as the application in the taskbar (scroll to event handling)
21    let mut dock_win = window::Window::default()
22        .with_size(1, 1) // So we can place it at the center of the screen (needs a size >0 to be centered)
23        .with_label("TestApplication")
24        .center_screen();
25    dock_win.size_range(0, 0, 0, 0);
26    dock_win.make_resizable(false);
27
28    dock_win.show();
29    dock_win.end();
30
31    let mut win = window::Window::default()
32        .with_size(900, 500)
33        .with_label("TestApplication")
34        .center_screen();
35    win.set_color(enums::Color::from_rgb(26, 25, 55));
36
37    let mut but = button::Button::default()
38        .with_label("Button")
39        .with_size(80, 80)
40        .center_of_parent();
41    but.set_frame(enums::FrameType::OFlatFrame);
42    but.set_color(enums::Color::Cyan);
43    but.clear_visible_focus();
44    but.set_callback(|_| println!("Clicked"));
45
46    win.show();
47    win.end();
48
49    let win_shape = prep_shape(win.w(), win.h());
50
51    // Called after showing window
52    win.set_shape(Some(win_shape));
53
54    win.handle({
55        let mut x = 0;
56        let mut y = 0;
57        let mut dock_win = dock_win.clone();
58        move |wself, event| match event {
59            enums::Event::Push => {
60                let coords = app::event_coords();
61                x = coords.0;
62                y = coords.1;
63
64                true
65            }
66            enums::Event::Drag => {
67                wself.set_pos(app::event_x_root() - x, app::event_y_root() - y);
68
69                // Changing dock window position so it's close enough to the center of the application (not "visible" to user)
70                dock_win.set_pos(wself.x() + (wself.w() / 2), wself.y() + (wself.w() / 2));
71
72                true
73            }
74            enums::Event::Close => {
75                app.quit();
76
77                true
78            }
79            enums::Event::Hide => {
80                app.quit();
81
82                true
83            }
84            _ => false,
85        }
86    });
87
88    // Make main window appear when "opened" via Alt+Tab or Taskbar
89    dock_win.handle({
90        let mut win = win.clone();
91        move |_wself, event| match event {
92            enums::Event::Focus => {
93                let win_shape = prep_shape(win.w(), win.h());
94
95                win.show();
96                win.set_shape(Some(win_shape));
97
98                true
99            }
100            enums::Event::Hide => {
101                win.hide();
102
103                true
104            }
105            enums::Event::Close => {
106                app.quit();
107
108                true
109            }
110            _ => false,
111        }
112    });
113
114    app.run().unwrap();
115}
examples/terminal.rs (line 667)
557fn mb_test4_cb(_choice: &mut fltk::menu::Choice, term: &mut Terminal) {
558    let sel_len = term.selection_text_len();
559    let sel = term.selection_text();
560
561    term.take_focus().unwrap();
562    term.reset_terminal();
563    // Test the Utf8Char primitive
564    let uc = Utf8Char::new(b'Q');
565    let uc1 = uc.text_utf8();
566    assert_eq!(&uc1, b"Q");
567    assert_eq!(&uc.attrib(), &Attrib::Normal);
568    assert_eq!(
569        &uc.charflags(),
570        &(CharFlags::FG_XTERM | CharFlags::BG_XTERM)
571    );
572    assert_eq!(&uc.fgcolor(), &Color::XtermWhite);
573    assert_eq!(&uc.bgcolor(), &Color::TransparentBg);
574
575    let ring_rows = term.ring_rows();
576
577    term.take_focus().unwrap();
578    term.clear_history();
579    assert_eq!(term.history_use(), 0);
580
581    // Subtract row numbers, modulo `rows`
582    fn row_diff(rows: i32, a: i32, b: i32) -> i32 {
583        match a - b {
584            n if n < 0 => n + rows,
585            n => n,
586        }
587    }
588    // disp_srow is always 1 greater than hist_erow, modulo (ring_rows+1)
589    assert_eq!(row_diff(ring_rows, term.disp_srow(), term.hist_erow()), 1);
590    assert!(term.disp_srow() >= 0);
591    assert!(term.disp_erow() >= 0);
592    assert!(term.hist_srow() >= 0);
593    assert!(term.hist_erow() >= 0);
594    assert!(term.offset() >= 0);
595    assert!(term.disp_srow() <= ring_rows);
596    assert!(term.disp_erow() <= ring_rows);
597    assert!(term.hist_srow() <= ring_rows);
598    assert!(term.hist_erow() <= ring_rows);
599    assert!(term.offset() <= ring_rows);
600
601    assert_eq!(term.ring_srow(), 0);
602    assert_eq!(term.ring_erow(), ring_rows - 1);
603    assert_eq!(
604        row_diff(ring_rows, term.disp_erow(), term.disp_srow()) + 1,
605        term.display_rows()
606    );
607    assert_eq!(
608        row_diff(ring_rows, term.hist_erow(), term.hist_srow()) + 1,
609        term.history_rows()
610    );
611
612    assert_eq!(term.ring_erow(), term.ring_rows() - 1);
613    assert_eq!(term.ring_srow(), 0);
614
615    /// Local function to read back all rows from the display into a long string.
616    /// Does not include scrollback history.
617    /// Trims trailing blanks on each line
618    fn read_disp(term: &Terminal) -> String {
619        let rows = term.display_rows();
620        let mut text: Vec<u8> = Vec::with_capacity((rows * 64) as usize);
621        for row in 0..rows {
622            let r = term.u8c_disp_row(row).trim();
623            // Iterate through a row, accumulating [u8]
624            for c in r.iter() {
625                // Note: Sometimes utf-8 length is > 1
626                text.extend_from_slice(c.text_utf8());
627            }
628            text.extend_from_slice(b"\n");
629        }
630        // Return the result as a string
631        std::str::from_utf8(&text).unwrap().to_string()
632    }
633
634    term.clear();
635    term.append("Top line  ↑ (up-arrow)");
636    term.set_text_attrib(Attrib::Underline);
637    term.append("  ");
638    term.set_text_attrib(Attrib::Normal);
639    term.append("  \n");
640    let mut text_out = read_disp(term);
641    // Trim trailing empty lines
642    text_out = text_out.trim_end_matches(&"\n").to_string();
643    // The two plain blanks at the end will be trimmed, the two underlined blanks will be retained.
644
645    assert_eq!(text_out, "Top line  ↑ (up-arrow)  ");
646    let r = term.u8c_disp_row(0);
647    assert_eq!(r.col(0).text_utf8(), b"T");
648    assert_eq!(r.col(10).text_utf8(), b"\xe2\x86\x91"); // UTF-8 up-arrow
649    assert_eq!(r.col(24).text_utf8(), b" "); // First blank after test text, NOT trimmed
650    let r = term.u8c_disp_row(1);
651    assert_eq!(r.col(0).text_utf8(), b" "); // Second row starts with blanks
652    assert_eq!(r.col(1).text_utf8(), b" "); // Second row is full of blanks
653
654    // Clear the screen again, then append test text, then read it back and compare
655    let test_text = "The wind was a torrent of darkness among the gusty trees.
656The moon was a ghostly galleon tossed upon cloudy seas.
657The road was a ribbon of moonlight over the purple moor,
658And the highwayman came riding—
659            Riding—riding—
660The highwayman came riding, up to the old inn-door.";
661
662    term.clear_history();
663    term.clear();
664    let bg_save = term.text_bg_color();
665    let fg_save = term.text_fg_color();
666    term.set_text_bg_color(Color::DarkBlue); // Set spooky colors
667    term.set_text_fg_color(Color::from_rgb(0x40, 0x40, 0xff));
668    term.append(test_text);
669    term.set_text_bg_color(bg_save);
670    term.set_text_fg_color(fg_save);
671
672    let mut text_out = read_disp(term);
673    // Trim trailing empty lines
674    text_out = text_out.trim_end_matches(&"\n").to_string();
675    assert_eq!(test_text, text_out);
676
677    assert_eq!(row_diff(ring_rows, term.disp_srow(), term.hist_erow()), 1);
678
679    assert_eq!(term.ring_srow(), 0);
680    assert_eq!(term.ring_erow(), ring_rows - 1);
681    assert_eq!(
682        row_diff(ring_rows, term.disp_erow(), term.disp_srow()) + 1,
683        term.display_rows()
684    );
685    assert_eq!(
686        row_diff(ring_rows, term.hist_erow(), term.hist_srow()) + 1,
687        term.history_rows()
688    );
689
690    term.append(&format!(
691        "\n\nScreen has {} rows of {} columns.\n",
692        term.display_rows(),
693        term.display_columns()
694    ));
695
696    term.append(&format!("Selection len: {sel_len}\nSelection: '{sel}'\n"));
697}
698
699//--------------------------------------------------------------------------------------
700/// Yet another set of tests for misc cursor functions and other stuff
701/// Note: these tests depend heavily on the low-level "protected" parts of the fltk library, which should be used with caution.
702fn mb_test5_cb(_choice: &mut fltk::menu::Choice, term: &mut Terminal) {
703    term.take_focus().unwrap();
704
705    // Test the attr_fg_color and attr_bg_color methods.
706    // Put a single character 'A' into the buffer and check it
707    term.clear(); // No reset_terminal(), just clear() to preserve the mouse selection for later
708    term.set_text_bg_color(Color::TransparentBg);
709    term.set_text_fg_color(Color::XtermWhite);
710    term.append("A");
711    let r = &term.u8c_disp_row(0);
712    let uc = r.col(0);
713    assert_eq!(uc.text_utf8(), b"A");
714    assert_eq!(&uc.attr_fgcolor(None), &Color::XtermWhite);
715    assert_eq!(&uc.attr_bgcolor(None), &Color::TransparentBg);
716    assert_eq!(&uc.attr_bgcolor(Some(term)), &Color::Black);
717    assert_eq!(&uc.attr_fgcolor(Some(term)), &Color::XtermWhite);
718    assert_eq!(&uc.attrib(), &Attrib::Normal);
719
720    // Put a short string "BCD" into the first line of the buffer, with fg color change after the 'B' and bold after 'C'
721    term.clear();
722    term.set_text_fg_color_xterm(XtermColor::White);
723    term.set_text_bg_color_xterm(XtermColor::Black);
724    assert_eq!(term.text_attrib(), Attrib::Normal);
725
726    assert!(term.ansi());
727    term.append("B\x1b[32mC\x1b[1mD\n");
728
729    let r = &term.u8c_disp_row(0);
730    let uc = r.col(0);
731    assert_eq!(uc.text_utf8(), b"B");
732    assert!(uc.is_char(b'B'));
733    assert!(!uc.is_char(b'A'));
734    assert_eq!(&uc.fgcolor(), &Color::XtermWhite);
735    assert_eq!(&uc.bgcolor(), &Color::XtermBlack);
736    assert_eq!(&uc.attr_fgcolor(None), &Color::XtermWhite);
737    assert_eq!(&uc.attr_bgcolor(None), &Color::XtermBlack);
738    assert_eq!(
739        &uc.charflags(),
740        &(CharFlags::FG_XTERM | CharFlags::BG_XTERM)
741    );
742
743    let uc = r.col(1);
744    assert_eq!(uc.text_utf8(), b"C");
745    assert!(uc.is_char(b'C'));
746    assert_eq!(&uc.fgcolor(), &Color::XtermGreen);
747    assert_eq!(&uc.bgcolor(), &Color::XtermBlack);
748    assert_eq!(&uc.attr_fgcolor(None), &Color::XtermGreen);
749    assert_eq!(&uc.attr_bgcolor(None), &Color::XtermBlack);
750    assert_eq!(
751        &uc.charflags(),
752        &(CharFlags::FG_XTERM | CharFlags::BG_XTERM)
753    );
754
755    let uc = r.col(2);
756    assert_eq!(uc.text_utf8(), b"D");
757    assert!(uc.is_char(b'D'));
758    assert_eq!(&uc.fgcolor(), &Color::XtermGreen);
759    assert_eq!(&uc.bgcolor(), &Color::XtermBlack);
760    assert_eq!(&uc.attr_fgcolor(None), &Color::from_rgb(0x20, 0xf0, 0x20));
761    assert_eq!(&uc.attr_bgcolor(None), &Color::from_rgb(0x20, 0x20, 0x20));
762    assert_eq!(
763        &uc.attr_fgcolor(Some(term)),
764        &Color::from_rgb(0x20, 0xf0, 0x20)
765    );
766    assert_eq!(&uc.attr_bgcolor(None), &Color::from_rgb(0x20, 0x20, 0x20));
767    assert_eq!(
768        &uc.charflags(),
769        &(CharFlags::FG_XTERM | CharFlags::BG_XTERM)
770    );
771
772    // Put a short string "BCDE" into the buffer, with fg color change after the 'B', bg change after 'C', and bold after 'D'
773    term.clear();
774    term.set_text_fg_color_xterm(XtermColor::White);
775    term.set_text_bg_color_xterm(XtermColor::Black);
776    term.set_text_attrib(Attrib::Normal);
777    assert_eq!(term.text_attrib(), Attrib::Normal);
778
779    assert!(term.ansi());
780    term.append("B\x1b[37mC\x1b[44mD\x1b[1mE\n");
781
782    let r = &term.u8c_disp_row(0);
783    let uc = r.col(0);
784    assert_eq!(uc.text_utf8(), b"B");
785    assert!(uc.is_char(b'B'));
786    assert!(!uc.is_char(b'A'));
787    assert_eq!(&uc.fgcolor(), &Color::XtermWhite);
788    assert_eq!(&uc.bgcolor(), &Color::XtermBlack);
789    assert_eq!(&uc.attr_fgcolor(None), &Color::XtermWhite);
790    assert_eq!(&uc.attr_bgcolor(None), &Color::XtermBlack);
791    assert_eq!(
792        &uc.charflags(),
793        &(CharFlags::FG_XTERM | CharFlags::BG_XTERM)
794    );
795
796    let uc = r.col(1);
797    assert_eq!(uc.text_utf8(), b"C");
798    assert!(uc.is_char(b'C'));
799    assert_eq!(&uc.fgcolor(), &Color::XtermWhite);
800    assert_eq!(&uc.bgcolor(), &Color::XtermBlack);
801    assert_eq!(&uc.attr_fgcolor(None), &Color::XtermWhite);
802    assert_eq!(&uc.attr_bgcolor(None), &Color::XtermBlack);
803    assert_eq!(
804        &uc.charflags(),
805        &(CharFlags::FG_XTERM | CharFlags::BG_XTERM)
806    );
807
808    let uc = r.col(2);
809    assert_eq!(uc.text_utf8(), b"D");
810    assert!(uc.is_char(b'D'));
811    assert_eq!(&uc.fgcolor(), &Color::XtermWhite);
812    assert_eq!(&uc.bgcolor(), &Color::XtermBgBlue);
813    assert_eq!(&uc.attr_fgcolor(None), &Color::XtermWhite);
814    assert_eq!(&uc.attr_bgcolor(None), &Color::XtermBgBlue);
815    assert_eq!(
816        &uc.charflags(),
817        &(CharFlags::FG_XTERM | CharFlags::BG_XTERM)
818    );
819
820    let uc = r.col(3);
821    assert_eq!(uc.text_utf8(), b"E");
822    assert!(uc.is_char(b'E'));
823    assert_eq!(&uc.fgcolor(), &Color::XtermWhite);
824    assert_eq!(&uc.bgcolor(), &Color::XtermBgBlue);
825    assert_eq!(&uc.attr_fgcolor(None), &Color::from_hex(0xf0f0f0));
826    assert_eq!(&uc.attr_bgcolor(None), &Color::from_hex(0x2020e0));
827    assert_eq!(
828        &uc.charflags(),
829        &(CharFlags::FG_XTERM | CharFlags::BG_XTERM)
830    );
831
832    // Test some miscellaneous Utf8 constants
833    assert_eq!(uc.length(), 1);
834    assert_eq!(uc.max_utf8(), 4);
835    assert_eq!(uc.pwidth(), 9.0);
836    assert_eq!(uc.pwidth_int(), 9);
837
838    term.set_text_fg_color_xterm(XtermColor::White);
839    term.set_text_bg_color_xterm(XtermColor::Black);
840    term.clear();
841    term.set_text_attrib(Attrib::Normal);
842
843    // Mouse selection functions
844    term.append(&format!("Mouse selection: {:?}\n", &term.get_selection()));
845    term.clear_mouse_selection();
846    assert_eq!(term.get_selection(), None);
847
848    // Play with cursor position
849    term.append("0123456789\n"); // Set up test pattern
850    term.append("ABCDEFGHIJ\n");
851    term.append("abcdefghij\n");
852
853    term.set_cursor_row(1);
854    assert_eq!(term.cursor_row(), 1);
855    term.set_cursor_col(1);
856    assert_eq!(term.cursor_col(), 1);
857    assert_eq!(term.u8c_cursor().text_utf8(), b"1");
858
859    term.append("----"); // Overwrites text at cursor and moves cursor forward
860    assert_eq!(term.cursor_row(), 1);
861    assert_eq!(term.cursor_col(), 5);
862    assert_eq!(term.u8c_cursor().text_utf8(), b"5");
863    term.set_cursor_col(1);
864    assert_eq!(term.u8c_cursor().text_utf8(), b"-"); // Overwritten text
865
866    term.cursor_up(1, false);
867    assert_eq!(term.cursor_row(), 0);
868    assert_eq!(term.cursor_col(), 1);
869    assert_eq!(term.u8c_cursor().text_utf8(), b"o");
870
871    // Hit top of screen, so nothing happens
872    term.cursor_up(1, false);
873    assert_eq!(term.cursor_row(), 0);
874    assert_eq!(term.cursor_col(), 1);
875    assert_eq!(term.u8c_cursor().text_utf8(), b"o");
876
877    // Hit top of screen with scroll enabled. A blank line from history is scrolled in.
878    term.cursor_up(1, true);
879    assert_eq!(term.cursor_row(), 0);
880    assert_eq!(term.cursor_col(), 1);
881    assert_eq!(term.u8c_cursor().text_utf8(), b" ");
882
883    // Go back down to the overwritten text
884    term.cursor_down(2, false);
885    assert_eq!(term.cursor_row(), 2);
886    assert_eq!(term.cursor_col(), 1);
887    assert_eq!(term.u8c_cursor().text_utf8(), b"-");
888
889    // Go right past the overwritten text
890    term.cursor_right(4, false);
891    assert_eq!(term.cursor_row(), 2);
892    assert_eq!(term.cursor_col(), 5);
893    assert_eq!(term.u8c_cursor().text_utf8(), b"5");
894
895    // Go left to the end of the overwritten text
896    term.cursor_left(1);
897    assert_eq!(term.cursor_row(), 2);
898    assert_eq!(term.cursor_col(), 4);
899    assert_eq!(term.u8c_cursor().text_utf8(), b"-");
900
901    // Scroll back down, removing the blank line at the top.
902    // Cursor stays in place, the text moves under it.
903    term.scroll(1);
904    assert_eq!(term.cursor_row(), 2);
905    assert_eq!(term.cursor_col(), 4);
906    assert_eq!(term.u8c_cursor().text_utf8(), b"E");
907
908    // Clear from here to end-of-line
909    term.clear_eol();
910    assert_eq!(term.cursor_row(), 2);
911    assert_eq!(term.cursor_col(), 4);
912    assert_eq!(term.u8c_cursor().text_utf8(), b" ");
913
914    // Now clear from here to start-of-line. Cursor does not move.
915    term.clear_sol();
916    assert_eq!(term.cursor_row(), 2);
917    assert_eq!(term.cursor_col(), 4);
918    assert_eq!(term.u8c_cursor().text_utf8(), b" ");
919    term.cursor_left(1);
920    assert_eq!(term.u8c_cursor().text_utf8(), b" ");
921    term.set_cursor_col(0);
922    assert_eq!(term.u8c_cursor().text_utf8(), b" ");
923
924    // Clear some lines
925    term.clear_line(1);
926    assert_eq!(term.cursor_row(), 2);
927    assert_eq!(term.cursor_col(), 0);
928    term.set_cursor_row(1);
929    assert_eq!(term.u8c_cursor().text_utf8(), b" ");
930    term.set_cursor_row(3);
931    term.clear_cur_line();
932    assert_eq!(term.u8c_cursor().text_utf8(), b" ");
933    assert_eq!(term.cursor_row(), 3);
934    assert_eq!(term.cursor_col(), 0);
935
936    term.append("Two lines above are intentionally left blank.\n");
937    assert_eq!(term.cursor_row(), 4);
938    assert_eq!(term.cursor_col(), 0);
939
940    // Set up the test pattern again, then play with insert/delete
941    term.append("0123456789\n");
942    term.append("ABCDEFGHIJ\n");
943    term.append("abcdefghij\n");
944    assert_eq!(term.cursor_row(), 7);
945
946    term.set_cursor_row(4);
947    term.set_cursor_col(4);
948    assert_eq!(term.u8c_cursor().text_utf8(), b"4");
949
950    term.insert_char('x', 5); // Push this row right 5 chars starting at col 4
951    assert_eq!(term.u8c_cursor().text_utf8(), b"x");
952    term.cursor_right(5, false);
953    assert_eq!(term.cursor_col(), 9);
954    assert_eq!(term.u8c_cursor().text_utf8(), b"4");
955
956    // Insert two blank rows above cursor. Cursor stays put.
957    term.insert_rows(2);
958    assert_eq!(term.cursor_row(), 4);
959    assert_eq!(term.cursor_col(), 9);
960    assert_eq!(term.u8c_cursor().text_utf8(), b" ");
961    term.cursor_down(2, false); // Go down to find our text again
962    assert_eq!(term.u8c_cursor().text_utf8(), b"4");
963
964    // Go back to the beginning of the inserted 'x' characters and delete them.
965    term.cursor_left(5);
966    assert_eq!(term.u8c_cursor().text_utf8(), b"x");
967    term.delete_cur_chars(5);
968    assert_eq!(term.cursor_row(), 6);
969    assert_eq!(term.cursor_col(), 4);
970    assert_eq!(term.u8c_cursor().text_utf8(), b"4");
971
972    term.delete_chars(7, 2, 2); // Delete "CD" from the next row
973    term.cursor_down(1, false);
974    term.cursor_left(2);
975    assert_eq!(term.u8c_cursor().text_utf8(), b"E");
976
977    term.delete_rows(1); // Middle row of pattern is gone, cursor stays put
978    assert_eq!(term.u8c_cursor().text_utf8(), b"c");
979    term.cursor_up(1, false);
980    term.delete_rows(2); // Delete remains of test pattern
981
982    term.set_text_attrib(Attrib::Bold);
983    term.insert_char_eol('-', 3, 15, 20);
984    term.set_cursor_row(3);
985    term.set_cursor_col(15);
986    assert_eq!(term.u8c_cursor().text_utf8(), b"-"); // Check the insertion
987    assert_eq!(term.u8c_cursor().attrib(), Attrib::Bold);
988
989    term.set_text_attrib(Attrib::Italic);
990    term.append(" and all lines below");
991    term.set_text_attrib(Attrib::Normal);
992    term.cursor_down(1, false);
993
994    let mut hsb = term.hscrollbar();
995    let mut sb = term.scrollbar();
996    hsb.set_value(100.0);
997    assert_eq!(hsb.value(), 100.0);
998    sb.set_value(50.0);
999    assert_eq!(sb.value(), 50.0);
1000    hsb.set_value(0.0);
1001    assert_eq!(hsb.value(), 0.0);
1002    sb.set_value(0.0);
1003    assert_eq!(sb.value(), 0.0);
1004}
Source

pub const fn from_rgba(r: u8, g: u8, b: u8, a: u8) -> Color

Returns a color from RGB

Source

pub const fn from_rgbi(rgbi: u32) -> Color

Returns a color enum from RGBI encoding

Source

pub fn from_rgba_tuple(tup: (u8, u8, u8, u8)) -> Color

Create color from RGBA using alpha compositing. Works for non-group types.

Source

pub const fn from_u32(val: u32) -> Color

Returns a color from hex or decimal

Examples found in repository?
examples/frames.rs (line 14)
9    pub fn new(idx: usize) -> MyFrame {
10        let mut f = frame::Frame::default();
11        // Normally you would use the FrameType enum, for example:
12        // some_widget.set_frame(FrameType::DownBox);
13        f.set_frame(enums::FrameType::by_index(idx));
14        f.set_color(enums::Color::from_u32(0x7FFFD4));
15        let f_name = format!("{:?}", f.frame());
16        f.set_label(&f_name);
17        f.set_label_size(12);
18        Self { f }
19    }
More examples
Hide additional examples
examples/custom_dial.rs (line 70)
64fn main() {
65    let app = app::App::default();
66    app::background(255, 255, 255);
67    let mut win = window::Window::default().with_size(400, 300);
68    let mut dial = MyDial::new(100, 100, 200, 200, "CPU Load %");
69    dial.set_label_size(22);
70    dial.set_label_color(Color::from_u32(0x797979));
71    win.end();
72    win.show();
73
74    // get the cpu load value from somewhere, then call dial.set_value() in a callback or event loop
75    dial.set_value(10);
76
77    app.run().unwrap();
78}
examples/table.rs (line 66)
63fn draw_data(txt: &str, x: i32, y: i32, w: i32, h: i32, selected: bool) {
64    draw::push_clip(x, y, w, h);
65    if selected {
66        draw::set_draw_color(enums::Color::from_u32(0x00D3_D3D3));
67    } else {
68        draw::set_draw_color(enums::Color::White);
69    }
70    draw::draw_rectf(x, y, w, h);
71    draw::set_draw_color(enums::Color::Gray0);
72    draw::set_font(enums::Font::Helvetica, 14);
73    draw::draw_text2(txt, x, y, w, h, enums::Align::Center);
74    draw::draw_rect(x, y, w, h);
75    draw::pop_clip();
76}
examples/editor2.rs (line 80)
70    pub fn new(buf: text::TextBuffer) -> Self {
71        let mut editor = text::TextEditor::new(5, 35, 790, 560, "");
72        editor.set_buffer(Some(buf));
73
74        #[cfg(target_os = "macos")]
75        editor.resize(5, 5, 790, 590);
76
77        editor.set_scrollbar_size(15);
78        editor.set_text_font(Font::Courier);
79        editor.set_linenumber_width(32);
80        editor.set_linenumber_fgcolor(Color::from_u32(0x008b_8386));
81        editor.set_trigger(CallbackTrigger::Changed);
82
83        Self { editor }
84    }
examples/spreadsheet.rs (line 132)
129    fn draw_data(txt: &str, x: i32, y: i32, w: i32, h: i32, selected: bool) {
130        draw::push_clip(x, y, w, h);
131        if selected {
132            draw::set_draw_color(enums::Color::from_u32(0x00D3_D3D3));
133        } else {
134            draw::set_draw_color(enums::Color::White);
135        }
136        draw::draw_rectf(x, y, w, h);
137        draw::set_draw_color(enums::Color::Gray0);
138        draw::set_font(enums::Font::Helvetica, 14);
139        draw::draw_text2(txt, x, y, w, h, enums::Align::Center);
140        draw::draw_rect(x, y, w, h);
141        draw::pop_clip();
142    }
examples/composite_widgets.rs (line 12)
9    pub fn new(w: i32, h: i32) -> MyButton {
10        let mut grp = group::Group::new(0, 0, w, h, None);
11        grp.set_frame(enums::FrameType::RFlatBox);
12        grp.set_color(enums::Color::from_u32(0x01579b));
13        grp.set_align(enums::Align::Center);
14        let mut btn = button::Button::new(grp.x() + 420, grp.y() + 35, 30, 25, "@1+");
15        btn.set_frame(enums::FrameType::OFlatFrame);
16        btn.set_color(enums::Color::from_u32(0xf49da9));
17        btn.set_callback(move |b| b.parent().unwrap().hide());
18        grp.end();
19        grp.handle(|g, ev| match ev {
20            enums::Event::Push => {
21                g.do_callback();
22                true
23            }
24            _ => false,
25        });
26        MyButton { grp }
27    }
Source

pub const fn from_hex(val: u32) -> Color

Returns a color from hex or decimal

Examples found in repository?
examples/counter3.rs (line 7)
7const BLUE: Color = Color::from_hex(0x42A5F5);
8const SEL_BLUE: Color = Color::from_hex(0x3f51b5);
9const GRAY: Color = Color::from_hex(0x757575);
More examples
Hide additional examples
examples/calculator2.rs (line 43)
37    pub fn new(title: &'static str) -> MyButton {
38        let mut b = Button::new(0, 0, 100, 0, title);
39        b.set_label_size(24);
40        b.set_frame(FrameType::FlatBox);
41        match title {
42            "CE" => {
43                b.set_color(Color::from_hex(0xd50000));
44                b.set_shortcut(Shortcut::None | Key::Delete);
45            }
46            "x" | "/" | "+" | "-" | "=" | "C" | "@<-" => {
47                b.set_color(Color::from_hex(0xffee58));
48                b.set_label_color(Color::Black);
49                let shortcut = if title == "x" {
50                    '*'
51                } else {
52                    title.chars().next().unwrap()
53                };
54                b.set_shortcut(Shortcut::None | shortcut);
55                if shortcut == '@' {
56                    b.set_shortcut(Shortcut::None | Key::BackSpace);
57                }
58                if shortcut == '=' {
59                    b.set_shortcut(Shortcut::None | Key::Enter);
60                }
61            }
62            _ => {
63                if title == "0" {
64                    b.resize(0, 0, 100 * 2, 0);
65                }
66                b.set_label_color(Color::White);
67                b.set_selection_color(Color::from_hex(0x1b1b1b));
68                b.set_shortcut(Shortcut::None | title.chars().next().unwrap());
69                b.handle(move |b, ev| match ev {
70                    Event::Enter => {
71                        b.set_color(Color::from_hex(0x2b2b2b));
72                        b.redraw();
73                        true
74                    }
75                    Event::Leave => {
76                        b.set_color(Color::from_hex(0x424242));
77                        b.redraw();
78                        true
79                    }
80                    _ => false,
81                });
82            }
83        }
84        Self { b }
85    }
86}
87
88impl Deref for MyButton {
89    type Target = Button;
90
91    fn deref(&self) -> &Self::Target {
92        &self.b
93    }
94}
95
96impl DerefMut for MyButton {
97    fn deref_mut(&mut self) -> &mut Self::Target {
98        &mut self.b
99    }
100}
101
102fn main() {
103    let app = app::App::default();
104    app::set_visible_focus(false);
105    app::background(0x42, 0x42, 0x42);
106
107    let win_w = 400;
108    let win_h = 500;
109    let but_row = 160;
110
111    let mut operation = Ops::None;
112    let mut txt = String::from("0");
113    let mut old_val = String::from("0");
114    let mut new_val: String;
115
116    let mut wind = Window::default()
117        .with_label("FLTK Calc")
118        .with_size(win_w, win_h)
119        .center_screen();
120
121    let mut out = Frame::new(0, 0, win_w, 160, "").with_align(Align::Right | Align::Inside);
122    out.set_color(Color::from_hex(0x1b1b1b));
123    out.set_frame(FrameType::FlatBox);
124    out.set_label_color(Color::White);
125    out.set_label_size(36);
126    out.set_label("0");
127
128    let vpack = Pack::new(0, but_row, win_w, win_h - 170, "");
129
130    let mut hpack = Pack::new(0, 0, win_w, 68, "");
131    let but_ce = MyButton::new("CE");
132    let but_c = MyButton::new("C");
133    let but_back = MyButton::new("@<-");
134    let but_div = MyButton::new("/");
135    hpack.end();
136    hpack.set_type(PackType::Horizontal);
137
138    let mut hpack = Pack::new(0, 0, win_w, 68, "");
139    let mut but7 = MyButton::new("7");
140    let mut but8 = MyButton::new("8");
141    let mut but9 = MyButton::new("9");
142    let but_mul = MyButton::new("x");
143    hpack.end();
144    hpack.set_type(PackType::Horizontal);
145
146    let mut hpack = Pack::new(0, 0, win_w, 68, "");
147    let mut but4 = MyButton::new("4");
148    let mut but5 = MyButton::new("5");
149    let mut but6 = MyButton::new("6");
150    let but_sub = MyButton::new("-");
151    hpack.end();
152    hpack.set_type(PackType::Horizontal);
153
154    let mut hpack = Pack::new(0, 0, win_w, 68, "");
155    let mut but1 = MyButton::new("1");
156    let mut but2 = MyButton::new("2");
157    let mut but3 = MyButton::new("3");
158    let but_add = MyButton::new("+");
159    hpack.end();
160    hpack.set_type(PackType::Horizontal);
161
162    let mut hpack = Pack::new(0, 0, win_w, 68, "");
163    let mut but_dot = MyButton::new(".");
164    let mut but0 = MyButton::new("0");
165    let but_eq = MyButton::new("=");
166    hpack.end();
167    hpack.set_type(PackType::Horizontal);
168
169    vpack.end();
170
171    wind.make_resizable(false);
172    wind.end();
173    wind.show();
174
175    app::set_focus(&*but1);
176    app::get_system_colors();
177
178    let but_vec = vec![
179        &mut but1, &mut but2, &mut but3, &mut but4, &mut but5, &mut but6, &mut but7, &mut but8,
180        &mut but9, &mut but0,
181    ];
182
183    let but_op_vec = vec![
184        but_add, but_sub, but_mul, but_div, but_c, but_ce, but_back, but_eq,
185    ];
186
187    let (s, r) = app::channel::<Message>();
188
189    for but in but_vec {
190        let label = but.label();
191        but.emit(s, Message::Number(label.parse().unwrap()));
192    }
193
194    for mut but in but_op_vec {
195        let op = match but.label().as_str() {
196            "+" => Ops::Add,
197            "-" => Ops::Sub,
198            "x" => Ops::Mul,
199            "/" => Ops::Div,
200            "=" => Ops::Eq,
201            "CE" => Ops::CE,
202            "C" => Ops::C,
203            "@<-" => Ops::Back,
204            _ => Ops::None,
205        };
206        but.emit(s, Message::Op(op));
207    }
208
209    but_dot.emit(s, Message::Dot);
210
211    while app.wait() {
212        if let Some(val) = r.recv() {
213            match val {
214                Message::Number(num) => {
215                    if out.label() == "0" {
216                        txt.clear();
217                    }
218                    txt.push_str(&num.to_string());
219                    out.set_label(txt.as_str());
220                }
221                Message::Dot => {
222                    if operation == Ops::Eq {
223                        txt.clear();
224                        operation = Ops::None;
225                        out.set_label("0.");
226                        txt.push_str("0.");
227                    }
228                    if !txt.contains('.') {
229                        txt.push('.');
230                        out.set_label(txt.as_str());
231                    }
232                }
233                Message::Op(op) => match op {
234                    Ops::Add | Ops::Sub | Ops::Div | Ops::Mul => {
235                        old_val.clear();
236                        old_val.push_str(&out.label());
237                        operation = op;
238                        out.set_label("0");
239                    }
240                    Ops::Back => {
241                        let val = out.label();
242                        txt.pop();
243                        if val.len() > 1 {
244                            out.set_label(txt.as_str());
245                        } else {
246                            out.set_label("0");
247                        }
248                    }
249                    Ops::CE => {
250                        txt.clear();
251                        old_val.clear();
252                        txt.push('0');
253                        out.set_label(txt.as_str());
254                    }
255                    Ops::C => {
256                        txt.clear();
257                        txt.push('0');
258                        out.set_label(txt.as_str());
259                    }
260                    Ops::Eq => {
261                        new_val = out.label();
262                        let old: f64 = old_val.parse().unwrap();
263                        let new: f64 = new_val.parse().unwrap();
264                        let val = match operation {
265                            Ops::Div => old / new,
266                            Ops::Mul => old * new,
267                            Ops::Add => old + new,
268                            Ops::Sub => old - new,
269                            _ => new,
270                        };
271                        operation = Ops::None;
272                        txt = String::from("0");
273                        out.set_label(&val.to_string());
274                    }
275                    _ => (),
276                },
277            }
278        }
279    }
280}
examples/terminal.rs (line 158)
20fn main() {
21    let app = fltk::app::App::default();
22
23    // Set panic handler for main thread (will become UI thread)
24    std::panic::set_hook(Box::new({
25        |e| {
26            eprintln!("!!!!PANIC!!!!{:#?}", e);
27            error_box(e.to_string()); // Only works from the UI thread
28            std::process::exit(2);
29        }
30    }));
31
32    let mut main_win = Window::new(
33        2285,
34        180,
35        WIN_WIDTH,
36        WIN_HEIGHT,
37        "FLTK/Terminal Rust wrapper test",
38    );
39    main_win.set_type(WindowType::Double);
40    main_win.make_resizable(true);
41
42    let mut menu_bar = MenuBar::new(0, 0, WIN_WIDTH, 30, None);
43
44    let mut term = Terminal::new(0, 30, WIN_WIDTH, WIN_HEIGHT - 30, None);
45    term.set_label("term");
46    main_win.resizable(&term);
47    term.set_label_type(LabelType::None);
48
49    let idx = menu_bar.add_choice("Test&1");
50    menu_bar.at(idx).unwrap().set_callback({
51        let mut term1 = term.clone();
52        move |c| mb_test1_cb(c, &mut term1)
53    });
54    menu_bar
55        .at(idx)
56        .unwrap()
57        .set_shortcut(unsafe { std::mem::transmute(0x80031) }); // Alt-1
58
59    let idx = menu_bar.add_choice("Test&2");
60    menu_bar.at(idx).unwrap().set_callback({
61        let mut term1 = term.clone();
62        move |c| mb_test2_cb(c, &mut term1)
63    });
64    menu_bar
65        .at(idx)
66        .unwrap()
67        .set_shortcut(unsafe { std::mem::transmute(0x80032) }); // Alt-2
68
69    let idx = menu_bar.add_choice("Test&3");
70    menu_bar.at(idx).unwrap().set_callback({
71        let mut term1 = term.clone();
72        move |c| mb_test3_cb(c, &mut term1)
73    });
74    menu_bar
75        .at(idx)
76        .unwrap()
77        .set_shortcut(unsafe { std::mem::transmute(0x80033) }); // Alt-3
78
79    let idx = menu_bar.add_choice("Test&4");
80    menu_bar.at(idx).unwrap().set_callback({
81        let mut term1 = term.clone();
82        move |c| mb_test4_cb(c, &mut term1)
83    });
84    menu_bar
85        .at(idx)
86        .unwrap()
87        .set_shortcut(unsafe { std::mem::transmute(0x80034) }); // Alt-4
88
89    let idx = menu_bar.add_choice("Test&5");
90    menu_bar.at(idx).unwrap().set_callback({
91        let mut term1 = term.clone();
92        move |c| mb_test5_cb(c, &mut term1)
93    });
94    menu_bar
95        .at(idx)
96        .unwrap()
97        .set_shortcut(unsafe { std::mem::transmute(0x80035) }); // Alt-5
98
99    menu_bar.end();
100
101    main_win.end();
102    main_win.show();
103
104    // Worker thread that drives the startup tests
105    let _worker_thread: std::thread::JoinHandle<_> = std::thread::spawn({
106        let mut term = term.clone();
107        move || {
108            println!("Startup tests\n");
109            term.append("Startup tests\n\n");
110            term.append("<tmp>\n"); // This line will be overwritten later
111
112            term.cursor_up(2, false);
113            assert_eq!(term.text(false), "Startup tests\n\n"); // Ignores lines below cursor
114            assert_eq!(term.text(true), "Startup tests\n\n<tmp>\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n");
115
116            // Testing ansi() and set_ansi() methods
117            assert!(term.ansi(), "Default ANSI mode should be ON at startup");
118            term.append("ANSI mode is \x1b[4mON\x1b[0m\n");
119            term.set_ansi(false);
120            assert!(!term.ansi());
121            term.append("ANSI mode is \x1b[4mOFF\x1b[0m\n");
122            // append() method is already being used/tested. Test the u8, ascii, and utf8 variants
123            term.append_u8(b"Appending u8 array\n");
124            term.append_ascii("Appending ASCII array ↑ (up-arrow is dropped)\n");
125            term.set_ansi(true); // Restore ANSI state
126
127            // Play with the horizontal scrollbar
128            assert_eq!(term.hscrollbar_style(), ScrollbarStyle::AUTO);
129            term.set_hscrollbar_style(ScrollbarStyle::ON);
130            assert_eq!(term.hscrollbar_style(), ScrollbarStyle::ON);
131
132            // Test show_unknown() as incidental part of testing append methods
133            term.set_show_unknown(true);
134            assert!(term.show_unknown());
135            term.append_ascii(
136                "Appending ASCII array with show_unknown() ↑ (up-arrow is three unknown bytes)\n",
137            );
138            term.set_show_unknown(false);
139            assert!(!term.show_unknown());
140
141            term.append_utf8("Appending UTF8 array ↑ (up-arrow is visible)\n");
142            term.append_utf8_u8(b"Appending UTF8 array as u8 \xe2\x86\x91 (up-arrow is visible)\n");
143
144            let r = term.cursor_row();
145            assert_eq!(term.cursor_col(), 0);
146            term.append(&format!("Testing cursor row/col {r}"));
147            assert_eq!(term.cursor_col(), 24);
148            assert_eq!(term.cursor_row(), r);
149
150            // Test cursor color methods
151            assert_eq!(
152                term.cursor_bg_color(),
153                Color::XtermGreen,
154                "Default cursor bg at startup"
155            );
156            assert_eq!(
157                term.cursor_fg_color(),
158                Color::from_hex(0xff_ff_f0),
159                "Default cursor fg at startup"
160            );
161            term.set_cursor_bg_color(Color::Red);
162            assert_eq!(term.cursor_bg_color(), Color::Red);
163            assert_eq!(term.cursor_fg_color(), Color::from_hex(0xff_ff_f0));
164            term.set_cursor_fg_color(Color::Blue);
165            assert_eq!(term.cursor_bg_color(), Color::Red);
166            assert_eq!(term.cursor_fg_color(), Color::Blue);
167            term.set_cursor_bg_color(Color::XtermGreen); // Restore the defaults
168            term.set_cursor_fg_color(Color::from_hex(0xff_ff_f0));
169            assert_eq!(term.cursor_bg_color(), Color::XtermGreen);
170            assert_eq!(term.cursor_fg_color(), Color::from_hex(0xff_ff_f0));
171
172            // The default display_rows() will derive from the window size
173            let dr = term.display_rows();
174            let height = term.height();
175            assert_eq!(height, term.h());
176            assert!(dr > 20, "Default display_rows at startup");
177            term.resize(term.x(), term.y(), term.w(), height * 2);
178            assert_eq!(term.h(), height * 2);
179            assert_eq!(height * 2, term.h());
180            assert!(term.display_rows() > dr);
181            term.resize(term.x(), term.y(), term.w(), height);
182
183            // The default display_columns() will derive from the window size
184            let dc = term.display_columns();
185            assert!(dc > 80, "Default display_rows at startup");
186            term.set_display_columns(200);
187            assert_eq!(term.display_columns(), 200);
188            term.append("\n         1         2         3         4         5         6         7         8         9");
189            term.append("\n123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890");
190            term.append("[This text should be truncated by display_columns() call below.]\n"); // We shouldn't see this on screen
191            term.set_display_columns(90);
192            assert_eq!(term.display_columns(), 90);
193            term.set_display_columns(dc); // Set back to default
194            assert_eq!(term.display_columns(), dc);
195
196            assert_eq!(term.history_rows(), 100, "Default history_rows at startup");
197            term.set_history_rows(50);
198            assert_eq!(term.history_rows(), 50);
199            term.set_history_rows(100); // Set back to default
200            assert_eq!(term.history_rows(), 100);
201
202            let hu = term.history_use();
203            term.append(&format!(
204                "history_use = {hu} (it's not clear what this means)\n"
205            ));
206            // assert_eq!(term.history_use(), hu+1);
207
208            term.append(&format!(
209                "margins = b:{} l:{} r:{} t{}\n",
210                term.margin_bottom(),
211                term.margin_left(),
212                term.margin_right(),
213                term.margin_top()
214            ));
215            assert_eq!(term.margin_bottom(), 3);
216            assert_eq!(term.margin_left(), 3);
217            assert_eq!(term.margin_right(), 3);
218            assert_eq!(term.margin_top(), 3);
219
220            term.set_margin_bottom(5);
221            term.set_margin_left(10);
222            term.set_margin_right(15);
223            term.set_margin_top(20);
224            assert_eq!(term.margin_bottom(), 5);
225            assert_eq!(term.margin_left(), 10);
226            assert_eq!(term.margin_right(), 15);
227            assert_eq!(term.margin_top(), 20);
228
229            term.append("Single character: '");
230            term.print_char('X');
231            term.append("', single UTF-8 character: '");
232            term.print_char_utf8('↑');
233            term.append("'\n");
234
235            let rr = term.redraw_rate();
236            assert_eq!(rr, 0.1, "Default redraw rate at startup");
237            term.append(&format!("Redraw rate {rr}\n"));
238            term.set_redraw_rate(1.0);
239            assert_eq!(term.redraw_rate(), 1.0);
240            term.set_redraw_rate(rr);
241            assert_eq!(term.redraw_rate(), rr);
242
243            let rs = term.redraw_style();
244            term.append(&format!("Redraw style {rs:?}\n"));
245            assert_eq!(
246                rs,
247                RedrawStyle::RateLimited,
248                "Default redraw style at startup"
249            );
250            term.set_redraw_style(RedrawStyle::NoRedraw);
251            assert_eq!(term.redraw_style(), RedrawStyle::NoRedraw);
252            term.set_redraw_style(rs);
253            assert_eq!(term.redraw_style(), rs);
254
255            // Sanity checks: enum values are implicitly assigned in the C++ code so could change unexpectedly
256            assert_eq!(
257                RedrawStyle::NoRedraw.bits(),
258                0x0000,
259                "RedrawStyle enum values have been reassigned"
260            );
261            assert_eq!(
262                RedrawStyle::RateLimited.bits(),
263                0x0001,
264                "RedrawStyle enum values have been reassigned"
265            );
266            assert_eq!(
267                RedrawStyle::PerWrite.bits(),
268                0x0002,
269                "RedrawStyle enum values have been reassigned"
270            );
271
272            let sb = term.scrollbar();
273            let hsb = term.hscrollbar();
274            // Both vertical and horizontal scrollbars are at zero
275            assert_eq!(sb.value(), 0.0);
276            assert_eq!(hsb.value(), 0.0);
277            term.set_hscrollbar_style(ScrollbarStyle::AUTO);
278
279            term.append(&format!(
280                "Scrollbar actual size {}\n",
281                term.scrollbar_actual_size()
282            ));
283            assert_eq!(term.scrollbar_actual_size(), 16);
284            term.append(&format!("Scrollbar size {}\n", term.scrollbar_size()));
285            assert_eq!(
286                term.scrollbar_size(),
287                0,
288                "Default scrollbar size at startup"
289            );
290            term.set_scrollbar_size(40);
291            assert_eq!(term.scrollbar_size(), 40);
292            assert_eq!(term.scrollbar_actual_size(), 40);
293            term.append(&format!(
294                "Scrollbar actual size {}\n",
295                term.scrollbar_actual_size()
296            ));
297            term.set_scrollbar_size(0); // Restore default
298            assert_eq!(term.scrollbar_size(), 0);
299            assert_eq!(term.scrollbar_actual_size(), 16);
300
301            let sfc = term.selection_fg_color();
302            let sbc = term.selection_bg_color();
303            assert_eq!(sfc, Color::Black);
304            assert_eq!(sbc, Color::White);
305            term.append(&format!("Selection colors: {sfc} {sbc}\n"));
306            term.set_selection_fg_color(Color::Green);
307            term.set_selection_bg_color(Color::DarkBlue);
308            assert_eq!(term.selection_fg_color(), Color::Green);
309            assert_eq!(term.selection_bg_color(), Color::DarkBlue);
310            term.set_selection_fg_color(sfc);
311            term.set_selection_bg_color(sbc);
312            assert_eq!(term.selection_fg_color(), Color::Black);
313            assert_eq!(term.selection_bg_color(), Color::White);
314
315            let tfcd = term.text_fg_color_default();
316            let tbcd = term.text_bg_color_default();
317            assert_eq!(tfcd, Color::XtermWhite);
318            assert_eq!(tbcd, Color::TransparentBg);
319            term.append(&format!("Default text colors: {sfc} {sbc}\n"));
320            term.set_text_fg_color_default(Color::Green);
321            term.set_text_bg_color_default(Color::DarkBlue);
322            assert_eq!(term.text_fg_color_default(), Color::Green);
323            assert_eq!(term.text_bg_color_default(), Color::DarkBlue);
324            term.set_text_fg_color_default(tfcd);
325            term.set_text_bg_color_default(tbcd);
326            assert_eq!(term.text_fg_color_default(), Color::XtermWhite);
327            assert_eq!(term.text_bg_color_default(), Color::TransparentBg);
328
329            let tfc = term.text_fg_color();
330            let tbc = term.text_bg_color();
331            assert_eq!(tfc, Color::XtermWhite);
332            assert_eq!(tbc, Color::TransparentBg);
333            term.append(&format!("Text colors: {sfc} {sbc}\n"));
334            term.set_text_fg_color(Color::Green);
335            term.set_text_bg_color(Color::DarkBlue);
336            assert_eq!(term.text_fg_color(), Color::Green);
337            assert_eq!(term.text_bg_color(), Color::DarkBlue);
338            term.set_text_fg_color(tfc);
339            term.set_text_bg_color(tbc);
340            assert_eq!(term.text_fg_color(), Color::XtermWhite);
341            assert_eq!(term.text_bg_color(), Color::TransparentBg);
342
343            let tf = term.text_font();
344            term.append(&format!("Text font: {tf:?}\n"));
345            assert_eq!(tf, Font::Courier);
346            term.set_text_font(Font::Screen);
347            assert_eq!(term.text_font(), Font::Screen);
348            term.set_text_font(tf);
349            assert_eq!(term.text_font(), Font::Courier);
350
351            let ts = term.text_size();
352            let r = term.h_to_row(100);
353            let c = term.w_to_col(100);
354            term.append(&format!(
355                "Text size: {ts}, h_to_row(100): {r}, w_to_col(100): {c}\n"
356            ));
357            assert_eq!(ts, 14);
358            term.set_text_size(30);
359            assert_eq!(term.text_size(), 30);
360            term.append(&format!(
361                "Text size: {}, h_to_row(100): {}, w_to_col(100): {}\n",
362                term.text_size(),
363                term.h_to_row(100),
364                term.w_to_col(100)
365            ));
366            term.set_text_size(ts);
367            assert_eq!(term.text_size(), ts);
368            term.append(&format!(
369                "Text size: {}, h_to_row(100): {}, w_to_col(100): {}\n",
370                term.text_size(),
371                term.h_to_row(100),
372                term.w_to_col(100)
373            ));
374
375            // Keyboard handler
376            term.handle({
377                move |term, e| {
378                    match e {
379                        fltk::enums::Event::KeyDown
380                            if fltk::app::event_key() == fltk::enums::Key::Escape =>
381                        {
382                            // false to let FLTK handle ESC. true to hide ESC
383                            false
384                        }
385
386                        fltk::enums::Event::KeyDown
387                            if fltk::app::event_length() == 1 && fltk::app::is_event_ctrl() =>
388                        {
389                            // We handle control keystroke
390                            let k = fltk::app::event_text();
391                            term.append_utf8(&k);
392                            true
393                        }
394
395                        fltk::enums::Event::KeyDown
396                            if fltk::app::event_length() == 1 && !fltk::app::is_event_alt() =>
397                        {
398                            // We handle normal printable keystroke
399                            let k = fltk::app::event_text();
400                            term.take_focus().unwrap();
401                            term.append(&k);
402                            true
403                        }
404
405                        // fltk docs say that keyboard handler should always claim Focus and Unfocus events
406                        // We can do this, or else ignore them (return false)
407                        // fltk::enums::Event::Focus | fltk::enums::Event::Unfocus => {
408                        //     term.redraw();
409                        //     true
410                        // }
411                        _ => false, // Let FLTK handle everything else
412                    }
413                }
414            });
415
416            let attr_save = term.text_attrib();
417            term.set_text_attrib(Attrib::Inverse | Attrib::Italic);
418            term.append("\nStartup tests complete. Keyboard is live.\n");
419            assert_eq!(term.text_attrib(), Attrib::Inverse | Attrib::Italic);
420            term.set_text_attrib(attr_save);
421            assert_eq!(term.text_attrib(), attr_save);
422            term.redraw();
423        }
424    });
425
426    app.run().unwrap();
427}
428//--------------------------------------------------------------------------------------
429/// More tests that run when the menu bar Test1 is clicked
430fn mb_test1_cb(_choice: &mut fltk::menu::Choice, term: &mut Terminal) {
431    term.take_focus().unwrap();
432    term.reset_terminal();
433    term.append("0123456789 0\n");
434    term.append("0123456789 1\n");
435    term.append("0123456789 2\n");
436    term.append("0123456789 3\n");
437    term.append("0123456789 4\n");
438    term.append("0123456789 5\n");
439    term.append("0123456789 6\n");
440    term.append("0123456789 7\n");
441    term.append("0123456789 8\n");
442    term.append("0123456789 9\n");
443    term.append("------------\n");
444
445    term.set_text_fg_color(Color::Green);
446    term.plot_char('A', 0, 0);
447    term.plot_char('B', 1, 1);
448    term.plot_char('C', 2, 2);
449    term.plot_char('D', 3, 3);
450    term.plot_char('E', 4, 4);
451    term.plot_char('F', 5, 5);
452    term.set_text_fg_color(Color::XtermWhite);
453
454    assert_eq!(term.cursor_row(), 11);
455    assert_eq!(term.cursor_col(), 0);
456
457    term.set_text_bg_color(Color::DarkBlue);
458    term.plot_char_utf8('b', 8, 1);
459    term.plot_char_utf8('↑', 9, 1);
460    term.plot_char_utf8('c', 8, 2);
461    term.plot_char_utf8('↑', 9, 2);
462    term.plot_char_utf8('d', 8, 3);
463    term.plot_char_utf8('↑', 9, 3);
464    term.plot_char_utf8('e', 8, 4);
465    term.plot_char_utf8('↑', 9, 4);
466    term.plot_char_utf8('f', 8, 5);
467    term.plot_char_utf8('↑', 9, 5);
468    term.plot_char_utf8('g', 8, 6);
469    term.plot_char_utf8('↑', 9, 6);
470    term.set_text_bg_color(Color::TransparentBg);
471
472    term.set_text_attrib(Attrib::Inverse | Attrib::Italic);
473    term.append("Done!\n");
474    term.set_text_attrib(Attrib::Normal);
475}
476
477//--------------------------------------------------------------------------------------
478/// More tests that run when the menu bar button Test2 is clicked
479fn mb_test2_cb(_choice: &mut fltk::menu::Choice, term: &mut Terminal) {
480    term.take_focus().unwrap();
481    term.reset_terminal();
482
483    for i in 0..50 {
484        term.append(&format!("{i}\n"));
485    }
486    assert_eq!(term.history_rows(), 100);
487
488    term.clear_history();
489    assert_eq!(term.history_use(), 0);
490
491    term.set_text_attrib(Attrib::Inverse | Attrib::Italic);
492    term.append("\nDone!\n");
493    term.set_text_attrib(Attrib::Normal);
494}
495
496//--------------------------------------------------------------------------------------
497/// Another set of tests that run when Test3 is clicked
498fn mb_test3_cb(_choice: &mut fltk::menu::Choice, term: &mut Terminal) {
499    term.take_focus().unwrap();
500    term.reset_terminal();
501    assert_eq!(term.text_bg_color_default(), Color::TransparentBg);
502
503    assert_eq!(term.history_use(), 0);
504    term.clear();
505    assert_eq!(term.cursor_row(), 0);
506    assert_eq!(term.history_use(), term.display_rows()); // A screenful of lines added to history
507
508    term.append("Test\ntext\na\nb\nc\nd");
509    assert_eq!(term.cursor_row(), 5);
510    let hist = term.history_use();
511    term.clear_screen_home(false);
512    assert_eq!(term.cursor_row(), 0);
513    assert_eq!(term.history_use(), hist); // History not changed
514
515    term.append("Test\ntext\na\nb\nc\nd\ne");
516    assert_eq!(term.cursor_row(), 6);
517    term.clear_screen_home(true);
518    assert_eq!(term.cursor_row(), 0);
519
520    term.append("Test\ntext\na\nb\nc\n");
521    assert_eq!(term.cursor_row(), 5);
522    term.clear_to_color(Color::DarkBlue);
523    assert_eq!(term.text_bg_color_default(), Color::TransparentBg);
524    assert_eq!(term.text_bg_color(), Color::TransparentBg);
525    assert_eq!(term.cursor_row(), 0);
526
527    // Test cursor_home()
528    term.append("Test\n\n\n\n\n\n\n\n\n\n");
529    assert_eq!(term.cursor_row(), 10);
530    term.cursor_home();
531    assert_eq!(term.cursor_row(), 0);
532
533    // Test the widget color
534    assert_eq!(term.color(), Color::Black); // Default
535    term.set_color(Color::DarkGreen);
536    assert_eq!(term.color(), Color::DarkGreen);
537    term.set_color(Color::Black);
538    assert_eq!(term.color(), Color::Black);
539    term.append(
540        "This should be one line of white text on black, embedded into the top of a blue field.\n",
541    );
542
543    assert_eq!(term.output_translate(), OutFlags::LF_TO_CRLF); // default
544    term.set_output_translate(OutFlags::OFF);
545    assert_eq!(term.output_translate(), OutFlags::OFF);
546    term.set_output_translate(OutFlags::LF_TO_CRLF); // restore default
547    assert_eq!(term.output_translate(), OutFlags::LF_TO_CRLF);
548
549    term.set_text_attrib(Attrib::Inverse | Attrib::Italic);
550    term.append("\nDone!\n");
551    term.set_text_attrib(Attrib::Normal);
552}
553
554//--------------------------------------------------------------------------------------
555/// Another set of tests for the ring-buffer access methods
556/// Note: these tests depend heavily on the low-level "protected" parts of the fltk library, which should be used with caution.
557fn mb_test4_cb(_choice: &mut fltk::menu::Choice, term: &mut Terminal) {
558    let sel_len = term.selection_text_len();
559    let sel = term.selection_text();
560
561    term.take_focus().unwrap();
562    term.reset_terminal();
563    // Test the Utf8Char primitive
564    let uc = Utf8Char::new(b'Q');
565    let uc1 = uc.text_utf8();
566    assert_eq!(&uc1, b"Q");
567    assert_eq!(&uc.attrib(), &Attrib::Normal);
568    assert_eq!(
569        &uc.charflags(),
570        &(CharFlags::FG_XTERM | CharFlags::BG_XTERM)
571    );
572    assert_eq!(&uc.fgcolor(), &Color::XtermWhite);
573    assert_eq!(&uc.bgcolor(), &Color::TransparentBg);
574
575    let ring_rows = term.ring_rows();
576
577    term.take_focus().unwrap();
578    term.clear_history();
579    assert_eq!(term.history_use(), 0);
580
581    // Subtract row numbers, modulo `rows`
582    fn row_diff(rows: i32, a: i32, b: i32) -> i32 {
583        match a - b {
584            n if n < 0 => n + rows,
585            n => n,
586        }
587    }
588    // disp_srow is always 1 greater than hist_erow, modulo (ring_rows+1)
589    assert_eq!(row_diff(ring_rows, term.disp_srow(), term.hist_erow()), 1);
590    assert!(term.disp_srow() >= 0);
591    assert!(term.disp_erow() >= 0);
592    assert!(term.hist_srow() >= 0);
593    assert!(term.hist_erow() >= 0);
594    assert!(term.offset() >= 0);
595    assert!(term.disp_srow() <= ring_rows);
596    assert!(term.disp_erow() <= ring_rows);
597    assert!(term.hist_srow() <= ring_rows);
598    assert!(term.hist_erow() <= ring_rows);
599    assert!(term.offset() <= ring_rows);
600
601    assert_eq!(term.ring_srow(), 0);
602    assert_eq!(term.ring_erow(), ring_rows - 1);
603    assert_eq!(
604        row_diff(ring_rows, term.disp_erow(), term.disp_srow()) + 1,
605        term.display_rows()
606    );
607    assert_eq!(
608        row_diff(ring_rows, term.hist_erow(), term.hist_srow()) + 1,
609        term.history_rows()
610    );
611
612    assert_eq!(term.ring_erow(), term.ring_rows() - 1);
613    assert_eq!(term.ring_srow(), 0);
614
615    /// Local function to read back all rows from the display into a long string.
616    /// Does not include scrollback history.
617    /// Trims trailing blanks on each line
618    fn read_disp(term: &Terminal) -> String {
619        let rows = term.display_rows();
620        let mut text: Vec<u8> = Vec::with_capacity((rows * 64) as usize);
621        for row in 0..rows {
622            let r = term.u8c_disp_row(row).trim();
623            // Iterate through a row, accumulating [u8]
624            for c in r.iter() {
625                // Note: Sometimes utf-8 length is > 1
626                text.extend_from_slice(c.text_utf8());
627            }
628            text.extend_from_slice(b"\n");
629        }
630        // Return the result as a string
631        std::str::from_utf8(&text).unwrap().to_string()
632    }
633
634    term.clear();
635    term.append("Top line  ↑ (up-arrow)");
636    term.set_text_attrib(Attrib::Underline);
637    term.append("  ");
638    term.set_text_attrib(Attrib::Normal);
639    term.append("  \n");
640    let mut text_out = read_disp(term);
641    // Trim trailing empty lines
642    text_out = text_out.trim_end_matches(&"\n").to_string();
643    // The two plain blanks at the end will be trimmed, the two underlined blanks will be retained.
644
645    assert_eq!(text_out, "Top line  ↑ (up-arrow)  ");
646    let r = term.u8c_disp_row(0);
647    assert_eq!(r.col(0).text_utf8(), b"T");
648    assert_eq!(r.col(10).text_utf8(), b"\xe2\x86\x91"); // UTF-8 up-arrow
649    assert_eq!(r.col(24).text_utf8(), b" "); // First blank after test text, NOT trimmed
650    let r = term.u8c_disp_row(1);
651    assert_eq!(r.col(0).text_utf8(), b" "); // Second row starts with blanks
652    assert_eq!(r.col(1).text_utf8(), b" "); // Second row is full of blanks
653
654    // Clear the screen again, then append test text, then read it back and compare
655    let test_text = "The wind was a torrent of darkness among the gusty trees.
656The moon was a ghostly galleon tossed upon cloudy seas.
657The road was a ribbon of moonlight over the purple moor,
658And the highwayman came riding—
659            Riding—riding—
660The highwayman came riding, up to the old inn-door.";
661
662    term.clear_history();
663    term.clear();
664    let bg_save = term.text_bg_color();
665    let fg_save = term.text_fg_color();
666    term.set_text_bg_color(Color::DarkBlue); // Set spooky colors
667    term.set_text_fg_color(Color::from_rgb(0x40, 0x40, 0xff));
668    term.append(test_text);
669    term.set_text_bg_color(bg_save);
670    term.set_text_fg_color(fg_save);
671
672    let mut text_out = read_disp(term);
673    // Trim trailing empty lines
674    text_out = text_out.trim_end_matches(&"\n").to_string();
675    assert_eq!(test_text, text_out);
676
677    assert_eq!(row_diff(ring_rows, term.disp_srow(), term.hist_erow()), 1);
678
679    assert_eq!(term.ring_srow(), 0);
680    assert_eq!(term.ring_erow(), ring_rows - 1);
681    assert_eq!(
682        row_diff(ring_rows, term.disp_erow(), term.disp_srow()) + 1,
683        term.display_rows()
684    );
685    assert_eq!(
686        row_diff(ring_rows, term.hist_erow(), term.hist_srow()) + 1,
687        term.history_rows()
688    );
689
690    term.append(&format!(
691        "\n\nScreen has {} rows of {} columns.\n",
692        term.display_rows(),
693        term.display_columns()
694    ));
695
696    term.append(&format!("Selection len: {sel_len}\nSelection: '{sel}'\n"));
697}
698
699//--------------------------------------------------------------------------------------
700/// Yet another set of tests for misc cursor functions and other stuff
701/// Note: these tests depend heavily on the low-level "protected" parts of the fltk library, which should be used with caution.
702fn mb_test5_cb(_choice: &mut fltk::menu::Choice, term: &mut Terminal) {
703    term.take_focus().unwrap();
704
705    // Test the attr_fg_color and attr_bg_color methods.
706    // Put a single character 'A' into the buffer and check it
707    term.clear(); // No reset_terminal(), just clear() to preserve the mouse selection for later
708    term.set_text_bg_color(Color::TransparentBg);
709    term.set_text_fg_color(Color::XtermWhite);
710    term.append("A");
711    let r = &term.u8c_disp_row(0);
712    let uc = r.col(0);
713    assert_eq!(uc.text_utf8(), b"A");
714    assert_eq!(&uc.attr_fgcolor(None), &Color::XtermWhite);
715    assert_eq!(&uc.attr_bgcolor(None), &Color::TransparentBg);
716    assert_eq!(&uc.attr_bgcolor(Some(term)), &Color::Black);
717    assert_eq!(&uc.attr_fgcolor(Some(term)), &Color::XtermWhite);
718    assert_eq!(&uc.attrib(), &Attrib::Normal);
719
720    // Put a short string "BCD" into the first line of the buffer, with fg color change after the 'B' and bold after 'C'
721    term.clear();
722    term.set_text_fg_color_xterm(XtermColor::White);
723    term.set_text_bg_color_xterm(XtermColor::Black);
724    assert_eq!(term.text_attrib(), Attrib::Normal);
725
726    assert!(term.ansi());
727    term.append("B\x1b[32mC\x1b[1mD\n");
728
729    let r = &term.u8c_disp_row(0);
730    let uc = r.col(0);
731    assert_eq!(uc.text_utf8(), b"B");
732    assert!(uc.is_char(b'B'));
733    assert!(!uc.is_char(b'A'));
734    assert_eq!(&uc.fgcolor(), &Color::XtermWhite);
735    assert_eq!(&uc.bgcolor(), &Color::XtermBlack);
736    assert_eq!(&uc.attr_fgcolor(None), &Color::XtermWhite);
737    assert_eq!(&uc.attr_bgcolor(None), &Color::XtermBlack);
738    assert_eq!(
739        &uc.charflags(),
740        &(CharFlags::FG_XTERM | CharFlags::BG_XTERM)
741    );
742
743    let uc = r.col(1);
744    assert_eq!(uc.text_utf8(), b"C");
745    assert!(uc.is_char(b'C'));
746    assert_eq!(&uc.fgcolor(), &Color::XtermGreen);
747    assert_eq!(&uc.bgcolor(), &Color::XtermBlack);
748    assert_eq!(&uc.attr_fgcolor(None), &Color::XtermGreen);
749    assert_eq!(&uc.attr_bgcolor(None), &Color::XtermBlack);
750    assert_eq!(
751        &uc.charflags(),
752        &(CharFlags::FG_XTERM | CharFlags::BG_XTERM)
753    );
754
755    let uc = r.col(2);
756    assert_eq!(uc.text_utf8(), b"D");
757    assert!(uc.is_char(b'D'));
758    assert_eq!(&uc.fgcolor(), &Color::XtermGreen);
759    assert_eq!(&uc.bgcolor(), &Color::XtermBlack);
760    assert_eq!(&uc.attr_fgcolor(None), &Color::from_rgb(0x20, 0xf0, 0x20));
761    assert_eq!(&uc.attr_bgcolor(None), &Color::from_rgb(0x20, 0x20, 0x20));
762    assert_eq!(
763        &uc.attr_fgcolor(Some(term)),
764        &Color::from_rgb(0x20, 0xf0, 0x20)
765    );
766    assert_eq!(&uc.attr_bgcolor(None), &Color::from_rgb(0x20, 0x20, 0x20));
767    assert_eq!(
768        &uc.charflags(),
769        &(CharFlags::FG_XTERM | CharFlags::BG_XTERM)
770    );
771
772    // Put a short string "BCDE" into the buffer, with fg color change after the 'B', bg change after 'C', and bold after 'D'
773    term.clear();
774    term.set_text_fg_color_xterm(XtermColor::White);
775    term.set_text_bg_color_xterm(XtermColor::Black);
776    term.set_text_attrib(Attrib::Normal);
777    assert_eq!(term.text_attrib(), Attrib::Normal);
778
779    assert!(term.ansi());
780    term.append("B\x1b[37mC\x1b[44mD\x1b[1mE\n");
781
782    let r = &term.u8c_disp_row(0);
783    let uc = r.col(0);
784    assert_eq!(uc.text_utf8(), b"B");
785    assert!(uc.is_char(b'B'));
786    assert!(!uc.is_char(b'A'));
787    assert_eq!(&uc.fgcolor(), &Color::XtermWhite);
788    assert_eq!(&uc.bgcolor(), &Color::XtermBlack);
789    assert_eq!(&uc.attr_fgcolor(None), &Color::XtermWhite);
790    assert_eq!(&uc.attr_bgcolor(None), &Color::XtermBlack);
791    assert_eq!(
792        &uc.charflags(),
793        &(CharFlags::FG_XTERM | CharFlags::BG_XTERM)
794    );
795
796    let uc = r.col(1);
797    assert_eq!(uc.text_utf8(), b"C");
798    assert!(uc.is_char(b'C'));
799    assert_eq!(&uc.fgcolor(), &Color::XtermWhite);
800    assert_eq!(&uc.bgcolor(), &Color::XtermBlack);
801    assert_eq!(&uc.attr_fgcolor(None), &Color::XtermWhite);
802    assert_eq!(&uc.attr_bgcolor(None), &Color::XtermBlack);
803    assert_eq!(
804        &uc.charflags(),
805        &(CharFlags::FG_XTERM | CharFlags::BG_XTERM)
806    );
807
808    let uc = r.col(2);
809    assert_eq!(uc.text_utf8(), b"D");
810    assert!(uc.is_char(b'D'));
811    assert_eq!(&uc.fgcolor(), &Color::XtermWhite);
812    assert_eq!(&uc.bgcolor(), &Color::XtermBgBlue);
813    assert_eq!(&uc.attr_fgcolor(None), &Color::XtermWhite);
814    assert_eq!(&uc.attr_bgcolor(None), &Color::XtermBgBlue);
815    assert_eq!(
816        &uc.charflags(),
817        &(CharFlags::FG_XTERM | CharFlags::BG_XTERM)
818    );
819
820    let uc = r.col(3);
821    assert_eq!(uc.text_utf8(), b"E");
822    assert!(uc.is_char(b'E'));
823    assert_eq!(&uc.fgcolor(), &Color::XtermWhite);
824    assert_eq!(&uc.bgcolor(), &Color::XtermBgBlue);
825    assert_eq!(&uc.attr_fgcolor(None), &Color::from_hex(0xf0f0f0));
826    assert_eq!(&uc.attr_bgcolor(None), &Color::from_hex(0x2020e0));
827    assert_eq!(
828        &uc.charflags(),
829        &(CharFlags::FG_XTERM | CharFlags::BG_XTERM)
830    );
831
832    // Test some miscellaneous Utf8 constants
833    assert_eq!(uc.length(), 1);
834    assert_eq!(uc.max_utf8(), 4);
835    assert_eq!(uc.pwidth(), 9.0);
836    assert_eq!(uc.pwidth_int(), 9);
837
838    term.set_text_fg_color_xterm(XtermColor::White);
839    term.set_text_bg_color_xterm(XtermColor::Black);
840    term.clear();
841    term.set_text_attrib(Attrib::Normal);
842
843    // Mouse selection functions
844    term.append(&format!("Mouse selection: {:?}\n", &term.get_selection()));
845    term.clear_mouse_selection();
846    assert_eq!(term.get_selection(), None);
847
848    // Play with cursor position
849    term.append("0123456789\n"); // Set up test pattern
850    term.append("ABCDEFGHIJ\n");
851    term.append("abcdefghij\n");
852
853    term.set_cursor_row(1);
854    assert_eq!(term.cursor_row(), 1);
855    term.set_cursor_col(1);
856    assert_eq!(term.cursor_col(), 1);
857    assert_eq!(term.u8c_cursor().text_utf8(), b"1");
858
859    term.append("----"); // Overwrites text at cursor and moves cursor forward
860    assert_eq!(term.cursor_row(), 1);
861    assert_eq!(term.cursor_col(), 5);
862    assert_eq!(term.u8c_cursor().text_utf8(), b"5");
863    term.set_cursor_col(1);
864    assert_eq!(term.u8c_cursor().text_utf8(), b"-"); // Overwritten text
865
866    term.cursor_up(1, false);
867    assert_eq!(term.cursor_row(), 0);
868    assert_eq!(term.cursor_col(), 1);
869    assert_eq!(term.u8c_cursor().text_utf8(), b"o");
870
871    // Hit top of screen, so nothing happens
872    term.cursor_up(1, false);
873    assert_eq!(term.cursor_row(), 0);
874    assert_eq!(term.cursor_col(), 1);
875    assert_eq!(term.u8c_cursor().text_utf8(), b"o");
876
877    // Hit top of screen with scroll enabled. A blank line from history is scrolled in.
878    term.cursor_up(1, true);
879    assert_eq!(term.cursor_row(), 0);
880    assert_eq!(term.cursor_col(), 1);
881    assert_eq!(term.u8c_cursor().text_utf8(), b" ");
882
883    // Go back down to the overwritten text
884    term.cursor_down(2, false);
885    assert_eq!(term.cursor_row(), 2);
886    assert_eq!(term.cursor_col(), 1);
887    assert_eq!(term.u8c_cursor().text_utf8(), b"-");
888
889    // Go right past the overwritten text
890    term.cursor_right(4, false);
891    assert_eq!(term.cursor_row(), 2);
892    assert_eq!(term.cursor_col(), 5);
893    assert_eq!(term.u8c_cursor().text_utf8(), b"5");
894
895    // Go left to the end of the overwritten text
896    term.cursor_left(1);
897    assert_eq!(term.cursor_row(), 2);
898    assert_eq!(term.cursor_col(), 4);
899    assert_eq!(term.u8c_cursor().text_utf8(), b"-");
900
901    // Scroll back down, removing the blank line at the top.
902    // Cursor stays in place, the text moves under it.
903    term.scroll(1);
904    assert_eq!(term.cursor_row(), 2);
905    assert_eq!(term.cursor_col(), 4);
906    assert_eq!(term.u8c_cursor().text_utf8(), b"E");
907
908    // Clear from here to end-of-line
909    term.clear_eol();
910    assert_eq!(term.cursor_row(), 2);
911    assert_eq!(term.cursor_col(), 4);
912    assert_eq!(term.u8c_cursor().text_utf8(), b" ");
913
914    // Now clear from here to start-of-line. Cursor does not move.
915    term.clear_sol();
916    assert_eq!(term.cursor_row(), 2);
917    assert_eq!(term.cursor_col(), 4);
918    assert_eq!(term.u8c_cursor().text_utf8(), b" ");
919    term.cursor_left(1);
920    assert_eq!(term.u8c_cursor().text_utf8(), b" ");
921    term.set_cursor_col(0);
922    assert_eq!(term.u8c_cursor().text_utf8(), b" ");
923
924    // Clear some lines
925    term.clear_line(1);
926    assert_eq!(term.cursor_row(), 2);
927    assert_eq!(term.cursor_col(), 0);
928    term.set_cursor_row(1);
929    assert_eq!(term.u8c_cursor().text_utf8(), b" ");
930    term.set_cursor_row(3);
931    term.clear_cur_line();
932    assert_eq!(term.u8c_cursor().text_utf8(), b" ");
933    assert_eq!(term.cursor_row(), 3);
934    assert_eq!(term.cursor_col(), 0);
935
936    term.append("Two lines above are intentionally left blank.\n");
937    assert_eq!(term.cursor_row(), 4);
938    assert_eq!(term.cursor_col(), 0);
939
940    // Set up the test pattern again, then play with insert/delete
941    term.append("0123456789\n");
942    term.append("ABCDEFGHIJ\n");
943    term.append("abcdefghij\n");
944    assert_eq!(term.cursor_row(), 7);
945
946    term.set_cursor_row(4);
947    term.set_cursor_col(4);
948    assert_eq!(term.u8c_cursor().text_utf8(), b"4");
949
950    term.insert_char('x', 5); // Push this row right 5 chars starting at col 4
951    assert_eq!(term.u8c_cursor().text_utf8(), b"x");
952    term.cursor_right(5, false);
953    assert_eq!(term.cursor_col(), 9);
954    assert_eq!(term.u8c_cursor().text_utf8(), b"4");
955
956    // Insert two blank rows above cursor. Cursor stays put.
957    term.insert_rows(2);
958    assert_eq!(term.cursor_row(), 4);
959    assert_eq!(term.cursor_col(), 9);
960    assert_eq!(term.u8c_cursor().text_utf8(), b" ");
961    term.cursor_down(2, false); // Go down to find our text again
962    assert_eq!(term.u8c_cursor().text_utf8(), b"4");
963
964    // Go back to the beginning of the inserted 'x' characters and delete them.
965    term.cursor_left(5);
966    assert_eq!(term.u8c_cursor().text_utf8(), b"x");
967    term.delete_cur_chars(5);
968    assert_eq!(term.cursor_row(), 6);
969    assert_eq!(term.cursor_col(), 4);
970    assert_eq!(term.u8c_cursor().text_utf8(), b"4");
971
972    term.delete_chars(7, 2, 2); // Delete "CD" from the next row
973    term.cursor_down(1, false);
974    term.cursor_left(2);
975    assert_eq!(term.u8c_cursor().text_utf8(), b"E");
976
977    term.delete_rows(1); // Middle row of pattern is gone, cursor stays put
978    assert_eq!(term.u8c_cursor().text_utf8(), b"c");
979    term.cursor_up(1, false);
980    term.delete_rows(2); // Delete remains of test pattern
981
982    term.set_text_attrib(Attrib::Bold);
983    term.insert_char_eol('-', 3, 15, 20);
984    term.set_cursor_row(3);
985    term.set_cursor_col(15);
986    assert_eq!(term.u8c_cursor().text_utf8(), b"-"); // Check the insertion
987    assert_eq!(term.u8c_cursor().attrib(), Attrib::Bold);
988
989    term.set_text_attrib(Attrib::Italic);
990    term.append(" and all lines below");
991    term.set_text_attrib(Attrib::Normal);
992    term.cursor_down(1, false);
993
994    let mut hsb = term.hscrollbar();
995    let mut sb = term.scrollbar();
996    hsb.set_value(100.0);
997    assert_eq!(hsb.value(), 100.0);
998    sb.set_value(50.0);
999    assert_eq!(sb.value(), 50.0);
1000    hsb.set_value(0.0);
1001    assert_eq!(hsb.value(), 0.0);
1002    sb.set_value(0.0);
1003    assert_eq!(sb.value(), 0.0);
1004}
Source

pub fn from_hex_str(col: &str) -> Result<Color, FltkError>

Return a Color from a hex color format (#xxxxxx)

Source

pub fn to_hex_str(&self) -> String

Returns the color in hex string format

Source

pub fn by_index(idx: u8) -> Color

Returns a color by index of RGBI

Examples found in repository?
examples/tile.rs (line 26)
3fn main() {
4    let app = app::App::default();
5    let mut window = window::Window::default().with_size(300, 300);
6    window.set_frame(FrameType::NoBox);
7    window.make_resizable(true);
8
9    let dx = 20;
10    let dy = dx; // border width of resizable() - see below
11    let tile = group::Tile::default_fill();
12
13    // create the symmetrical resize box with dx and dy pixels distance, resp.
14    // from the borders of the Fl_Tile widget before all other children
15    let r = frame::Frame::new(
16        tile.x() + dx,
17        tile.y() + dy,
18        tile.w() - 2 * dx,
19        tile.h() - 2 * dy,
20        None,
21    );
22    tile.resizable(&r);
23
24    let mut box0 = frame::Frame::new(0, 0, 150, 150, "0");
25    box0.set_frame(FrameType::DownBox);
26    box0.set_color(Color::by_index(9));
27    box0.set_label_size(36);
28    box0.set_align(Align::Clip);
29
30    let mut w1 = window::Window::new(150, 0, 150, 150, "1");
31    w1.set_frame(FrameType::NoBox);
32    let mut box1 = frame::Frame::new(0, 0, 150, 150, "1\nThis is a child window");
33    box1.set_frame(FrameType::DownBox);
34    box1.set_color(Color::by_index(19));
35    box1.set_label_size(18);
36    box1.set_align(Align::Clip | Align::Inside | Align::Wrap);
37    w1.resizable(&box1);
38    w1.end();
39
40    let mut box2a = frame::Frame::new(0, 150, 70, 150, "2a");
41    box2a.set_frame(FrameType::DownBox);
42    box2a.set_color(Color::by_index(12));
43    box2a.set_label_size(36);
44    box2a.set_align(Align::Clip);
45
46    let mut box2b = frame::Frame::new(70, 150, 80, 150, "2b");
47    box2b.set_frame(FrameType::DownBox);
48    box2b.set_color(Color::by_index(13));
49    box2b.set_label_size(36);
50    box2b.set_align(Align::Clip);
51
52    let mut box3a = frame::Frame::new(150, 150, 150, 70, "3a");
53    box3a.set_frame(FrameType::DownBox);
54    box3a.set_color(Color::by_index(12));
55    box3a.set_label_size(36);
56    box3a.set_align(Align::Clip);
57
58    let mut box3b = frame::Frame::new(150, 150 + 70, 150, 80, "3b");
59    box3b.set_frame(FrameType::DownBox);
60    box3b.set_color(Color::by_index(13));
61    box3b.set_label_size(36);
62    box3b.set_align(Align::Clip);
63
64    tile.end();
65    window.end();
66
67    w1.show();
68    window.show();
69
70    app.run().unwrap();
71}
Source

pub fn inactive(&self) -> Color

Returns an inactive form of the color

Examples found in repository?
examples/gradients.rs (line 19)
5fn create_vertical_gradient_frame(
6    x: i32,
7    y: i32,
8    w: i32,
9    h: i32,
10    col1: Color,
11    col2: Color,
12) -> frame::Frame {
13    let mut frame = frame::Frame::new(x, y, w, h, "Vertical");
14    frame.draw(move |f| {
15        let imax = f.h();
16        let d = if imax > 0 { imax } else { 1 };
17        for i in 0..=imax {
18            let w = 1.0 - i as f32 / d as f32;
19            set_draw_color(Color::inactive(&Color::color_average(col1, col2, w)));
20            draw_xyline(f.x(), f.y() + i, f.x() + f.w());
21        }
22        set_draw_color(Color::Black);
23        set_font(Font::Helvetica, app::font_size());
24        draw_text2(&f.label(), f.x(), f.y(), f.w(), f.h(), f.align());
25    });
26    frame
27}
28
29fn create_horizontal_gradient_frame(
30    x: i32,
31    y: i32,
32    w: i32,
33    h: i32,
34    col1: Color,
35    col2: Color,
36) -> frame::Frame {
37    let mut frame = frame::Frame::new(x, y, w, h, "Horizontal");
38    frame.draw(move |f| {
39        let imax = f.w();
40        let d = if imax > 0 { imax } else { 1 };
41        for i in 0..=imax {
42            let w = 1.0 - i as f32 / d as f32;
43            set_draw_color(Color::inactive(&Color::color_average(col1, col2, w)));
44            draw_yxline(f.x() + i, f.y(), f.y() + f.h());
45        }
46        set_draw_color(Color::Black);
47        set_font(Font::Helvetica, app::font_size());
48        draw_text2(&f.label(), f.x(), f.y(), f.w(), f.h(), f.align());
49    });
50    frame
51}
52
53fn create_horizontal_svg_gradient_frame(
54    x: i32,
55    y: i32,
56    w: i32,
57    h: i32,
58    col1: Color,
59    col2: Color,
60) -> frame::Frame {
61    let mut frame = frame::Frame::new(x, y, w, h, "Svg");
62    frame.draw(move |f| {
63        let (r1, g1, b1) = Color::inactive(&col1).to_rgb();
64        let (r2, g2, b2) = Color::inactive(&col2).to_rgb();
65        let svg = format!(
66            "<svg viewBox='0 0 {} {}'>
67        <defs>
68        <linearGradient id='grad1' x1='0%' y1='0%' x2='0%' y2='100%'>
69        <stop offset='0%' style='stop-color:rgb({},{},{});stop-opacity:1' />
70        <stop offset='100%' style='stop-color:rgb({},{},{});stop-opacity:1' />
71        </linearGradient>
72        </defs>
73        <rect width='100%' height='100%' fill='url(#grad1)' />
74        </svg>",
75            f.w(),
76            f.h() + 1,
77            r1,
78            g1,
79            b1,
80            r2,
81            g2,
82            b2
83        );
84        let mut image = image::SvgImage::from_data(&svg).unwrap();
85        image.draw(f.x(), f.y(), f.w(), f.h());
86        set_draw_color(Color::Black);
87        set_font(Font::Helvetica, app::font_size());
88        draw_text2(&f.label(), f.x(), f.y(), f.w(), f.h(), f.align());
89    });
90    frame
91}
Source

pub fn darker(&self) -> Color

Returns an darker form of the color

Examples found in repository?
examples/defaults.rs (line 23)
3fn main() {
4    let app = app::App::default();
5    // global theming
6    app::background(55, 55, 55); // background color.
7                                 // For input/output and text widgets, use app::background2
8    app::background2(0, 0, 0);
9    app::foreground(255, 255, 255); // labels
10    app::set_font_size(16);
11    app::set_frame_type2(FrameType::UpBox, FrameType::RFlatBox);
12    app::set_frame_type2(FrameType::DownBox, FrameType::RFlatBox);
13    app::set_frame_border_radius_max(15); // set the roundness of the RFlatBox
14    app::set_font(Font::Times);
15    app::set_visible_focus(false);
16
17    // regular widget code
18    let mut win = window::Window::default().with_size(400, 300);
19    let mut flex = group::Flex::default_fill().column();
20    flex.set_margins(100, 60, 100, 60);
21    flex.set_pad(10);
22    let mut btn1 = button::Button::default().with_label("Increment");
23    btn1.set_color(Color::Red.darker());
24    btn1.set_selection_color(Color::Red.darker().darker());
25    let mut out = frame::Frame::default().with_label("0");
26    out.set_color(Color::Green.darker());
27    let mut btn2 = button::Button::default().with_label("Decrement");
28    btn2.set_color(Color::Red.darker());
29    btn2.set_selection_color(Color::Red.darker().darker());
30    flex.end();
31    win.end();
32    win.show();
33
34    app.run().unwrap();
35}
Source

pub fn lighter(&self) -> Color

Returns an lighter form of the color

Source

pub fn gray_ramp(val: i32) -> Color

Returns a gray color value from black (i == 0) to white (i == FL_NUM_GRAY - 1)

Source

pub fn color_average(c1: Color, c2: Color, weight: f32) -> Color

Returns a gray color value from black (i == 0) to white (i == FL_NUM_GRAY - 1)

Examples found in repository?
examples/gradients.rs (line 19)
5fn create_vertical_gradient_frame(
6    x: i32,
7    y: i32,
8    w: i32,
9    h: i32,
10    col1: Color,
11    col2: Color,
12) -> frame::Frame {
13    let mut frame = frame::Frame::new(x, y, w, h, "Vertical");
14    frame.draw(move |f| {
15        let imax = f.h();
16        let d = if imax > 0 { imax } else { 1 };
17        for i in 0..=imax {
18            let w = 1.0 - i as f32 / d as f32;
19            set_draw_color(Color::inactive(&Color::color_average(col1, col2, w)));
20            draw_xyline(f.x(), f.y() + i, f.x() + f.w());
21        }
22        set_draw_color(Color::Black);
23        set_font(Font::Helvetica, app::font_size());
24        draw_text2(&f.label(), f.x(), f.y(), f.w(), f.h(), f.align());
25    });
26    frame
27}
28
29fn create_horizontal_gradient_frame(
30    x: i32,
31    y: i32,
32    w: i32,
33    h: i32,
34    col1: Color,
35    col2: Color,
36) -> frame::Frame {
37    let mut frame = frame::Frame::new(x, y, w, h, "Horizontal");
38    frame.draw(move |f| {
39        let imax = f.w();
40        let d = if imax > 0 { imax } else { 1 };
41        for i in 0..=imax {
42            let w = 1.0 - i as f32 / d as f32;
43            set_draw_color(Color::inactive(&Color::color_average(col1, col2, w)));
44            draw_yxline(f.x() + i, f.y(), f.y() + f.h());
45        }
46        set_draw_color(Color::Black);
47        set_font(Font::Helvetica, app::font_size());
48        draw_text2(&f.label(), f.x(), f.y(), f.w(), f.h(), f.align());
49    });
50    frame
51}
52
53fn create_horizontal_svg_gradient_frame(
54    x: i32,
55    y: i32,
56    w: i32,
57    h: i32,
58    col1: Color,
59    col2: Color,
60) -> frame::Frame {
61    let mut frame = frame::Frame::new(x, y, w, h, "Svg");
62    frame.draw(move |f| {
63        let (r1, g1, b1) = Color::inactive(&col1).to_rgb();
64        let (r2, g2, b2) = Color::inactive(&col2).to_rgb();
65        let svg = format!(
66            "<svg viewBox='0 0 {} {}'>
67        <defs>
68        <linearGradient id='grad1' x1='0%' y1='0%' x2='0%' y2='100%'>
69        <stop offset='0%' style='stop-color:rgb({},{},{});stop-opacity:1' />
70        <stop offset='100%' style='stop-color:rgb({},{},{});stop-opacity:1' />
71        </linearGradient>
72        </defs>
73        <rect width='100%' height='100%' fill='url(#grad1)' />
74        </svg>",
75            f.w(),
76            f.h() + 1,
77            r1,
78            g1,
79            b1,
80            r2,
81            g2,
82            b2
83        );
84        let mut image = image::SvgImage::from_data(&svg).unwrap();
85        image.draw(f.x(), f.y(), f.w(), f.h());
86        set_draw_color(Color::Black);
87        set_font(Font::Helvetica, app::font_size());
88        draw_text2(&f.label(), f.x(), f.y(), f.w(), f.h(), f.align());
89    });
90    frame
91}
92
93fn main() {
94    let a = app::App::default();
95    let mut win = window::Window::default().with_size(300, 300);
96    create_vertical_gradient_frame(0, 0, 100, 100, Color::Red, Color::Cyan);
97    create_horizontal_gradient_frame(100, 0, 100, 100, Color::Red, Color::Cyan);
98    create_horizontal_svg_gradient_frame(200, 0, 100, 100, Color::Red, Color::Cyan);
99    win.end();
100    win.draw(|w| {
101        // vertical gradient
102        let imax = w.w();
103        let d = if imax > 0 { imax } else { 1 };
104        for i in 0..=imax {
105            let v = 1.0 - i as f32 / d as f32;
106            set_draw_color(Color::color_average(Color::Red, Color::Blue, v));
107            draw_yxline(i, 0, w.h());
108        }
109        w.draw_children();
110    });
111    win.make_resizable(true);
112    win.show();
113    a.run().unwrap();
114}
Source

pub fn contrast(fg: Color, bg: Color) -> Color

Returns a color that contrasts with the background color.

Source

pub fn gray_scale(g: u8) -> Color

Returns the color closest to the passed grayscale value

Source

pub fn rgb_color(r: u8, g: u8, b: u8) -> Color

Returns the color closest to the passed rgb value

Source

pub fn to_rgb(&self) -> (u8, u8, u8)

Get the RGB value of the color

Examples found in repository?
examples/gradients.rs (line 63)
53fn create_horizontal_svg_gradient_frame(
54    x: i32,
55    y: i32,
56    w: i32,
57    h: i32,
58    col1: Color,
59    col2: Color,
60) -> frame::Frame {
61    let mut frame = frame::Frame::new(x, y, w, h, "Svg");
62    frame.draw(move |f| {
63        let (r1, g1, b1) = Color::inactive(&col1).to_rgb();
64        let (r2, g2, b2) = Color::inactive(&col2).to_rgb();
65        let svg = format!(
66            "<svg viewBox='0 0 {} {}'>
67        <defs>
68        <linearGradient id='grad1' x1='0%' y1='0%' x2='0%' y2='100%'>
69        <stop offset='0%' style='stop-color:rgb({},{},{});stop-opacity:1' />
70        <stop offset='100%' style='stop-color:rgb({},{},{});stop-opacity:1' />
71        </linearGradient>
72        </defs>
73        <rect width='100%' height='100%' fill='url(#grad1)' />
74        </svg>",
75            f.w(),
76            f.h() + 1,
77            r1,
78            g1,
79            b1,
80            r2,
81            g2,
82            b2
83        );
84        let mut image = image::SvgImage::from_data(&svg).unwrap();
85        image.draw(f.x(), f.y(), f.w(), f.h());
86        set_draw_color(Color::Black);
87        set_font(Font::Helvetica, app::font_size());
88        draw_text2(&f.label(), f.x(), f.y(), f.w(), f.h(), f.align());
89    });
90    frame
91}
More examples
Hide additional examples
examples/rounded_images.rs (line 12)
6    pub fn new(radius: i32, mut image: image::RgbImage) -> Self {
7        let mut frame = frame::Frame::new(0, 0, radius * 2, radius * 2, None);
8        frame.set_frame(enums::FrameType::FlatBox);
9        frame.draw(move |f| {
10            image.scale(f.w(), f.h(), false, true);
11            image.draw(f.x(), f.y(), f.w(), f.h());
12            let color = f.color().to_rgb();
13            let s = format!(
14                "<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n
15              <svg width='{}' height='{}'>\n
16                <rect x='{}' 
17                    y='{}' 
18                    rx='{}' 
19                    ry='{}' 
20                    width='{}' 
21                    height='{}' 
22                    fill='none' 
23                    stroke='rgb({}, {}, {})' 
24                    stroke-width='{}' />\n
25              </svg>\n",
26                f.w(),
27                f.h(),
28                -f.w() / 2,
29                -f.w() / 2,
30                f.w(),
31                f.w(),
32                f.w() + f.w(),
33                f.h() + f.w(),
34                color.0,
35                color.1,
36                color.2,
37                f.w()
38            );
39            let mut s = image::SvgImage::from_data(&s).unwrap();
40            s.draw(f.x(), f.y(), f.w(), f.h());
41        });
42        Self
43    }
examples/format_text.rs (line 293)
122fn main() {
123    let style = Rc::from(RefCell::from(Style::new()));
124
125    let app = App::default().with_scheme(Scheme::Gleam);
126    let mut wind = Window::default()
127        .with_size(500, 200)
128        .with_label("Highlight");
129    let mut vpack = Pack::new(4, 4, 492, 192, "");
130    vpack.set_spacing(4);
131    let mut text_editor = TextEditor::default().with_size(492, 163);
132
133    let mut hpack = Pack::new(4, 4, 492, 25, "").with_type(PackType::Horizontal);
134    hpack.set_spacing(8);
135    let mut font = Choice::default().with_size(130, 25);
136    let mut choice = Choice::default().with_size(130, 25);
137    let mut size = Spinner::default().with_size(60, 25);
138
139    let mut color = Choice::default().with_size(100, 25);
140    let mut btn_clear = Button::default().with_size(40, 25).with_label("X");
141    hpack.end();
142
143    vpack.end();
144    wind.end();
145    wind.show();
146
147    text_editor.wrap_mode(fltk::text::WrapMode::AtBounds, 0);
148    text_editor.set_buffer(TextBuffer::default());
149
150    font.add_choice("Courier|Helvetica|Times");
151    font.set_value(0);
152    font.set_tooltip("Font");
153
154    choice.add_choice("Normal|Underline|Strike");
155    choice.set_value(0);
156
157    size.set_value(18.0);
158    size.set_step(1.0);
159    size.set_range(12.0, 28.0);
160    size.set_tooltip("Size");
161
162    color.set_tooltip("Color");
163    color.add_choice("#000000|#ff0000|#00ff00|#0000ff|#ffff00|#00ffff");
164    color.set_value(0);
165
166    btn_clear.set_label_color(Color::Red);
167    btn_clear.set_tooltip("Clear style");
168
169    // set colors
170    for mut item in color.clone() {
171        if let Some(lbl) = item.label() {
172            item.set_label_color(Color::from_u32(
173                u32::from_str_radix(lbl.trim().strip_prefix('#').unwrap(), 16)
174                    .ok()
175                    .unwrap(),
176            ));
177        }
178    }
179
180    let style_rc1 = Rc::clone(&style);
181
182    text_editor.buffer().unwrap().add_modify_callback({
183        let mut text_editor1 = text_editor.clone();
184        let font1 = font.clone();
185        let size1 = size.clone();
186        let color1 = color.clone();
187        let choice1 = choice.clone();
188        move |pos: i32, ins_items: i32, del_items: i32, _: i32, _: &str| {
189            let attr = if choice1.value() == 1 {
190                TextAttr::Underline
191            } else if choice1.value() == 2 {
192                TextAttr::StrikeThrough
193            } else {
194                TextAttr::None
195            };
196            if ins_items > 0 || del_items > 0 {
197                let mut style = style_rc1.borrow_mut();
198                let color = Color::from_u32(
199                    u32::from_str_radix(
200                        color1
201                            .text(color1.value())
202                            .unwrap()
203                            .trim()
204                            .strip_prefix('#')
205                            .unwrap(),
206                        16,
207                    )
208                    .ok()
209                    .unwrap(),
210                );
211                style.apply_style(
212                    Some(pos),
213                    Some(ins_items),
214                    Some(del_items),
215                    None,
216                    None,
217                    Font::by_name(font1.text(font1.value()).unwrap().trim()),
218                    size1.value() as i32,
219                    color,
220                    attr,
221                    &mut text_editor1,
222                );
223            }
224        }
225    });
226
227    color.set_callback({
228        let size = size.clone();
229        let font = font.clone();
230        let choice = choice.clone();
231        let mut text_editor = text_editor.clone();
232        let style_rc1 = Rc::clone(&style);
233        move |color| {
234            let attr = match choice.value() {
235                0 => TextAttr::None,
236                1 => TextAttr::Underline,
237                2 => TextAttr::StrikeThrough,
238                _ => unreachable!(),
239            };
240            if let Some(buf) = text_editor.buffer() {
241                if let Some((s, e)) = buf.selection_position() {
242                    let mut style = style_rc1.borrow_mut();
243                    let color = Color::from_u32(
244                        u32::from_str_radix(
245                            color
246                                .text(color.value())
247                                .unwrap()
248                                .trim()
249                                .strip_prefix('#')
250                                .unwrap(),
251                            16,
252                        )
253                        .ok()
254                        .unwrap(),
255                    );
256                    style.apply_style(
257                        None,
258                        None,
259                        None,
260                        Some(s),
261                        Some(e),
262                        Font::by_name(font.text(font.value()).unwrap().trim()),
263                        size.value() as i32,
264                        color,
265                        attr,
266                        &mut text_editor,
267                    );
268                }
269            }
270        }
271    });
272
273    // get the style from the current cursor position
274    text_editor.handle({
275        let style_rc1 = Rc::clone(&style);
276        let mut font1 = font.clone();
277        let mut size1 = size.clone();
278        let mut color1 = color.clone();
279        move |te, e| match e {
280            Event::KeyUp | Event::Released => {
281                if let Some(buff) = te.style_buffer() {
282                    let i = te.insert_position();
283                    if let Some(t) = buff.text_range(i, i + 1) {
284                        if !t.is_empty() {
285                            let style = style_rc1.borrow_mut();
286                            if let Some(i) = t.chars().next().map(|c| (c as usize - 65)) {
287                                if let Some(style) = style.style_table.get(i) {
288                                    if let Some(mn) = font1.find_item(&format!("{:?}", style.font))
289                                    {
290                                        font1.set_item(&mn);
291                                    }
292                                    size1.set_value(style.size as f64);
293                                    let (r, g, b) = style.color.to_rgb();
294                                    if let Some(mn) =
295                                        color1.find_item(format!("{r:02x}{g:02x}{b:02x}").as_str())
296                                    {
297                                        color1.set_item(&mn);
298                                    }
299                                }
300                            }
301                        }
302                    }
303                }
304                true
305            }
306            _ => false,
307        }
308    });
309
310    choice.set_callback({
311        let mut color1 = color.clone();
312        move |_| color1.do_callback()
313    });
314
315    font.set_callback({
316        let mut color1 = color.clone();
317        move |_| color1.do_callback()
318    });
319
320    size.set_callback({
321        let mut color1 = color.clone();
322        move |_| color1.do_callback()
323    });
324
325    // clear style of the current selection or, if no text is selected, clear all text style
326    btn_clear.set_callback({
327        let style_rc1 = Rc::clone(&style);
328        let text_editor1 = text_editor.clone();
329        move |_| {
330            match text_editor1.buffer().unwrap().selection_position() {
331                Some((_, _)) => {
332                    font.set_value(0);
333                    size.set_value(18.0);
334                    color.set_value(0);
335                    choice.set_value(0);
336                    color.do_callback();
337                }
338                None => {
339                    font.set_value(0);
340                    size.set_value(18.0);
341                    color.set_value(0);
342                    style_rc1.borrow_mut().apply_style(
343                        None,
344                        None,
345                        None,
346                        Some(0),
347                        Some(text_editor1.buffer().unwrap().length()),
348                        Font::Courier,
349                        16,
350                        Color::Black,
351                        TextAttr::None,
352                        &mut text_editor,
353                    );
354                }
355            };
356        }
357    });
358
359    app.run().unwrap();
360}
Source

pub fn to_rgba(&self) -> (u8, u8, u8, u8)

Get the RGBA value of the color

Trait Implementations§

Source§

impl Clone for Color

Source§

fn clone(&self) -> Color

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Color

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Display for Color

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Hash for Color

Source§

fn hash<__H: Hasher>(&self, state: &mut __H)

Feeds this value into the given Hasher. Read more
1.3.0 · Source§

fn hash_slice<H>(data: &[Self], state: &mut H)
where H: Hasher, Self: Sized,

Feeds a slice of this type into the given Hasher. Read more
Source§

impl Ord for Color

Source§

fn cmp(&self, other: &Color) -> Ordering

This method returns an Ordering between self and other. Read more
1.21.0 · Source§

fn max(self, other: Self) -> Self
where Self: Sized,

Compares and returns the maximum of two values. Read more
1.21.0 · Source§

fn min(self, other: Self) -> Self
where Self: Sized,

Compares and returns the minimum of two values. Read more
1.50.0 · Source§

fn clamp(self, min: Self, max: Self) -> Self
where Self: Sized,

Restrict a value to a certain interval. Read more
Source§

impl PartialEq for Color

Source§

fn eq(&self, other: &Color) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl PartialOrd for Color

Source§

fn partial_cmp(&self, other: &Color) -> Option<Ordering>

This method returns an ordering between self and other values if one exists. Read more
1.0.0 · Source§

fn lt(&self, other: &Rhs) -> bool

Tests less than (for self and other) and is used by the < operator. Read more
1.0.0 · Source§

fn le(&self, other: &Rhs) -> bool

Tests less than or equal to (for self and other) and is used by the <= operator. Read more
1.0.0 · Source§

fn gt(&self, other: &Rhs) -> bool

Tests greater than (for self and other) and is used by the > operator. Read more
1.0.0 · Source§

fn ge(&self, other: &Rhs) -> bool

Tests greater than or equal to (for self and other) and is used by the >= operator. Read more
Source§

impl Copy for Color

Source§

impl Eq for Color

Source§

impl StructuralPartialEq for Color

Auto Trait Implementations§

§

impl Freeze for Color

§

impl RefUnwindSafe for Color

§

impl Send for Color

§

impl Sync for Color

§

impl Unpin for Color

§

impl UnwindSafe for Color

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T> ToString for T
where T: Display + ?Sized,

Source§

fn to_string(&self) -> String

Converts the given value to a String. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.