277 lines
7.3 KiB
D
277 lines
7.3 KiB
D
/**
|
|
* HULK Console functionality.
|
|
*/
|
|
module hulk.console;
|
|
|
|
import hulk.fb;
|
|
import hulk.kfont;
|
|
import hulk.ver;
|
|
import hulk.rtc;
|
|
import hulk.writef;
|
|
|
|
/**
|
|
* Represent the HULK console.
|
|
*
|
|
* Coordinate (0,0) is the top-left console position.
|
|
*/
|
|
struct Console
|
|
{
|
|
/** Border color. */
|
|
private enum BORDER_COLOR = 0xFF8000u;
|
|
|
|
/** Heading color. */
|
|
private enum HEADING_COLOR = 0x0066FFu;
|
|
|
|
/** Console page width in text columns. */
|
|
private static __gshared size_t m_width;
|
|
|
|
/** Console page height in text rows. */
|
|
private static __gshared size_t m_height;
|
|
|
|
/** Current console page. */
|
|
private static __gshared size_t m_page;
|
|
|
|
/** Current page cursor X position. */
|
|
private static __gshared size_t m_x;
|
|
|
|
/** Current page cursor Y position. */
|
|
private static __gshared size_t m_y;
|
|
|
|
/** Number of delayed newline characters. */
|
|
private static __gshared size_t m_newlines;
|
|
|
|
/** Active console escape code. */
|
|
private static __gshared char m_escape_code;
|
|
|
|
/** Flag to indicate the previous character was an escape character. */
|
|
private static __gshared bool m_escape;
|
|
|
|
/**
|
|
* Initialize the console.
|
|
*/
|
|
public static void initialize()
|
|
{
|
|
size_t fb_console_height = Fb.height - Kfont.line_height - 1;
|
|
m_width = (Fb.width - 1) / 2 / Kfont.advance;
|
|
m_height = fb_console_height / Kfont.line_height;
|
|
}
|
|
|
|
/**
|
|
* Clear the console.
|
|
*/
|
|
public static void clear()
|
|
{
|
|
Fb.clear();
|
|
m_page = 0u;
|
|
m_x = 0u;
|
|
m_y = 0u;
|
|
draw();
|
|
}
|
|
|
|
/**
|
|
* Write a character to the console (buffer newlines).
|
|
*
|
|
* @param ch Character to write.
|
|
*/
|
|
public static void write(char ch)
|
|
{
|
|
if (ch == '\n')
|
|
{
|
|
render_heading_end();
|
|
m_escape_code = 0u;
|
|
m_newlines++;
|
|
}
|
|
else
|
|
{
|
|
dowrite(ch);
|
|
}
|
|
}
|
|
|
|
private static void render_heading_start()
|
|
{
|
|
if ('0' <= m_escape_code && m_escape_code <= '9' && m_x < (m_width - 1))
|
|
{
|
|
size_t heading_level = m_escape_code - ('0' - 1);
|
|
size_t nx = m_x + heading_level;
|
|
if (nx >= m_width)
|
|
{
|
|
nx = m_width - 1;
|
|
}
|
|
size_t hx = fb_x(m_page, m_x);
|
|
size_t hy = fb_y(m_y) + Kfont.line_height / 2 - 1;
|
|
size_t hwidth = (nx - m_x - 1) * Kfont.advance + Kfont.advance / 2 - 1;
|
|
Fb.rect(hx, hy, hwidth, 2, HEADING_COLOR);
|
|
Fb.rect(hx + hwidth, fb_y(m_y) + Kfont.line_height / 8,
|
|
2, Kfont.line_height * 3 / 4, HEADING_COLOR);
|
|
m_x = nx;
|
|
}
|
|
}
|
|
|
|
private static void render_heading_end()
|
|
{
|
|
if ('0' <= m_escape_code && m_escape_code <= '9' && m_x < (m_width - 1))
|
|
{
|
|
size_t heading_level = m_escape_code - ('0' - 1);
|
|
size_t nx = m_x + heading_level;
|
|
if (nx >= m_width)
|
|
{
|
|
nx = m_width - 1;
|
|
}
|
|
size_t hwidth = (nx - m_x - 1) * Kfont.advance + Kfont.advance / 2 - 1;
|
|
size_t hx = fb_x(m_page, nx) - hwidth;
|
|
size_t hy = fb_y(m_y) + Kfont.line_height / 2 - 1;
|
|
Fb.rect(hx, hy, hwidth, 2, HEADING_COLOR);
|
|
Fb.rect(hx - 2, fb_y(m_y) + Kfont.line_height / 8,
|
|
2, Kfont.line_height * 3 / 4, HEADING_COLOR);
|
|
m_x = nx;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Write a character to the console (no newline buffering).
|
|
*
|
|
* @param ch Character to write.
|
|
*/
|
|
private static void dowrite(char ch)
|
|
{
|
|
if (m_newlines != 0u)
|
|
{
|
|
size_t newlines = m_newlines;
|
|
m_newlines = 0u;
|
|
for (size_t i = 0u; i < newlines; i++)
|
|
{
|
|
dowrite('\n');
|
|
}
|
|
}
|
|
if (m_escape)
|
|
{
|
|
m_escape_code = ch;
|
|
render_heading_start();
|
|
m_escape = false;
|
|
return;
|
|
}
|
|
if (ch == '\a')
|
|
{
|
|
m_escape = true;
|
|
return;
|
|
}
|
|
if (ch == '\n')
|
|
{
|
|
m_x = 0u;
|
|
m_y++;
|
|
}
|
|
else
|
|
{
|
|
render_char(fb_x(m_page, m_x), fb_y(m_y), ch);
|
|
m_x++;
|
|
if (m_x == m_width)
|
|
{
|
|
m_x = 0u;
|
|
m_y++;
|
|
}
|
|
}
|
|
if (m_y == m_height)
|
|
{
|
|
if (m_page == 0u)
|
|
{
|
|
m_page = 1u;
|
|
m_x = 0u;
|
|
m_y = 0u;
|
|
}
|
|
else
|
|
{
|
|
m_y--;
|
|
shift_rows();
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Shift console rows.
|
|
*/
|
|
private static void shift_rows()
|
|
{
|
|
/* Shift up page 0 */
|
|
Fb.copy_rect(fb_x(0u, 0u), fb_y(1u),
|
|
m_width * Kfont.advance, (m_height - 1u) * Kfont.line_height,
|
|
fb_x(0u, 0u), fb_y(0u));
|
|
/* Copy page 1 first row to page 0 last row. */
|
|
Fb.copy_rect(fb_x(1u, 0u), fb_y(0u),
|
|
m_width * Kfont.advance, Kfont.line_height,
|
|
fb_x(0u, 0u), fb_y(m_height - 1u));
|
|
/* Shift up page 1 */
|
|
Fb.copy_rect(fb_x(1u, 0u), fb_y(1u),
|
|
m_width * Kfont.advance, (m_height - 1u) * Kfont.line_height,
|
|
fb_x(1u, 0u), fb_y(0u));
|
|
/* Erase page 1 last row. */
|
|
Fb.rect(fb_x(1u, 0u), fb_y(m_height - 1u),
|
|
m_width * Kfont.advance, Kfont.line_height, 0u);
|
|
}
|
|
|
|
/**
|
|
* Render a character.
|
|
*
|
|
* @param x X position.
|
|
* @param y Y position.
|
|
* @param ch Character to render.
|
|
*/
|
|
private static void render_char(size_t x, size_t y, char ch)
|
|
{
|
|
if (ch > 127)
|
|
{
|
|
ch = 0u;
|
|
}
|
|
const(CharInfo) * ci = &Kfont.chars[ch];
|
|
Fb.blit_alpha_bitmap(x + ci.left, y + ci.top, ci.bitmap, ci.width, ci.height);
|
|
}
|
|
|
|
/**
|
|
* Get the framebuffer X coordinate corresponding to the console page X position.
|
|
*/
|
|
private static size_t fb_x(size_t page, size_t x)
|
|
{
|
|
return x * Kfont.advance + page * (m_width * Kfont.advance + 1);
|
|
}
|
|
|
|
/**
|
|
* Get the framebuffer Y coordinate corresponding to the console page Y position.
|
|
*/
|
|
private static size_t fb_y(size_t y)
|
|
{
|
|
return (y + 1) * Kfont.line_height + 1;
|
|
}
|
|
|
|
/**
|
|
* Draw console.
|
|
*/
|
|
private static draw()
|
|
{
|
|
static __gshared string header_text = "Welcome to HOS v" ~ VERSION ~ "!";
|
|
Fb.rect(0u, Kfont.line_height, Fb.width, 1, BORDER_COLOR);
|
|
Fb.rect(m_width * Kfont.advance, Kfont.line_height, 1, Fb.height - Kfont.line_height, BORDER_COLOR);
|
|
size_t x = 0;
|
|
foreach (c; header_text)
|
|
{
|
|
render_char(x, 0, c);
|
|
x += Kfont.advance;
|
|
}
|
|
update_header();
|
|
}
|
|
|
|
/**
|
|
* Update console header.
|
|
*/
|
|
public static update_header()
|
|
{
|
|
__gshared uint x;
|
|
x = Fb.width - 8 * Kfont.advance;
|
|
Fb.rect(x - 1, 0, 1, Kfont.line_height, BORDER_COLOR);
|
|
Fb.rect(x, 0, Fb.width - x, Kfont.line_height, 0);
|
|
Rtc.time rtc_time = Rtc.read_rtc_time();
|
|
writef(function(ubyte ch) {
|
|
render_char(x, 0, ch);
|
|
x += Kfont.advance;
|
|
}, "%02u:%02u:%02u", rtc_time.hour, rtc_time.minute, rtc_time.second);
|
|
}
|
|
}
|