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