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!(
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 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 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); assert_eq!(term.hscrollbar_style(), ScrollbarStyle::AUTO);
132 term.set_hscrollbar_style(ScrollbarStyle::ON);
133 assert_eq!(term.hscrollbar_style(), ScrollbarStyle::ON);
134
135 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 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); 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 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 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"); term.set_display_columns(90);
189 assert_eq!(term.display_columns(), 90);
190 term.set_display_columns(dc); 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); 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 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 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 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); 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 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
381 }
382
383 fltk::enums::Event::KeyDown
384 if fltk::app::event_length() == 1 && fltk::app::is_event_ctrl() =>
385 {
386 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 let k = fltk::app::event_text().unwrap();
397 term.take_focus().unwrap();
398 term.append(&k);
399 true
400 }
401
402 _ => false, }
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}
425fn 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
474fn 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
493fn 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()); 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); 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 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 assert_eq!(term.color(), Color::Black); 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); term.set_output_translate(OutFlags::OFF);
542 assert_eq!(term.output_translate(), OutFlags::OFF);
543 term.set_output_translate(OutFlags::LF_TO_CRLF); 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
551fn 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 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 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 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 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 for c in r.iter() {
622 text.extend_from_slice(c.text_utf8());
624 }
625 text.extend_from_slice(b"\n");
626 }
627 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 text_out = text_out.trim_end_matches(&"\n").to_string();
640 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"); assert_eq!(r.col(24).text_utf8(), b" "); let r = term.u8c_disp_row(1);
648 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.
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); 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 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
696fn mb_test5_cb(_choice: &mut fltk::menu::Choice, term: &mut Terminal) {
700 term.take_focus().unwrap();
701
702 term.clear(); 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 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 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 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 term.append(&format!("Mouse selection: {:?}\n", &term.get_selection()));
842 term.clear_mouse_selection();
843 assert_eq!(term.get_selection(), None);
844
845 term.append("0123456789\n"); 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("----"); 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"-"); 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 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 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 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 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 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 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 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 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 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 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); 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 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); assert_eq!(term.u8c_cursor().text_utf8(), b"4");
960
961 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); 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); assert_eq!(term.u8c_cursor().text_utf8(), b"c");
976 term.cursor_up(1, false);
977 term.delete_rows(2); 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"-"); 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}
1002
1003fn error_box(msg: String) {
1009 fltk::app::lock().unwrap();
1010 fltk::dialog::message_title("Error");
1011 fltk::dialog::message_set_hotspot(true);
1012 fltk::dialog::message_icon_label("!");
1013 fltk::dialog::message(&msg);
1014 fltk::app::unlock();
1015}