1#![allow(clippy::missing_transmute_annotations)]
2
3use fltk::{
8 enums::{Color, Font, LabelType},
9 menu::MenuBar,
10 prelude::*,
11 terminal::{
12 Attrib, CharFlags, OutFlags, RedrawStyle, ScrollbarStyle, Terminal, Utf8Char, XtermColor,
13 },
14 window::{Window, WindowType},
15};
16
17const WIN_WIDTH: i32 = 900;
18const WIN_HEIGHT: i32 = 600;
19
20fn main() {
21 let app = fltk::app::App::default();
22
23 std::panic::set_hook(Box::new({
25 |e| {
26 eprintln!("!!!!PANIC!!!!{:#?}", e);
27 error_box(e.to_string()); 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) }); 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) }); 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) }); 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) }); 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) }); menu_bar.end();
100
101 main_win.end();
102 main_win.show();
103
104 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"); term.cursor_up(2, false);
113 assert_eq!(term.text(false), "Startup tests\n\n"); assert_eq!(term.text(true), "Startup tests\n\n<tmp>\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n");
115
116 assert!(term.ansi(), "Default ANSI mode should be ON at startup");
118 term.append("ANSI mode is \x1b[4mON\x1b[0m\n");
119 term.set_ansi(false);
120 assert!(!term.ansi());
121 term.append("ANSI mode is \x1b[4mOFF\x1b[0m\n");
122 term.append_u8(b"Appending u8 array\n");
124 term.append_ascii("Appending ASCII array ↑ (up-arrow is dropped)\n");
125 term.set_ansi(true); assert_eq!(term.hscrollbar_style(), ScrollbarStyle::AUTO);
129 term.set_hscrollbar_style(ScrollbarStyle::ON);
130 assert_eq!(term.hscrollbar_style(), ScrollbarStyle::ON);
131
132 term.set_show_unknown(true);
134 assert!(term.show_unknown());
135 term.append_ascii(
136 "Appending ASCII array with show_unknown() ↑ (up-arrow is three unknown bytes)\n",
137 );
138 term.set_show_unknown(false);
139 assert!(!term.show_unknown());
140
141 term.append_utf8("Appending UTF8 array ↑ (up-arrow is visible)\n");
142 term.append_utf8_u8(b"Appending UTF8 array as u8 \xe2\x86\x91 (up-arrow is visible)\n");
143
144 let r = term.cursor_row();
145 assert_eq!(term.cursor_col(), 0);
146 term.append(&format!("Testing cursor row/col {r}"));
147 assert_eq!(term.cursor_col(), 24);
148 assert_eq!(term.cursor_row(), r);
149
150 assert_eq!(
152 term.cursor_bg_color(),
153 Color::XtermGreen,
154 "Default cursor bg at startup"
155 );
156 assert_eq!(
157 term.cursor_fg_color(),
158 Color::from_hex(0xff_ff_f0),
159 "Default cursor fg at startup"
160 );
161 term.set_cursor_bg_color(Color::Red);
162 assert_eq!(term.cursor_bg_color(), Color::Red);
163 assert_eq!(term.cursor_fg_color(), Color::from_hex(0xff_ff_f0));
164 term.set_cursor_fg_color(Color::Blue);
165 assert_eq!(term.cursor_bg_color(), Color::Red);
166 assert_eq!(term.cursor_fg_color(), Color::Blue);
167 term.set_cursor_bg_color(Color::XtermGreen); term.set_cursor_fg_color(Color::from_hex(0xff_ff_f0));
169 assert_eq!(term.cursor_bg_color(), Color::XtermGreen);
170 assert_eq!(term.cursor_fg_color(), Color::from_hex(0xff_ff_f0));
171
172 let dr = term.display_rows();
174 let height = term.height();
175 assert_eq!(height, term.h());
176 assert!(dr > 20, "Default display_rows at startup");
177 term.resize(term.x(), term.y(), term.w(), height * 2);
178 assert_eq!(term.h(), height * 2);
179 assert_eq!(height * 2, term.h());
180 assert!(term.display_rows() > dr);
181 term.resize(term.x(), term.y(), term.w(), height);
182
183 let dc = term.display_columns();
185 assert!(dc > 80, "Default display_rows at startup");
186 term.set_display_columns(200);
187 assert_eq!(term.display_columns(), 200);
188 term.append("\n 1 2 3 4 5 6 7 8 9");
189 term.append("\n123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890");
190 term.append("[This text should be truncated by display_columns() call below.]\n"); term.set_display_columns(90);
192 assert_eq!(term.display_columns(), 90);
193 term.set_display_columns(dc); assert_eq!(term.display_columns(), dc);
195
196 assert_eq!(term.history_rows(), 100, "Default history_rows at startup");
197 term.set_history_rows(50);
198 assert_eq!(term.history_rows(), 50);
199 term.set_history_rows(100); assert_eq!(term.history_rows(), 100);
201
202 let hu = term.history_use();
203 term.append(&format!(
204 "history_use = {hu} (it's not clear what this means)\n"
205 ));
206 term.append(&format!(
209 "margins = b:{} l:{} r:{} t{}\n",
210 term.margin_bottom(),
211 term.margin_left(),
212 term.margin_right(),
213 term.margin_top()
214 ));
215 assert_eq!(term.margin_bottom(), 3);
216 assert_eq!(term.margin_left(), 3);
217 assert_eq!(term.margin_right(), 3);
218 assert_eq!(term.margin_top(), 3);
219
220 term.set_margin_bottom(5);
221 term.set_margin_left(10);
222 term.set_margin_right(15);
223 term.set_margin_top(20);
224 assert_eq!(term.margin_bottom(), 5);
225 assert_eq!(term.margin_left(), 10);
226 assert_eq!(term.margin_right(), 15);
227 assert_eq!(term.margin_top(), 20);
228
229 term.append("Single character: '");
230 term.print_char('X');
231 term.append("', single UTF-8 character: '");
232 term.print_char_utf8('↑');
233 term.append("'\n");
234
235 let rr = term.redraw_rate();
236 assert_eq!(rr, 0.1, "Default redraw rate at startup");
237 term.append(&format!("Redraw rate {rr}\n"));
238 term.set_redraw_rate(1.0);
239 assert_eq!(term.redraw_rate(), 1.0);
240 term.set_redraw_rate(rr);
241 assert_eq!(term.redraw_rate(), rr);
242
243 let rs = term.redraw_style();
244 term.append(&format!("Redraw style {rs:?}\n"));
245 assert_eq!(
246 rs,
247 RedrawStyle::RateLimited,
248 "Default redraw style at startup"
249 );
250 term.set_redraw_style(RedrawStyle::NoRedraw);
251 assert_eq!(term.redraw_style(), RedrawStyle::NoRedraw);
252 term.set_redraw_style(rs);
253 assert_eq!(term.redraw_style(), rs);
254
255 assert_eq!(
257 RedrawStyle::NoRedraw.bits(),
258 0x0000,
259 "RedrawStyle enum values have been reassigned"
260 );
261 assert_eq!(
262 RedrawStyle::RateLimited.bits(),
263 0x0001,
264 "RedrawStyle enum values have been reassigned"
265 );
266 assert_eq!(
267 RedrawStyle::PerWrite.bits(),
268 0x0002,
269 "RedrawStyle enum values have been reassigned"
270 );
271
272 let sb = term.scrollbar();
273 let hsb = term.hscrollbar();
274 assert_eq!(sb.value(), 0.0);
276 assert_eq!(hsb.value(), 0.0);
277 term.set_hscrollbar_style(ScrollbarStyle::AUTO);
278
279 term.append(&format!(
280 "Scrollbar actual size {}\n",
281 term.scrollbar_actual_size()
282 ));
283 assert_eq!(term.scrollbar_actual_size(), 16);
284 term.append(&format!("Scrollbar size {}\n", term.scrollbar_size()));
285 assert_eq!(
286 term.scrollbar_size(),
287 0,
288 "Default scrollbar size at startup"
289 );
290 term.set_scrollbar_size(40);
291 assert_eq!(term.scrollbar_size(), 40);
292 assert_eq!(term.scrollbar_actual_size(), 40);
293 term.append(&format!(
294 "Scrollbar actual size {}\n",
295 term.scrollbar_actual_size()
296 ));
297 term.set_scrollbar_size(0); assert_eq!(term.scrollbar_size(), 0);
299 assert_eq!(term.scrollbar_actual_size(), 16);
300
301 let sfc = term.selection_fg_color();
302 let sbc = term.selection_bg_color();
303 assert_eq!(sfc, Color::Black);
304 assert_eq!(sbc, Color::White);
305 term.append(&format!("Selection colors: {sfc} {sbc}\n"));
306 term.set_selection_fg_color(Color::Green);
307 term.set_selection_bg_color(Color::DarkBlue);
308 assert_eq!(term.selection_fg_color(), Color::Green);
309 assert_eq!(term.selection_bg_color(), Color::DarkBlue);
310 term.set_selection_fg_color(sfc);
311 term.set_selection_bg_color(sbc);
312 assert_eq!(term.selection_fg_color(), Color::Black);
313 assert_eq!(term.selection_bg_color(), Color::White);
314
315 let tfcd = term.text_fg_color_default();
316 let tbcd = term.text_bg_color_default();
317 assert_eq!(tfcd, Color::XtermWhite);
318 assert_eq!(tbcd, Color::TransparentBg);
319 term.append(&format!("Default text colors: {sfc} {sbc}\n"));
320 term.set_text_fg_color_default(Color::Green);
321 term.set_text_bg_color_default(Color::DarkBlue);
322 assert_eq!(term.text_fg_color_default(), Color::Green);
323 assert_eq!(term.text_bg_color_default(), Color::DarkBlue);
324 term.set_text_fg_color_default(tfcd);
325 term.set_text_bg_color_default(tbcd);
326 assert_eq!(term.text_fg_color_default(), Color::XtermWhite);
327 assert_eq!(term.text_bg_color_default(), Color::TransparentBg);
328
329 let tfc = term.text_fg_color();
330 let tbc = term.text_bg_color();
331 assert_eq!(tfc, Color::XtermWhite);
332 assert_eq!(tbc, Color::TransparentBg);
333 term.append(&format!("Text colors: {sfc} {sbc}\n"));
334 term.set_text_fg_color(Color::Green);
335 term.set_text_bg_color(Color::DarkBlue);
336 assert_eq!(term.text_fg_color(), Color::Green);
337 assert_eq!(term.text_bg_color(), Color::DarkBlue);
338 term.set_text_fg_color(tfc);
339 term.set_text_bg_color(tbc);
340 assert_eq!(term.text_fg_color(), Color::XtermWhite);
341 assert_eq!(term.text_bg_color(), Color::TransparentBg);
342
343 let tf = term.text_font();
344 term.append(&format!("Text font: {tf:?}\n"));
345 assert_eq!(tf, Font::Courier);
346 term.set_text_font(Font::Screen);
347 assert_eq!(term.text_font(), Font::Screen);
348 term.set_text_font(tf);
349 assert_eq!(term.text_font(), Font::Courier);
350
351 let ts = term.text_size();
352 let r = term.h_to_row(100);
353 let c = term.w_to_col(100);
354 term.append(&format!(
355 "Text size: {ts}, h_to_row(100): {r}, w_to_col(100): {c}\n"
356 ));
357 assert_eq!(ts, 14);
358 term.set_text_size(30);
359 assert_eq!(term.text_size(), 30);
360 term.append(&format!(
361 "Text size: {}, h_to_row(100): {}, w_to_col(100): {}\n",
362 term.text_size(),
363 term.h_to_row(100),
364 term.w_to_col(100)
365 ));
366 term.set_text_size(ts);
367 assert_eq!(term.text_size(), ts);
368 term.append(&format!(
369 "Text size: {}, h_to_row(100): {}, w_to_col(100): {}\n",
370 term.text_size(),
371 term.h_to_row(100),
372 term.w_to_col(100)
373 ));
374
375 term.handle({
377 move |term, e| {
378 match e {
379 fltk::enums::Event::KeyDown
380 if fltk::app::event_key() == fltk::enums::Key::Escape =>
381 {
382 false
384 }
385
386 fltk::enums::Event::KeyDown
387 if fltk::app::event_length() == 1 && fltk::app::is_event_ctrl() =>
388 {
389 let k = fltk::app::event_text();
391 term.append_utf8(&k);
392 true
393 }
394
395 fltk::enums::Event::KeyDown
396 if fltk::app::event_length() == 1 && !fltk::app::is_event_alt() =>
397 {
398 let k = fltk::app::event_text();
400 term.take_focus().unwrap();
401 term.append(&k);
402 true
403 }
404
405 _ => false, }
413 }
414 });
415
416 let attr_save = term.text_attrib();
417 term.set_text_attrib(Attrib::Inverse | Attrib::Italic);
418 term.append("\nStartup tests complete. Keyboard is live.\n");
419 assert_eq!(term.text_attrib(), Attrib::Inverse | Attrib::Italic);
420 term.set_text_attrib(attr_save);
421 assert_eq!(term.text_attrib(), attr_save);
422 term.redraw();
423 }
424 });
425
426 app.run().unwrap();
427}
428fn mb_test1_cb(_choice: &mut fltk::menu::Choice, term: &mut Terminal) {
431 term.take_focus().unwrap();
432 term.reset_terminal();
433 term.append("0123456789 0\n");
434 term.append("0123456789 1\n");
435 term.append("0123456789 2\n");
436 term.append("0123456789 3\n");
437 term.append("0123456789 4\n");
438 term.append("0123456789 5\n");
439 term.append("0123456789 6\n");
440 term.append("0123456789 7\n");
441 term.append("0123456789 8\n");
442 term.append("0123456789 9\n");
443 term.append("------------\n");
444
445 term.set_text_fg_color(Color::Green);
446 term.plot_char('A', 0, 0);
447 term.plot_char('B', 1, 1);
448 term.plot_char('C', 2, 2);
449 term.plot_char('D', 3, 3);
450 term.plot_char('E', 4, 4);
451 term.plot_char('F', 5, 5);
452 term.set_text_fg_color(Color::XtermWhite);
453
454 assert_eq!(term.cursor_row(), 11);
455 assert_eq!(term.cursor_col(), 0);
456
457 term.set_text_bg_color(Color::DarkBlue);
458 term.plot_char_utf8('b', 8, 1);
459 term.plot_char_utf8('↑', 9, 1);
460 term.plot_char_utf8('c', 8, 2);
461 term.plot_char_utf8('↑', 9, 2);
462 term.plot_char_utf8('d', 8, 3);
463 term.plot_char_utf8('↑', 9, 3);
464 term.plot_char_utf8('e', 8, 4);
465 term.plot_char_utf8('↑', 9, 4);
466 term.plot_char_utf8('f', 8, 5);
467 term.plot_char_utf8('↑', 9, 5);
468 term.plot_char_utf8('g', 8, 6);
469 term.plot_char_utf8('↑', 9, 6);
470 term.set_text_bg_color(Color::TransparentBg);
471
472 term.set_text_attrib(Attrib::Inverse | Attrib::Italic);
473 term.append("Done!\n");
474 term.set_text_attrib(Attrib::Normal);
475}
476
477fn mb_test2_cb(_choice: &mut fltk::menu::Choice, term: &mut Terminal) {
480 term.take_focus().unwrap();
481 term.reset_terminal();
482
483 for i in 0..50 {
484 term.append(&format!("{i}\n"));
485 }
486 assert_eq!(term.history_rows(), 100);
487
488 term.clear_history();
489 assert_eq!(term.history_use(), 0);
490
491 term.set_text_attrib(Attrib::Inverse | Attrib::Italic);
492 term.append("\nDone!\n");
493 term.set_text_attrib(Attrib::Normal);
494}
495
496fn mb_test3_cb(_choice: &mut fltk::menu::Choice, term: &mut Terminal) {
499 term.take_focus().unwrap();
500 term.reset_terminal();
501 assert_eq!(term.text_bg_color_default(), Color::TransparentBg);
502
503 assert_eq!(term.history_use(), 0);
504 term.clear();
505 assert_eq!(term.cursor_row(), 0);
506 assert_eq!(term.history_use(), term.display_rows()); term.append("Test\ntext\na\nb\nc\nd");
509 assert_eq!(term.cursor_row(), 5);
510 let hist = term.history_use();
511 term.clear_screen_home(false);
512 assert_eq!(term.cursor_row(), 0);
513 assert_eq!(term.history_use(), hist); term.append("Test\ntext\na\nb\nc\nd\ne");
516 assert_eq!(term.cursor_row(), 6);
517 term.clear_screen_home(true);
518 assert_eq!(term.cursor_row(), 0);
519
520 term.append("Test\ntext\na\nb\nc\n");
521 assert_eq!(term.cursor_row(), 5);
522 term.clear_to_color(Color::DarkBlue);
523 assert_eq!(term.text_bg_color_default(), Color::TransparentBg);
524 assert_eq!(term.text_bg_color(), Color::TransparentBg);
525 assert_eq!(term.cursor_row(), 0);
526
527 term.append("Test\n\n\n\n\n\n\n\n\n\n");
529 assert_eq!(term.cursor_row(), 10);
530 term.cursor_home();
531 assert_eq!(term.cursor_row(), 0);
532
533 assert_eq!(term.color(), Color::Black); term.set_color(Color::DarkGreen);
536 assert_eq!(term.color(), Color::DarkGreen);
537 term.set_color(Color::Black);
538 assert_eq!(term.color(), Color::Black);
539 term.append(
540 "This should be one line of white text on black, embedded into the top of a blue field.\n",
541 );
542
543 assert_eq!(term.output_translate(), OutFlags::LF_TO_CRLF); term.set_output_translate(OutFlags::OFF);
545 assert_eq!(term.output_translate(), OutFlags::OFF);
546 term.set_output_translate(OutFlags::LF_TO_CRLF); assert_eq!(term.output_translate(), OutFlags::LF_TO_CRLF);
548
549 term.set_text_attrib(Attrib::Inverse | Attrib::Italic);
550 term.append("\nDone!\n");
551 term.set_text_attrib(Attrib::Normal);
552}
553
554fn mb_test4_cb(_choice: &mut fltk::menu::Choice, term: &mut Terminal) {
558 let sel_len = term.selection_text_len();
559 let sel = term.selection_text();
560
561 term.take_focus().unwrap();
562 term.reset_terminal();
563 let uc = Utf8Char::new(b'Q');
565 let uc1 = uc.text_utf8();
566 assert_eq!(&uc1, b"Q");
567 assert_eq!(&uc.attrib(), &Attrib::Normal);
568 assert_eq!(
569 &uc.charflags(),
570 &(CharFlags::FG_XTERM | CharFlags::BG_XTERM)
571 );
572 assert_eq!(&uc.fgcolor(), &Color::XtermWhite);
573 assert_eq!(&uc.bgcolor(), &Color::TransparentBg);
574
575 let ring_rows = term.ring_rows();
576
577 term.take_focus().unwrap();
578 term.clear_history();
579 assert_eq!(term.history_use(), 0);
580
581 fn row_diff(rows: i32, a: i32, b: i32) -> i32 {
583 match a - b {
584 n if n < 0 => n + rows,
585 n => n,
586 }
587 }
588 assert_eq!(row_diff(ring_rows, term.disp_srow(), term.hist_erow()), 1);
590 assert!(term.disp_srow() >= 0);
591 assert!(term.disp_erow() >= 0);
592 assert!(term.hist_srow() >= 0);
593 assert!(term.hist_erow() >= 0);
594 assert!(term.offset() >= 0);
595 assert!(term.disp_srow() <= ring_rows);
596 assert!(term.disp_erow() <= ring_rows);
597 assert!(term.hist_srow() <= ring_rows);
598 assert!(term.hist_erow() <= ring_rows);
599 assert!(term.offset() <= ring_rows);
600
601 assert_eq!(term.ring_srow(), 0);
602 assert_eq!(term.ring_erow(), ring_rows - 1);
603 assert_eq!(
604 row_diff(ring_rows, term.disp_erow(), term.disp_srow()) + 1,
605 term.display_rows()
606 );
607 assert_eq!(
608 row_diff(ring_rows, term.hist_erow(), term.hist_srow()) + 1,
609 term.history_rows()
610 );
611
612 assert_eq!(term.ring_erow(), term.ring_rows() - 1);
613 assert_eq!(term.ring_srow(), 0);
614
615 fn read_disp(term: &Terminal) -> String {
619 let rows = term.display_rows();
620 let mut text: Vec<u8> = Vec::with_capacity((rows * 64) as usize);
621 for row in 0..rows {
622 let r = term.u8c_disp_row(row).trim();
623 for c in r.iter() {
625 text.extend_from_slice(c.text_utf8());
627 }
628 text.extend_from_slice(b"\n");
629 }
630 std::str::from_utf8(&text).unwrap().to_string()
632 }
633
634 term.clear();
635 term.append("Top line ↑ (up-arrow)");
636 term.set_text_attrib(Attrib::Underline);
637 term.append(" ");
638 term.set_text_attrib(Attrib::Normal);
639 term.append(" \n");
640 let mut text_out = read_disp(term);
641 text_out = text_out.trim_end_matches(&"\n").to_string();
643 assert_eq!(text_out, "Top line ↑ (up-arrow) ");
646 let r = term.u8c_disp_row(0);
647 assert_eq!(r.col(0).text_utf8(), b"T");
648 assert_eq!(r.col(10).text_utf8(), b"\xe2\x86\x91"); assert_eq!(r.col(24).text_utf8(), b" "); let r = term.u8c_disp_row(1);
651 assert_eq!(r.col(0).text_utf8(), b" "); assert_eq!(r.col(1).text_utf8(), b" "); let test_text = "The wind was a torrent of darkness among the gusty trees.
656The moon was a ghostly galleon tossed upon cloudy seas.
657The road was a ribbon of moonlight over the purple moor,
658And the highwayman came riding—
659 Riding—riding—
660The highwayman came riding, up to the old inn-door.";
661
662 term.clear_history();
663 term.clear();
664 let bg_save = term.text_bg_color();
665 let fg_save = term.text_fg_color();
666 term.set_text_bg_color(Color::DarkBlue); term.set_text_fg_color(Color::from_rgb(0x40, 0x40, 0xff));
668 term.append(test_text);
669 term.set_text_bg_color(bg_save);
670 term.set_text_fg_color(fg_save);
671
672 let mut text_out = read_disp(term);
673 text_out = text_out.trim_end_matches(&"\n").to_string();
675 assert_eq!(test_text, text_out);
676
677 assert_eq!(row_diff(ring_rows, term.disp_srow(), term.hist_erow()), 1);
678
679 assert_eq!(term.ring_srow(), 0);
680 assert_eq!(term.ring_erow(), ring_rows - 1);
681 assert_eq!(
682 row_diff(ring_rows, term.disp_erow(), term.disp_srow()) + 1,
683 term.display_rows()
684 );
685 assert_eq!(
686 row_diff(ring_rows, term.hist_erow(), term.hist_srow()) + 1,
687 term.history_rows()
688 );
689
690 term.append(&format!(
691 "\n\nScreen has {} rows of {} columns.\n",
692 term.display_rows(),
693 term.display_columns()
694 ));
695
696 term.append(&format!("Selection len: {sel_len}\nSelection: '{sel}'\n"));
697}
698
699fn mb_test5_cb(_choice: &mut fltk::menu::Choice, term: &mut Terminal) {
703 term.take_focus().unwrap();
704
705 term.clear(); term.set_text_bg_color(Color::TransparentBg);
709 term.set_text_fg_color(Color::XtermWhite);
710 term.append("A");
711 let r = &term.u8c_disp_row(0);
712 let uc = r.col(0);
713 assert_eq!(uc.text_utf8(), b"A");
714 assert_eq!(&uc.attr_fgcolor(None), &Color::XtermWhite);
715 assert_eq!(&uc.attr_bgcolor(None), &Color::TransparentBg);
716 assert_eq!(&uc.attr_bgcolor(Some(term)), &Color::Black);
717 assert_eq!(&uc.attr_fgcolor(Some(term)), &Color::XtermWhite);
718 assert_eq!(&uc.attrib(), &Attrib::Normal);
719
720 term.clear();
722 term.set_text_fg_color_xterm(XtermColor::White);
723 term.set_text_bg_color_xterm(XtermColor::Black);
724 assert_eq!(term.text_attrib(), Attrib::Normal);
725
726 assert!(term.ansi());
727 term.append("B\x1b[32mC\x1b[1mD\n");
728
729 let r = &term.u8c_disp_row(0);
730 let uc = r.col(0);
731 assert_eq!(uc.text_utf8(), b"B");
732 assert!(uc.is_char(b'B'));
733 assert!(!uc.is_char(b'A'));
734 assert_eq!(&uc.fgcolor(), &Color::XtermWhite);
735 assert_eq!(&uc.bgcolor(), &Color::XtermBlack);
736 assert_eq!(&uc.attr_fgcolor(None), &Color::XtermWhite);
737 assert_eq!(&uc.attr_bgcolor(None), &Color::XtermBlack);
738 assert_eq!(
739 &uc.charflags(),
740 &(CharFlags::FG_XTERM | CharFlags::BG_XTERM)
741 );
742
743 let uc = r.col(1);
744 assert_eq!(uc.text_utf8(), b"C");
745 assert!(uc.is_char(b'C'));
746 assert_eq!(&uc.fgcolor(), &Color::XtermGreen);
747 assert_eq!(&uc.bgcolor(), &Color::XtermBlack);
748 assert_eq!(&uc.attr_fgcolor(None), &Color::XtermGreen);
749 assert_eq!(&uc.attr_bgcolor(None), &Color::XtermBlack);
750 assert_eq!(
751 &uc.charflags(),
752 &(CharFlags::FG_XTERM | CharFlags::BG_XTERM)
753 );
754
755 let uc = r.col(2);
756 assert_eq!(uc.text_utf8(), b"D");
757 assert!(uc.is_char(b'D'));
758 assert_eq!(&uc.fgcolor(), &Color::XtermGreen);
759 assert_eq!(&uc.bgcolor(), &Color::XtermBlack);
760 assert_eq!(&uc.attr_fgcolor(None), &Color::from_rgb(0x20, 0xf0, 0x20));
761 assert_eq!(&uc.attr_bgcolor(None), &Color::from_rgb(0x20, 0x20, 0x20));
762 assert_eq!(
763 &uc.attr_fgcolor(Some(term)),
764 &Color::from_rgb(0x20, 0xf0, 0x20)
765 );
766 assert_eq!(&uc.attr_bgcolor(None), &Color::from_rgb(0x20, 0x20, 0x20));
767 assert_eq!(
768 &uc.charflags(),
769 &(CharFlags::FG_XTERM | CharFlags::BG_XTERM)
770 );
771
772 term.clear();
774 term.set_text_fg_color_xterm(XtermColor::White);
775 term.set_text_bg_color_xterm(XtermColor::Black);
776 term.set_text_attrib(Attrib::Normal);
777 assert_eq!(term.text_attrib(), Attrib::Normal);
778
779 assert!(term.ansi());
780 term.append("B\x1b[37mC\x1b[44mD\x1b[1mE\n");
781
782 let r = &term.u8c_disp_row(0);
783 let uc = r.col(0);
784 assert_eq!(uc.text_utf8(), b"B");
785 assert!(uc.is_char(b'B'));
786 assert!(!uc.is_char(b'A'));
787 assert_eq!(&uc.fgcolor(), &Color::XtermWhite);
788 assert_eq!(&uc.bgcolor(), &Color::XtermBlack);
789 assert_eq!(&uc.attr_fgcolor(None), &Color::XtermWhite);
790 assert_eq!(&uc.attr_bgcolor(None), &Color::XtermBlack);
791 assert_eq!(
792 &uc.charflags(),
793 &(CharFlags::FG_XTERM | CharFlags::BG_XTERM)
794 );
795
796 let uc = r.col(1);
797 assert_eq!(uc.text_utf8(), b"C");
798 assert!(uc.is_char(b'C'));
799 assert_eq!(&uc.fgcolor(), &Color::XtermWhite);
800 assert_eq!(&uc.bgcolor(), &Color::XtermBlack);
801 assert_eq!(&uc.attr_fgcolor(None), &Color::XtermWhite);
802 assert_eq!(&uc.attr_bgcolor(None), &Color::XtermBlack);
803 assert_eq!(
804 &uc.charflags(),
805 &(CharFlags::FG_XTERM | CharFlags::BG_XTERM)
806 );
807
808 let uc = r.col(2);
809 assert_eq!(uc.text_utf8(), b"D");
810 assert!(uc.is_char(b'D'));
811 assert_eq!(&uc.fgcolor(), &Color::XtermWhite);
812 assert_eq!(&uc.bgcolor(), &Color::XtermBgBlue);
813 assert_eq!(&uc.attr_fgcolor(None), &Color::XtermWhite);
814 assert_eq!(&uc.attr_bgcolor(None), &Color::XtermBgBlue);
815 assert_eq!(
816 &uc.charflags(),
817 &(CharFlags::FG_XTERM | CharFlags::BG_XTERM)
818 );
819
820 let uc = r.col(3);
821 assert_eq!(uc.text_utf8(), b"E");
822 assert!(uc.is_char(b'E'));
823 assert_eq!(&uc.fgcolor(), &Color::XtermWhite);
824 assert_eq!(&uc.bgcolor(), &Color::XtermBgBlue);
825 assert_eq!(&uc.attr_fgcolor(None), &Color::from_hex(0xf0f0f0));
826 assert_eq!(&uc.attr_bgcolor(None), &Color::from_hex(0x2020e0));
827 assert_eq!(
828 &uc.charflags(),
829 &(CharFlags::FG_XTERM | CharFlags::BG_XTERM)
830 );
831
832 assert_eq!(uc.length(), 1);
834 assert_eq!(uc.max_utf8(), 4);
835 assert_eq!(uc.pwidth(), 9.0);
836 assert_eq!(uc.pwidth_int(), 9);
837
838 term.set_text_fg_color_xterm(XtermColor::White);
839 term.set_text_bg_color_xterm(XtermColor::Black);
840 term.clear();
841 term.set_text_attrib(Attrib::Normal);
842
843 term.append(&format!("Mouse selection: {:?}\n", &term.get_selection()));
845 term.clear_mouse_selection();
846 assert_eq!(term.get_selection(), None);
847
848 term.append("0123456789\n"); term.append("ABCDEFGHIJ\n");
851 term.append("abcdefghij\n");
852
853 term.set_cursor_row(1);
854 assert_eq!(term.cursor_row(), 1);
855 term.set_cursor_col(1);
856 assert_eq!(term.cursor_col(), 1);
857 assert_eq!(term.u8c_cursor().text_utf8(), b"1");
858
859 term.append("----"); assert_eq!(term.cursor_row(), 1);
861 assert_eq!(term.cursor_col(), 5);
862 assert_eq!(term.u8c_cursor().text_utf8(), b"5");
863 term.set_cursor_col(1);
864 assert_eq!(term.u8c_cursor().text_utf8(), b"-"); term.cursor_up(1, false);
867 assert_eq!(term.cursor_row(), 0);
868 assert_eq!(term.cursor_col(), 1);
869 assert_eq!(term.u8c_cursor().text_utf8(), b"o");
870
871 term.cursor_up(1, false);
873 assert_eq!(term.cursor_row(), 0);
874 assert_eq!(term.cursor_col(), 1);
875 assert_eq!(term.u8c_cursor().text_utf8(), b"o");
876
877 term.cursor_up(1, true);
879 assert_eq!(term.cursor_row(), 0);
880 assert_eq!(term.cursor_col(), 1);
881 assert_eq!(term.u8c_cursor().text_utf8(), b" ");
882
883 term.cursor_down(2, false);
885 assert_eq!(term.cursor_row(), 2);
886 assert_eq!(term.cursor_col(), 1);
887 assert_eq!(term.u8c_cursor().text_utf8(), b"-");
888
889 term.cursor_right(4, false);
891 assert_eq!(term.cursor_row(), 2);
892 assert_eq!(term.cursor_col(), 5);
893 assert_eq!(term.u8c_cursor().text_utf8(), b"5");
894
895 term.cursor_left(1);
897 assert_eq!(term.cursor_row(), 2);
898 assert_eq!(term.cursor_col(), 4);
899 assert_eq!(term.u8c_cursor().text_utf8(), b"-");
900
901 term.scroll(1);
904 assert_eq!(term.cursor_row(), 2);
905 assert_eq!(term.cursor_col(), 4);
906 assert_eq!(term.u8c_cursor().text_utf8(), b"E");
907
908 term.clear_eol();
910 assert_eq!(term.cursor_row(), 2);
911 assert_eq!(term.cursor_col(), 4);
912 assert_eq!(term.u8c_cursor().text_utf8(), b" ");
913
914 term.clear_sol();
916 assert_eq!(term.cursor_row(), 2);
917 assert_eq!(term.cursor_col(), 4);
918 assert_eq!(term.u8c_cursor().text_utf8(), b" ");
919 term.cursor_left(1);
920 assert_eq!(term.u8c_cursor().text_utf8(), b" ");
921 term.set_cursor_col(0);
922 assert_eq!(term.u8c_cursor().text_utf8(), b" ");
923
924 term.clear_line(1);
926 assert_eq!(term.cursor_row(), 2);
927 assert_eq!(term.cursor_col(), 0);
928 term.set_cursor_row(1);
929 assert_eq!(term.u8c_cursor().text_utf8(), b" ");
930 term.set_cursor_row(3);
931 term.clear_cur_line();
932 assert_eq!(term.u8c_cursor().text_utf8(), b" ");
933 assert_eq!(term.cursor_row(), 3);
934 assert_eq!(term.cursor_col(), 0);
935
936 term.append("Two lines above are intentionally left blank.\n");
937 assert_eq!(term.cursor_row(), 4);
938 assert_eq!(term.cursor_col(), 0);
939
940 term.append("0123456789\n");
942 term.append("ABCDEFGHIJ\n");
943 term.append("abcdefghij\n");
944 assert_eq!(term.cursor_row(), 7);
945
946 term.set_cursor_row(4);
947 term.set_cursor_col(4);
948 assert_eq!(term.u8c_cursor().text_utf8(), b"4");
949
950 term.insert_char('x', 5); assert_eq!(term.u8c_cursor().text_utf8(), b"x");
952 term.cursor_right(5, false);
953 assert_eq!(term.cursor_col(), 9);
954 assert_eq!(term.u8c_cursor().text_utf8(), b"4");
955
956 term.insert_rows(2);
958 assert_eq!(term.cursor_row(), 4);
959 assert_eq!(term.cursor_col(), 9);
960 assert_eq!(term.u8c_cursor().text_utf8(), b" ");
961 term.cursor_down(2, false); assert_eq!(term.u8c_cursor().text_utf8(), b"4");
963
964 term.cursor_left(5);
966 assert_eq!(term.u8c_cursor().text_utf8(), b"x");
967 term.delete_cur_chars(5);
968 assert_eq!(term.cursor_row(), 6);
969 assert_eq!(term.cursor_col(), 4);
970 assert_eq!(term.u8c_cursor().text_utf8(), b"4");
971
972 term.delete_chars(7, 2, 2); term.cursor_down(1, false);
974 term.cursor_left(2);
975 assert_eq!(term.u8c_cursor().text_utf8(), b"E");
976
977 term.delete_rows(1); assert_eq!(term.u8c_cursor().text_utf8(), b"c");
979 term.cursor_up(1, false);
980 term.delete_rows(2); term.set_text_attrib(Attrib::Bold);
983 term.insert_char_eol('-', 3, 15, 20);
984 term.set_cursor_row(3);
985 term.set_cursor_col(15);
986 assert_eq!(term.u8c_cursor().text_utf8(), b"-"); assert_eq!(term.u8c_cursor().attrib(), Attrib::Bold);
988
989 term.set_text_attrib(Attrib::Italic);
990 term.append(" and all lines below");
991 term.set_text_attrib(Attrib::Normal);
992 term.cursor_down(1, false);
993
994 let mut hsb = term.hscrollbar();
995 let mut sb = term.scrollbar();
996 hsb.set_value(100.0);
997 assert_eq!(hsb.value(), 100.0);
998 sb.set_value(50.0);
999 assert_eq!(sb.value(), 50.0);
1000 hsb.set_value(0.0);
1001 assert_eq!(hsb.value(), 0.0);
1002 sb.set_value(0.0);
1003 assert_eq!(sb.value(), 0.0);
1004}
1005
1006fn error_box(msg: String) {
1012 fltk::app::lock().unwrap();
1013 fltk::dialog::message_title("Error");
1014 fltk::dialog::message_set_hotspot(true);
1015 fltk::dialog::message_icon_label("!");
1016 fltk::dialog::message_default(&msg);
1017 fltk::app::unlock();
1018}