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

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

Available on crate feature enable-glwindow only.

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

Available on crate feature enable-glwindow only.

Get the RGBA value of the color

Trait Implementations§

Source§

impl Clone for Color

Source§

fn clone(&self) -> Color

Returns a copy 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.