textui.rs 34 KB

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