322 lines
9.6 KiB
C

#include "textui.h"
#include "screen_manager.h"
#include "driver/uart/uart.h"
#include <common/string.h>
#include <common/printk.h>
#include <common/atomic.h>
struct scm_ui_framework_t textui_framework;
static spinlock_t __window_id_lock = {1};
static uint32_t __window_max_id = 0;
// 暂时初始化16080个初始字符对象以及67个虚拟行对象
#define INITIAL_CHARS 16080
#define INITIAL_VLINES (int)(1080 / 16)
static struct textui_char_chromatic_t __initial_chars[INITIAL_CHARS] = {0};
static struct textui_vline_chromatic_t __initial_vlines[INITIAL_VLINES] = {0};
static struct textui_window_t __initial_window = {0}; // 初始窗口
static struct textui_private_info_t __private_info = {0};
static struct List __windows_list;
/**
* @brief 初始化window对象
*
* @param window 窗口对象
* @param flags 标志位
* @param vlines_num 虚拟行的总数
* @param vlines_ptr 虚拟行数组指针
* @param cperline 每行最大的字符数
*/
static int __textui_init_window(struct textui_window_t *window, uint8_t flags, uint16_t vlines_num, void *vlines_ptr, uint16_t cperline)
{
memset((window), 0, sizeof(struct textui_window_t));
list_init(&(window)->list);
window->lock.lock = 1;
spin_lock(&__window_id_lock);
window->id = __window_max_id++;
spin_unlock(&__window_id_lock);
window->flags = flags;
window->vlines_num = vlines_num;
window->vlines_used = 1;
window->top_vline = 0;
window->vline_operating = 0;
window->chars_per_line = cperline;
if (textui_is_chromatic(flags))
window->vlines.chromatic = vlines_ptr;
else
window->vlines.normal = vlines_ptr;
list_add(&__windows_list, &(window)->list);
}
/**
* @brief 初始化虚拟行对象
*
* @param vline 虚拟行对象指针
* @param chars_ptr 字符对象数组指针
*/
#define __textui_init_vline(vline, chars_ptr) \
do \
{ \
memset(vline, 0, sizeof(struct textui_vline_chromatic_t)); \
(vline)->index = 0; \
(vline)->chars = chars_ptr; \
} while (0)
int textui_install_handler(struct scm_buffer_info_t *buf)
{
// return printk_init(buf);
uart_send_str(COM1, "textui_install_handler");
return 0;
}
int textui_uninstall_handler(void *args)
{
return 0;
}
int textui_enable_handler(void *args)
{
uart_send_str(COM1, "textui_enable_handler");
return 0;
}
int textui_disable_handler(void *args)
{
return 0;
}
int textui_change_handler(struct scm_buffer_info_t *buf)
{
memcpy((void *)buf->vaddr, (void *)(textui_framework.buf->vaddr), textui_framework.buf->size);
textui_framework.buf = buf;
set_pos_VBE_FB_addr((uint *)buf->vaddr);
return 0;
}
struct scm_ui_framework_operations_t textui_ops =
{
.install = &textui_install_handler,
.uninstall = &textui_uninstall_handler,
.change = &textui_change_handler,
.enable = &textui_enable_handler,
.disable = &textui_disable_handler,
};
/**
* @brief 获取textui的帧缓冲区能容纳的内容的行数
*
* @return uint16_t
*/
uint16_t __textui_get_actual_lines()
{
return __private_info.actual_line;
}
/**
* @brief 获取当前渲染的窗口的id
*
* @return uint16_t
*/
uint32_t __textui_get_current_window_id()
{
return __private_info.current_window->id;
}
/**
* @brief 插入换行
*
* @param window 窗口结构体
* @param vline_id 虚拟行号
* @return int
*/
static int __textui_new_line(struct textui_window_t *window, uint16_t vline_id)
{
// todo: 支持在两个虚拟行之间插入一个新行
++window->vline_operating;
if (unlikely(window->vline_operating == window->vlines_num))
window->vline_operating = 0;
struct textui_vline_chromatic_t *vline = &window->vlines.chromatic[window->vline_operating];
memset(vline->chars, 0, sizeof(struct textui_char_chromatic_t) * window->chars_per_line);
vline->index = 0;
if (likely(window->vlines_used == window->vlines_num)) // 需要滚动屏幕
{
// uart_send_str(COM1, " scroll, top vline= ");
++window->top_vline;
// uart_send(COM1, '0' + window->top_vline);
if (unlikely(window->top_vline >= window->vlines_num))
window->top_vline = 0;
// int delta = ABS((int)window->vline_operating - (int)window->top_vline);
// 刷新所有行
textui_refresh_vlines(window, window->top_vline, window->vlines_num);
}
else
++window->vlines_used;
return 0;
}
static int __textui_putchar_window(struct textui_window_t *window, uint16_t character)
{
if (textui_is_chromatic(window->flags)) // 启用彩色字符
{
struct textui_vline_chromatic_t *vline = &window->vlines.chromatic[window->vline_operating];
vline->chars[vline->index].c = character;
vline->chars[vline->index].Fr = 0xff;
vline->chars[vline->index].Fg = 0xff;
vline->chars[vline->index].Fb = 0xff;
vline->chars[vline->index].Br = 0;
vline->chars[vline->index].Bg = 0;
vline->chars[vline->index].Bb = 0;
++vline->index;
textui_refresh_characters(window, window->vline_operating, vline->index - 1, 1);
// 换行
if (vline->index >= window->chars_per_line)
{
__textui_new_line(window, window->vline_operating);
}
}
else
{
// todo: 支持纯文本字符
while (1)
pause();
}
return 0;
}
/**
* @brief 在指定窗口上输出一个字符
*
* @param window 窗口
* @param character 字符
* @return int
*/
int textui_putchar_window(struct textui_window_t *window, uint16_t character)
{
if (unlikely(character == '\0'))
return 0;
if (!textui_is_chromatic(window->flags)) // 暂不支持纯文本窗口
return 0;
uint64_t rflags = 0; // 加锁后rflags存储到这里
spin_lock_irqsave(&window->lock, rflags);
uart_send(COM1, character);
if (unlikely(character == '\n'))
{
__textui_new_line(window, window->vline_operating);
spin_unlock_irqrestore(&window->lock, rflags);
return 0;
}
else if (character == '\t') // 输出制表符
{
int space_to_print = 8 - window->vlines.chromatic[window->vline_operating].index % 8;
while (space_to_print--)
{
__textui_putchar_window(window, ' ');
}
}
else if (character == '\b') // 退格
{
--window->vlines.chromatic[window->vline_operating].index;
{
uint16_t tmp = window->vlines.chromatic[window->vline_operating].index;
window->vlines.chromatic[window->vline_operating].chars[tmp].c = ' ';
textui_refresh_characters(window, window->vline_operating, tmp, 1);
}
// 需要向上缩一行
if (window->vlines.chromatic[window->vline_operating].index < 0)
{
window->vlines.chromatic[window->vline_operating].index = 0;
memset(window->vlines.chromatic[window->vline_operating].chars, 0, sizeof(struct textui_char_chromatic_t) * window->chars_per_line);
--window->vline_operating;
if (unlikely(window->vline_operating < 0))
window->vline_operating = window->vlines_num - 1;
// 考虑是否向上滚动
if (likely(window->vlines_used >= __private_info.actual_line))
{
--window->top_vline;
if (unlikely(window->top_vline < 0))
window->top_vline = window->vlines_num - 1;
}
--window->vlines_used;
textui_refresh_vlines(window, window->top_vline, __private_info.actual_line);
}
}
else
__textui_putchar_window(window, character);
spin_unlock_irqrestore(&window->lock, rflags);
return 0;
}
/**
* @brief 在默认窗口上输出一个字符
*
* @param character 字符
* @return int
*/
int textui_putchar(uint16_t character)
{
return textui_putchar_window(__private_info.default_window, character);
}
/**
* @brief 初始化text ui框架
*
* @return int
*/
int textui_init()
{
spin_init(&__window_id_lock);
__window_max_id = 0;
list_init(&__windows_list);
memset(&textui_framework, 0, sizeof(struct scm_ui_framework_t));
memset(&__private_info, 0, sizeof(struct textui_private_info_t));
io_mfence();
char name[] = "textUI";
strcpy(textui_framework.name, name);
textui_framework.ui_ops = &textui_ops;
textui_framework.type = 0;
// 注册框架到屏幕管理器
int retval = scm_register(&textui_framework);
if (retval != 0)
{
uart_send_str(COM1, "text ui init failed");
while (1)
pause();
}
uint16_t chars_per_vline = textui_framework.buf->width / TEXTUI_CHAR_WIDTH;
uint16_t total_vlines = textui_framework.buf->height / TEXTUI_CHAR_HEIGHT;
int cnt = chars_per_vline * total_vlines;
struct textui_vline_chromatic_t *vl_ptr = __initial_vlines;
struct textui_char_chromatic_t *ch_ptr = __initial_chars;
// 初始化虚拟行
for (int i = 0; i < total_vlines; ++i)
{
__textui_init_vline((vl_ptr + i), (ch_ptr + i * chars_per_vline));
}
// 初始化窗口
__textui_init_window((&__initial_window), TEXTUI_WF_CHROMATIC, total_vlines, __initial_vlines, chars_per_vline);
__private_info.current_window = &__initial_window;
__private_info.default_window = &__initial_window;
__private_info.actual_line = textui_framework.buf->height / TEXTUI_CHAR_HEIGHT;
uart_send_str(COM1, "text ui initialized");
return 0;
}