1 use crate::{ 2 driver::uart::uart_device::{c_uart_send, c_uart_send_str, UartPort}, 3 include::bindings::bindings::video_frame_buffer_info, 4 kinfo, 5 libs::{lib_ui::font::FONT_8x16, spinlock::SpinLock}, 6 syscall::SystemError, 7 }; 8 use alloc::{boxed::Box, collections::LinkedList, string::ToString}; 9 use alloc::{sync::Arc, vec::Vec}; 10 use core::{ 11 fmt::Debug, 12 intrinsics::unlikely, 13 ops::{Add, AddAssign, Sub}, 14 sync::atomic::{AtomicBool, AtomicI32, AtomicU32, Ordering}, 15 }; 16 17 use super::{ 18 screen_manager::{ 19 scm_register, ScmBufferInfo, ScmFramworkType, ScmUiFramework, ScmUiFrameworkMetadata, 20 }, 21 textui_no_alloc::no_init_textui_putchar_window, 22 }; 23 24 /// 声明全局的TEXTUI_FRAMEWORK 25 static mut __TEXTUI_FRAMEWORK: Option<Box<TextUiFramework>> = None; 26 27 /// 每个字符的宽度和高度(像素) 28 pub const TEXTUI_CHAR_WIDTH: u32 = 8; 29 30 pub const TEXTUI_CHAR_HEIGHT: u32 = 16; 31 32 pub static mut TEXTUI_IS_INIT: bool = false; 33 34 pub static ENABLE_PUT_TO_WINDOW: AtomicBool = AtomicBool::new(true); 35 36 /// 获取TEXTUI_FRAMEWORK的可变实例 37 pub fn textui_framework() -> &'static mut TextUiFramework { 38 return unsafe { __TEXTUI_FRAMEWORK.as_mut().unwrap() }; 39 } 40 /// 初始化TEXTUI_FRAMEWORK 41 pub unsafe fn textui_framwork_init() { 42 if __TEXTUI_FRAMEWORK.is_none() { 43 kinfo!("textuiframework init"); 44 let metadata = ScmUiFrameworkMetadata::new("TextUI".to_string(), ScmFramworkType::Text); 45 // 为textui框架生成第一个窗口 46 let vlines_num = (metadata.buf_info().buf_height() / TEXTUI_CHAR_HEIGHT) as usize; 47 48 let chars_num = (metadata.buf_info().buf_width() / TEXTUI_CHAR_WIDTH) as usize; 49 50 let initial_window = TextuiWindow::new( 51 WindowFlag::TEXTUI_CHROMATIC, 52 vlines_num as i32, 53 chars_num as i32, 54 ); 55 56 let current_window: Arc<SpinLock<TextuiWindow>> = Arc::new(SpinLock::new(initial_window)); 57 58 let default_window = current_window.clone(); 59 60 // 生成窗口链表,并把上面窗口添加进textui框架的窗口链表中 61 let window_list: Arc<SpinLock<LinkedList<Arc<SpinLock<TextuiWindow>>>>> = 62 Arc::new(SpinLock::new(LinkedList::new())); 63 window_list.lock().push_back(current_window.clone()); 64 65 __TEXTUI_FRAMEWORK = Some(Box::new(TextUiFramework::new( 66 metadata, 67 window_list, 68 current_window, 69 default_window, 70 ))); 71 } else { 72 panic!("Try to init TEXTUI_FRAMEWORK twice!"); 73 } 74 } 75 // window标志位 76 bitflags! { 77 pub struct WindowFlag: u8 { 78 // 采用彩色字符 79 const TEXTUI_CHROMATIC = 1 << 0; 80 } 81 } 82 83 /** 84 * @brief 黑白字符对象 85 * 86 */ 87 #[derive(Clone, Debug)] 88 struct TextuiCharNormal { 89 _data: u8, 90 } 91 92 #[derive(Debug, Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash, Default)] 93 pub struct LineId(i32); 94 impl LineId { 95 pub fn new(num: i32) -> Self { 96 LineId(num) 97 } 98 99 pub fn check(&self, max: i32) -> bool { 100 self.0 < max && self.0 >= 0 101 } 102 103 pub fn data(&self) -> i32 { 104 self.0 105 } 106 } 107 impl Add<i32> for LineId { 108 type Output = LineId; 109 fn add(self, rhs: i32) -> Self::Output { 110 LineId::new(self.0 + rhs) 111 } 112 } 113 impl Sub<i32> for LineId { 114 type Output = LineId; 115 116 fn sub(self, rhs: i32) -> Self::Output { 117 LineId::new(self.0 - rhs) 118 } 119 } 120 121 impl Into<i32> for LineId { 122 fn into(self) -> i32 { 123 self.0.clone() 124 } 125 } 126 impl Into<u32> for LineId { 127 fn into(self) -> u32 { 128 self.0.clone() as u32 129 } 130 } 131 impl Into<usize> for LineId { 132 fn into(self) -> usize { 133 self.0.clone() as usize 134 } 135 } 136 impl Sub<LineId> for LineId { 137 type Output = LineId; 138 139 fn sub(mut self, rhs: LineId) -> Self::Output { 140 self.0 -= rhs.0; 141 return self; 142 } 143 } 144 impl AddAssign<LineId> for LineId { 145 fn add_assign(&mut self, rhs: LineId) { 146 self.0 += rhs.0; 147 } 148 } 149 #[derive(Debug, Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash, Default)] 150 pub struct LineIndex(i32); 151 impl LineIndex { 152 pub fn new(num: i32) -> Self { 153 LineIndex(num) 154 } 155 pub fn check(&self, chars_per_line: i32) -> bool { 156 self.0 < chars_per_line && self.0 >= 0 157 } 158 } 159 impl Add<LineIndex> for LineIndex { 160 type Output = LineIndex; 161 162 fn add(self, rhs: LineIndex) -> Self::Output { 163 LineIndex::new(self.0 + rhs.0) 164 } 165 } 166 impl Add<i32> for LineIndex { 167 // type Output = Self; 168 type Output = LineIndex; 169 170 fn add(self, rhs: i32) -> Self::Output { 171 LineIndex::new(self.0 + rhs) 172 } 173 } 174 impl Sub<i32> for LineIndex { 175 type Output = LineIndex; 176 177 fn sub(self, rhs: i32) -> Self::Output { 178 LineIndex::new(self.0 - rhs) 179 } 180 } 181 182 impl Into<i32> for LineIndex { 183 fn into(self) -> i32 { 184 self.0.clone() 185 } 186 } 187 impl Into<u32> for LineIndex { 188 fn into(self) -> u32 { 189 self.0.clone() as u32 190 } 191 } 192 impl Into<usize> for LineIndex { 193 fn into(self) -> usize { 194 self.0.clone() as usize 195 } 196 } 197 #[derive(Copy, Clone, Debug)] 198 pub struct FontColor(u32); 199 #[allow(dead_code)] 200 impl FontColor { 201 pub const BLUE: FontColor = FontColor::new(0, 0, 0xff); 202 pub const RED: FontColor = FontColor::new(0xff, 0, 0); 203 pub const GREEN: FontColor = FontColor::new(0, 0xff, 0); 204 pub const WHITE: FontColor = FontColor::new(0xff, 0xff, 0xff); 205 pub const BLACK: FontColor = FontColor::new(0, 0, 0); 206 pub const YELLOW: FontColor = FontColor::new(0xff, 0xff, 0); 207 pub const ORANGE: FontColor = FontColor::new(0xff, 0x80, 0); 208 pub const INDIGO: FontColor = FontColor::new(0x00, 0xff, 0xff); 209 pub const PURPLE: FontColor = FontColor::new(0x80, 0x00, 0xff); 210 211 pub const fn new(r: u8, g: u8, b: u8) -> Self { 212 let val = ((r as u32) << 16) | ((g as u32) << 8) | (b as u32); 213 return FontColor(val & 0x00ffffff); 214 } 215 } 216 217 impl From<u32> for FontColor { 218 fn from(value: u32) -> Self { 219 return Self(value & 0x00ffffff); 220 } 221 } 222 impl Into<usize> for FontColor { 223 fn into(self) -> usize { 224 self.0.clone() as usize 225 } 226 } 227 impl Into<u32> for FontColor { 228 fn into(self) -> u32 { 229 self.0.clone() 230 } 231 } 232 impl Into<u16> for FontColor { 233 fn into(self) -> u16 { 234 self.0.clone() as u16 235 } 236 } 237 impl Into<u64> for FontColor { 238 fn into(self) -> u64 { 239 self.0.clone() as u64 240 } 241 } 242 243 /// 彩色字符对象 244 245 #[derive(Clone, Debug, Copy)] 246 pub struct TextuiCharChromatic { 247 c: Option<char>, 248 249 // 前景色 250 frcolor: FontColor, // rgb 251 252 // 背景色 253 bkcolor: FontColor, // rgb 254 } 255 256 #[derive(Debug)] 257 pub struct TextuiBuf<'a>(&'a mut [u32]); 258 259 impl TextuiBuf<'_> { 260 pub fn new(buf: &mut [u32]) -> TextuiBuf { 261 TextuiBuf(buf) 262 } 263 pub fn put_color_in_pixel(&mut self, color: u32, index: usize) { 264 let buf: &mut [u32] = self.0; 265 buf[index] = color; 266 } 267 pub fn get_index_of_next_line(now_index: usize) -> usize { 268 textui_framework().metadata.buf_info().buf_width() as usize + now_index 269 } 270 pub fn get_index_by_x_y(x: usize, y: usize) -> usize { 271 textui_framework().metadata.buf_info().buf_width() as usize * y + x 272 } 273 pub fn get_start_index_by_lineid_lineindex(lineid: LineId, lineindex: LineIndex) -> usize { 274 // x 左上角列像素点位置 275 // y 左上角行像素点位置 276 let index_x: u32 = lineindex.into(); 277 let x: u32 = index_x * TEXTUI_CHAR_WIDTH; 278 279 let id_y: u32 = lineid.into(); 280 let y: u32 = id_y * TEXTUI_CHAR_HEIGHT; 281 282 TextuiBuf::get_index_by_x_y(x as usize, y as usize) 283 } 284 } 285 286 #[derive(Debug, Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)] 287 pub struct Font([u8; 16]); 288 impl Font { 289 #[inline] 290 pub fn get_font(character: char) -> Font { 291 let x = FONT_8x16.char_map(character); 292 293 let mut data = [0u8; 16]; 294 data.copy_from_slice(x); 295 return Font(data); 296 } 297 pub fn is_frcolor(&self, height: usize, width: usize) -> bool { 298 let w = self.0[height]; 299 let testbit = 1 << (8 - width); 300 w & testbit != 0 301 } 302 } 303 304 impl TextuiCharChromatic { 305 pub fn new(c: Option<char>, frcolor: FontColor, bkcolor: FontColor) -> Self { 306 TextuiCharChromatic { 307 c, 308 frcolor, 309 bkcolor, 310 } 311 } 312 313 /// 将该字符对象输出到缓冲区 314 /// ## 参数 315 /// -line_id 要放入的真实行号 316 /// -index 要放入的真实列号 317 pub fn textui_refresh_character( 318 &self, 319 lineid: LineId, 320 lineindex: LineIndex, 321 ) -> Result<i32, SystemError> { 322 // 找到要渲染的字符的像素点数据 323 324 let font: Font = Font::get_font(self.c.unwrap_or(' ')); 325 326 let mut count = TextuiBuf::get_start_index_by_lineid_lineindex(lineid, lineindex); 327 328 let mut buf = TextuiBuf::new(textui_framework().metadata.buf()); 329 // 在缓冲区画出一个字体,每个字体有TEXTUI_CHAR_HEIGHT行,TEXTUI_CHAR_WIDTH列个像素点 330 for i in 0..TEXTUI_CHAR_HEIGHT { 331 let start = count; 332 for j in 0..TEXTUI_CHAR_WIDTH { 333 if font.is_frcolor(i as usize, j as usize) { 334 // 字,显示前景色 335 buf.put_color_in_pixel(self.frcolor.into(), count); 336 } else { 337 // 背景色 338 buf.put_color_in_pixel(self.bkcolor.into(), count); 339 } 340 count += 1; 341 } 342 count = TextuiBuf::get_index_of_next_line(start); 343 } 344 345 return Ok(0); 346 } 347 348 pub fn no_init_textui_render_chromatic(&self, lineid: LineId, lineindex: LineIndex) { 349 // 找到要渲染的字符的像素点数据 350 let font = Font::get_font(self.c.unwrap_or(' ')); 351 352 // x 左上角列像素点位置 353 // y 左上角行像素点位置 354 let index_x: u32 = lineindex.into(); 355 let x: u32 = index_x * TEXTUI_CHAR_WIDTH; 356 357 let id_y: u32 = lineid.into(); 358 let y: u32 = id_y * TEXTUI_CHAR_HEIGHT; 359 // 找到输入缓冲区的起始地址位置 360 let fb = unsafe { video_frame_buffer_info.vaddr }; 361 362 let mut testbit: u32; // 用来测试特定行的某列是背景还是字体本身 363 364 // 在缓冲区画出一个字体,每个字体有TEXTUI_CHAR_HEIGHT行,TEXTUI_CHAR_WIDTH列个像素点 365 for i in 0..TEXTUI_CHAR_HEIGHT { 366 // 计算出帧缓冲区每一行打印的起始位置的地址(起始位置+(y+i)*缓冲区的宽度+x) 367 368 let mut addr: *mut u32 = (fb 369 + unsafe { video_frame_buffer_info.width } as u64 * 4 * (y as u64 + i as u64) 370 + 4 * x as u64) as *mut u32; 371 372 testbit = 1 << (TEXTUI_CHAR_WIDTH + 1); 373 374 for _j in 0..TEXTUI_CHAR_WIDTH { 375 //从左往右逐个测试相应位 376 testbit >>= 1; 377 if (font.0[i as usize] & testbit as u8) != 0 { 378 unsafe { *addr = self.frcolor.into() }; // 字,显示前景色 379 } else { 380 unsafe { *addr = self.bkcolor.into() }; // 背景色 381 } 382 383 unsafe { 384 addr = (addr.offset(1)) as *mut u32; 385 } 386 } 387 } 388 } 389 } 390 391 /// 单色显示的虚拟行结构体 392 393 #[derive(Clone, Debug, Default)] 394 pub struct TextuiVlineNormal { 395 _characters: Vec<TextuiCharNormal>, // 字符对象数组 396 _index: i16, // 当前操作的位置 397 } 398 /// 彩色显示的虚拟行结构体 399 400 #[derive(Clone, Debug, Default)] 401 pub struct TextuiVlineChromatic { 402 chars: Vec<TextuiCharChromatic>, // 字符对象数组 403 index: LineIndex, // 当前操作的位置 404 } 405 impl TextuiVlineChromatic { 406 pub fn new(char_num: usize) -> Self { 407 let mut r = TextuiVlineChromatic { 408 chars: Vec::with_capacity(char_num), 409 index: LineIndex::new(0), 410 }; 411 412 for _ in 0..char_num { 413 r.chars.push(TextuiCharChromatic::new( 414 None, 415 FontColor::BLACK, 416 FontColor::BLACK, 417 )); 418 } 419 420 return r; 421 } 422 } 423 424 #[derive(Clone, Debug)] 425 pub enum TextuiVline { 426 Chromatic(TextuiVlineChromatic), 427 _Normal(TextuiVlineNormal), 428 } 429 430 #[derive(Debug, Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)] 431 pub struct WindowId(u32); 432 433 impl WindowId { 434 pub fn new() -> Self { 435 static MAX_ID: AtomicU32 = AtomicU32::new(0); 436 return WindowId(MAX_ID.fetch_add(1, Ordering::SeqCst)); 437 } 438 } 439 #[allow(dead_code)] 440 #[derive(Clone, Debug)] 441 pub struct TextuiWindow { 442 // 虚拟行是个循环表,头和尾相接 443 id: WindowId, 444 // 虚拟行总数 445 vline_sum: i32, 446 // 当前已经使用了的虚拟行总数(即在已经输入到缓冲区(之后显示在屏幕上)的虚拟行数量) 447 vlines_used: i32, 448 // 位于最顶上的那一个虚拟行的行号 449 top_vline: LineId, 450 // 储存虚拟行的数组 451 vlines: Vec<TextuiVline>, 452 // 正在操作的vline 453 vline_operating: LineId, 454 // 每行最大容纳的字符数 455 chars_per_line: i32, 456 // 窗口flag 457 flags: WindowFlag, 458 } 459 460 impl TextuiWindow { 461 /// 使用参数初始化window对象 462 /// ## 参数 463 /// 464 /// -flags 标志位 465 /// -vlines_num 虚拟行的总数 466 /// -chars_num 每行最大的字符数 467 468 pub fn new(flags: WindowFlag, vlines_num: i32, chars_num: i32) -> Self { 469 let mut initial_vlines = Vec::new(); 470 471 for _ in 0..vlines_num { 472 let vline = TextuiVlineChromatic::new(chars_num as usize); 473 474 initial_vlines.push(TextuiVline::Chromatic(vline)); 475 } 476 TextuiWindow { 477 id: WindowId::new(), 478 flags, 479 vline_sum: vlines_num, 480 vlines_used: 1, 481 top_vline: LineId::new(0), 482 vlines: initial_vlines, 483 vline_operating: LineId::new(0), 484 chars_per_line: chars_num, 485 } 486 } 487 488 /// 刷新某个窗口的缓冲区的某个虚拟行的连续n个字符对象 489 /// ## 参数 490 /// - window 窗口结构体 491 /// - vline_id 要刷新的虚拟行号 492 /// - start 起始字符号 493 /// - count 要刷新的字符数量 494 495 fn textui_refresh_characters( 496 &mut self, 497 vline_id: LineId, 498 start: LineIndex, 499 count: i32, 500 ) -> Result<(), SystemError> { 501 let actual_line_sum = textui_framework().actual_line.load(Ordering::SeqCst); 502 503 // 判断虚拟行参数是否合法 504 if unlikely( 505 !vline_id.check(self.vline_sum) 506 || (<LineIndex as Into<i32>>::into(start) + count) > self.chars_per_line, 507 ) { 508 return Err(SystemError::EINVAL); 509 } 510 // 计算虚拟行对应的真实行(即要渲染的行) 511 let mut actual_line_id = vline_id - self.top_vline; //为正说明虚拟行不在真实行显示的区域上面 512 513 if <LineId as Into<i32>>::into(actual_line_id) < 0 { 514 //真实行数小于虚拟行数,则需要加上真实行数的位置,以便正确计算真实行 515 actual_line_id = actual_line_id + actual_line_sum; 516 } 517 518 // 将此窗口的某个虚拟行的连续n个字符对象往缓存区写入 519 if self.flags.contains(WindowFlag::TEXTUI_CHROMATIC) { 520 let vline = &mut self.vlines[<LineId as Into<usize>>::into(vline_id)]; 521 let mut i = 0; 522 let mut index = start; 523 524 while i < count { 525 if let TextuiVline::Chromatic(vline) = vline { 526 vline.chars[<LineIndex as Into<usize>>::into(index)] 527 .textui_refresh_character(actual_line_id, index)?; 528 529 index = index + 1; 530 } 531 i += 1; 532 } 533 } 534 535 return Ok(()); 536 } 537 538 /// 重新渲染某个窗口的某个虚拟行 539 /// ## 参数 540 541 /// - window 窗口结构体 542 /// - vline_id 虚拟行号 543 544 fn textui_refresh_vline(&mut self, vline_id: LineId) -> Result<(), SystemError> { 545 if self.flags.contains(WindowFlag::TEXTUI_CHROMATIC) { 546 return self.textui_refresh_characters( 547 vline_id, 548 LineIndex::new(0), 549 self.chars_per_line, 550 ); 551 } else { 552 //todo支持纯文本字符() 553 todo!(); 554 } 555 } 556 557 // 刷新某个窗口的start 到start + count行(即将这些行输入到缓冲区) 558 fn textui_refresh_vlines(&mut self, start: LineId, count: i32) -> Result<i32, SystemError> { 559 let mut refresh_count = count; 560 for i in <LineId as Into<i32>>::into(start) 561 ..(self.vline_sum).min(<LineId as Into<i32>>::into(start) + count) 562 { 563 self.textui_refresh_vline(LineId::new(i))?; 564 refresh_count -= 1; 565 } 566 //因为虚拟行是循环表 567 let mut refresh_start = 0; 568 while refresh_count > 0 { 569 self.textui_refresh_vline(LineId::new(refresh_start))?; 570 refresh_start += 1; 571 refresh_count -= 1; 572 } 573 return Ok(0); 574 } 575 576 /// 往某个窗口的缓冲区的某个虚拟行插入换行 577 /// ## 参数 578 /// - window 窗口结构体 579 /// - vline_id 虚拟行号 580 581 fn textui_new_line(&mut self) -> Result<i32, SystemError> { 582 // todo: 支持在两个虚拟行之间插入一个新行 583 let actual_line_sum = textui_framework().actual_line.load(Ordering::SeqCst); 584 self.vline_operating = self.vline_operating + 1; 585 //如果已经到了最大行数,则重新从0开始 586 if !self.vline_operating.check(self.vline_sum) { 587 self.vline_operating = LineId::new(0); 588 } 589 590 if let TextuiVline::Chromatic(vline) = 591 &mut (self.vlines[<LineId as Into<usize>>::into(self.vline_operating)]) 592 { 593 for i in 0..self.chars_per_line { 594 if let Some(v_char) = vline.chars.get_mut(i as usize) { 595 v_char.c = None; 596 v_char.frcolor = FontColor::BLACK; 597 v_char.bkcolor = FontColor::BLACK; 598 } 599 } 600 vline.index = LineIndex::new(0); 601 } 602 // 当已经使用的虚拟行总数等于真实行总数时,说明窗口中已经显示的文本行数已经达到了窗口的最大容量。这时,如果继续在窗口中添加新的文本,就会导致文本溢出窗口而无法显示。因此,需要往下滚动屏幕来显示更多的文本。 603 604 if self.vlines_used == actual_line_sum { 605 self.top_vline = self.top_vline + 1; 606 607 if !self.top_vline.check(self.vline_sum) { 608 self.top_vline = LineId::new(0); 609 } 610 611 // 刷新所有行 612 self.textui_refresh_vlines(self.top_vline, actual_line_sum)?; 613 } else { 614 //换行说明上一行已经在缓冲区中,所以已经使用的虚拟行总数+1 615 self.vlines_used += 1; 616 } 617 618 return Ok(0); 619 } 620 621 /// 真正向窗口的缓冲区上输入字符的函数(位置为window.vline_operating,window.vline_operating.index) 622 /// ## 参数 623 /// - window 624 /// - character 625 626 fn true_textui_putchar_window( 627 &mut self, 628 character: char, 629 frcolor: FontColor, 630 bkcolor: FontColor, 631 ) -> Result<(), SystemError> { 632 // 启用彩色字符 633 if self.flags.contains(WindowFlag::TEXTUI_CHROMATIC) { 634 let mut line_index = LineIndex::new(0); //操作的列号 635 if let TextuiVline::Chromatic(vline) = 636 &mut (self.vlines[<LineId as Into<usize>>::into(self.vline_operating)]) 637 { 638 let index = <LineIndex as Into<usize>>::into(vline.index); 639 640 if let Some(v_char) = vline.chars.get_mut(index) { 641 v_char.c = Some(character); 642 v_char.frcolor = frcolor; 643 v_char.bkcolor = bkcolor; 644 } 645 line_index = vline.index; 646 vline.index = vline.index + 1; 647 } 648 649 self.textui_refresh_characters(self.vline_operating, line_index, 1)?; 650 651 // 加入光标后,因为会识别光标,所以需超过该行最大字符数才能创建新行 652 if !line_index.check(self.chars_per_line - 1) { 653 self.textui_new_line()?; 654 } 655 } else { 656 // todo: 支持纯文本字符 657 todo!(); 658 } 659 return Ok(()); 660 } 661 /// 根据输入的一个字符在窗口上输出 662 /// ## 参数 663 664 /// - window 窗口 665 /// - character 字符 666 /// - FRcolor 前景色(RGB) 667 /// - BKcolor 背景色(RGB) 668 669 fn textui_putchar_window( 670 &mut self, 671 character: char, 672 frcolor: FontColor, 673 bkcolor: FontColor, 674 is_enable_window: bool, 675 ) -> Result<(), SystemError> { 676 let actual_line_sum = textui_framework().actual_line.load(Ordering::SeqCst); 677 678 //字符'\0'代表ASCII码表中的空字符,表示字符串的结尾 679 if unlikely(character == '\0') { 680 return Ok(()); 681 } 682 683 if unlikely(character == '\r') { 684 return Ok(()); 685 } 686 687 // 暂不支持纯文本窗口 688 if !self.flags.contains(WindowFlag::TEXTUI_CHROMATIC) { 689 return Ok(()); 690 } 691 692 //进行换行操作 693 if character == '\n' { 694 // 换行时还需要输出\r 695 c_uart_send(UartPort::COM1.to_u16(), b'\r'); 696 if is_enable_window == true { 697 self.textui_new_line()?; 698 } 699 return Ok(()); 700 } 701 // 输出制表符 702 else if character == '\t' { 703 if is_enable_window == true { 704 if let TextuiVline::Chromatic(vline) = 705 &self.vlines[<LineId as Into<usize>>::into(self.vline_operating)] 706 { 707 //打印的空格数(注意将每行分成一个个表格,每个表格为8个字符) 708 let mut space_to_print = 8 - <LineIndex as Into<usize>>::into(vline.index) % 8; 709 while space_to_print > 0 { 710 self.true_textui_putchar_window(' ', frcolor, bkcolor)?; 711 space_to_print -= 1; 712 } 713 } 714 } 715 } 716 // 字符 '\x08' 代表 ASCII 码中的退格字符。它在输出中的作用是将光标向左移动一个位置,并在该位置上输出后续的字符,从而实现字符的删除或替换。 717 else if character == '\x08' { 718 if is_enable_window == true { 719 let mut tmp = LineIndex(0); 720 if let TextuiVline::Chromatic(vline) = 721 &mut self.vlines[<LineId as Into<usize>>::into(self.vline_operating)] 722 { 723 vline.index = vline.index - 1; 724 tmp = vline.index; 725 } 726 if <LineIndex as Into<i32>>::into(tmp) >= 0 { 727 if let TextuiVline::Chromatic(vline) = 728 &mut self.vlines[<LineId as Into<usize>>::into(self.vline_operating)] 729 { 730 if let Some(v_char) = 731 vline.chars.get_mut(<LineIndex as Into<usize>>::into(tmp)) 732 { 733 v_char.c = Some(' '); 734 735 v_char.bkcolor = bkcolor; 736 } 737 } 738 return self.textui_refresh_characters(self.vline_operating, tmp, 1); 739 } 740 // 需要向上缩一行 741 if <LineIndex as Into<i32>>::into(tmp) < 0 { 742 // 当前行为空,需要重新刷新 743 if let TextuiVline::Chromatic(vline) = 744 &mut self.vlines[<LineId as Into<usize>>::into(self.vline_operating)] 745 { 746 vline.index = LineIndex::new(0); 747 for i in 0..self.chars_per_line { 748 if let Some(v_char) = vline.chars.get_mut(i as usize) { 749 v_char.c = None; 750 v_char.frcolor = FontColor::BLACK; 751 v_char.bkcolor = FontColor::BLACK; 752 } 753 } 754 } 755 // 上缩一行 756 self.vline_operating = self.vline_operating - 1; 757 if self.vline_operating.data() < 0 { 758 self.vline_operating = LineId(self.vline_sum - 1); 759 } 760 761 // 考虑是否向上滚动(在top_vline上退格) 762 if self.vlines_used > actual_line_sum { 763 self.top_vline = self.top_vline - 1; 764 if <LineId as Into<i32>>::into(self.top_vline) < 0 { 765 self.top_vline = LineId(self.vline_sum - 1); 766 } 767 } 768 //因为上缩一行所以显示在屏幕中的虚拟行少一 769 self.vlines_used -= 1; 770 self.textui_refresh_vlines(self.top_vline, actual_line_sum)?; 771 } 772 } 773 } else { 774 // 输出其他字符 775 776 c_uart_send(UartPort::COM1.to_u16(), character as u8); 777 778 if is_enable_window == true { 779 if let TextuiVline::Chromatic(vline) = 780 &self.vlines[<LineId as Into<usize>>::into(self.vline_operating)] 781 { 782 if !vline.index.check(self.chars_per_line) { 783 self.textui_new_line()?; 784 } 785 786 return self.true_textui_putchar_window(character, frcolor, bkcolor); 787 } 788 } 789 } 790 791 return Ok(()); 792 } 793 } 794 impl Default for TextuiWindow { 795 fn default() -> Self { 796 TextuiWindow { 797 id: WindowId(0), 798 flags: WindowFlag::TEXTUI_CHROMATIC, 799 vline_sum: 0, 800 vlines_used: 1, 801 top_vline: LineId::new(0), 802 vlines: Vec::new(), 803 vline_operating: LineId::new(0), 804 chars_per_line: 0, 805 } 806 } 807 } 808 #[allow(dead_code)] 809 #[derive(Debug)] 810 pub struct TextUiFramework { 811 metadata: ScmUiFrameworkMetadata, 812 window_list: Arc<SpinLock<LinkedList<Arc<SpinLock<TextuiWindow>>>>>, 813 actual_line: AtomicI32, // 真实行的数量(textui的帧缓冲区能容纳的内容的行数) 814 current_window: Arc<SpinLock<TextuiWindow>>, // 当前的主窗口 815 default_window: Arc<SpinLock<TextuiWindow>>, // 默认print到的窗口 816 } 817 818 impl TextUiFramework { 819 pub fn new( 820 metadata: ScmUiFrameworkMetadata, 821 window_list: Arc<SpinLock<LinkedList<Arc<SpinLock<TextuiWindow>>>>>, 822 current_window: Arc<SpinLock<TextuiWindow>>, 823 default_window: Arc<SpinLock<TextuiWindow>>, 824 ) -> Self { 825 let actual_line = 826 AtomicI32::new((&metadata.buf_info().buf_height() / TEXTUI_CHAR_HEIGHT) as i32); 827 let inner = TextUiFramework { 828 metadata, 829 window_list, 830 actual_line, 831 current_window, 832 default_window, 833 }; 834 return inner; 835 } 836 } 837 838 impl ScmUiFramework for &mut TextUiFramework { 839 // 安装ui框架的回调函数 840 fn install(&self) -> Result<i32, SystemError> { 841 c_uart_send_str( 842 UartPort::COM1.to_u16(), 843 "\ntextui_install_handler\n\0".as_ptr(), 844 ); 845 return Ok(0); 846 } 847 // 卸载ui框架的回调函数 848 fn uninstall(&self) -> Result<i32, SystemError> { 849 return Ok(0); 850 } 851 // 启用ui框架的回调函数 852 fn enable(&self) -> Result<i32, SystemError> { 853 ENABLE_PUT_TO_WINDOW.store(true, Ordering::SeqCst); 854 return Ok(0); 855 } 856 // 禁用ui框架的回调函数 857 fn disable(&self) -> Result<i32, SystemError> { 858 ENABLE_PUT_TO_WINDOW.store(false, Ordering::SeqCst); 859 860 return Ok(0); 861 } 862 // 改变ui框架的帧缓冲区的回调函数 863 fn change(&self, buf_info: ScmBufferInfo) -> Result<i32, SystemError> { 864 let src_buf = textui_framework().metadata.buf(); 865 textui_framework().metadata.set_buf_info(buf_info); 866 let dst_buf = textui_framework().metadata.buf(); 867 dst_buf.copy_from_slice(src_buf); 868 return Ok(0); 869 } 870 /// 获取ScmUiFramework的元数据 871 /// ## 返回值 872 /// 873 /// -成功:Ok(ScmUiFramework的元数据) 874 /// -失败:Err(错误码) 875 fn metadata(&self) -> Result<ScmUiFrameworkMetadata, SystemError> { 876 let metadata = self.metadata.clone(); 877 878 return Ok(metadata); 879 } 880 } 881 882 /// Mapping from characters to glyph indices. 883 pub trait GlyphMapping: Sync { 884 /// Maps a character to a glyph index. 885 /// 886 /// If `c` isn't included in the font the index of a suitable replacement glyph is returned. 887 fn index(&self, c: char) -> usize; 888 } 889 890 impl<F> GlyphMapping for F 891 where 892 F: Sync + Fn(char) -> usize, 893 { 894 fn index(&self, c: char) -> usize { 895 self(c) 896 } 897 } 898 899 /// 在默认窗口上输出一个字符 900 /// ## 参数 901 /// - character 字符 902 /// - FRcolor 前景色(RGB) 903 /// - BKcolor 背景色(RGB) 904 905 #[no_mangle] 906 pub extern "C" fn rs_textui_putchar(character: u8, fr_color: u32, bk_color: u32) -> i32 { 907 return textui_putchar( 908 character as char, 909 FontColor::from(fr_color), 910 FontColor::from(bk_color), 911 ) 912 .map(|_| 0) 913 .unwrap_or_else(|e| e.to_posix_errno()); 914 } 915 916 pub fn textui_putchar( 917 character: char, 918 fr_color: FontColor, 919 bk_color: FontColor, 920 ) -> Result<(), SystemError> { 921 if unsafe { TEXTUI_IS_INIT } { 922 return textui_framework() 923 .current_window 924 .lock() 925 .textui_putchar_window( 926 character, 927 fr_color, 928 bk_color, 929 ENABLE_PUT_TO_WINDOW.load(Ordering::SeqCst), 930 ); 931 } else { 932 //未初始化暴力输出 933 return no_init_textui_putchar_window( 934 character, 935 fr_color, 936 bk_color, 937 ENABLE_PUT_TO_WINDOW.load(Ordering::SeqCst), 938 ); 939 } 940 } 941 942 /// 初始化text ui框架 943 944 #[no_mangle] 945 pub extern "C" fn rs_textui_init() -> i32 { 946 let r = textui_init().unwrap_or_else(|e| e.to_posix_errno()); 947 if r.is_negative() { 948 c_uart_send_str(UartPort::COM1.to_u16(), "textui init failed.\n\0".as_ptr()); 949 } 950 return r; 951 } 952 953 fn textui_init() -> Result<i32, SystemError> { 954 unsafe { textui_framwork_init() }; 955 let textui_framework = textui_framework(); 956 957 unsafe { TEXTUI_IS_INIT = true }; 958 959 scm_register(Arc::new(textui_framework))?; 960 961 c_uart_send_str( 962 UartPort::COM1.to_u16(), 963 "\ntext ui initialized\n\0".as_ptr(), 964 ); 965 966 return Ok(0); 967 } 968