ssheven/ssheven-console.c

295 lines
6.2 KiB
C
Raw Normal View History

/*
* ssheven
*
* Copyright (c) 2020 by cy384 <cy384@cy384.com>
* See LICENSE file for details
*/
#include "ssheven-console.h"
void draw_char(int x, int y, Rect* r, char c)
{
MoveTo(r->left + x * con.cell_width + 2, r->top + ((y+1) * con.cell_height) - 2);
DrawChar(c);
}
2020-08-22 02:29:34 +01:00
void toggle_cursor(void)
{
con.cursor_state = !con.cursor_state;
Rect cursor = cell_rect(con.cursor_x, con.cursor_y, con.win->portRect);
InvalRect(&cursor);
}
2020-08-22 02:29:34 +01:00
void check_cursor(void)
{
long int now = TickCount();
if ((now - con.last_cursor_blink) > GetCaretTime())
{
toggle_cursor();
con.last_cursor_blink = now;
}
}
// closely inspired by the retro68 console library
void draw_screen(Rect* r)
{
// get the intersection of our console region and the update region
Rect bounds = (con.win->portRect);
SectRect(r, &bounds, r);
short minRow = (0 > (r->top - bounds.top) / con.cell_height) ? 0 : (r->top - bounds.top) / con.cell_height;
short maxRow = (24 < (r->bottom - bounds.top + con.cell_height - 1) / con.cell_height) ? 24 : (r->bottom - bounds.top + con.cell_height - 1) / con.cell_height;
short minCol = (0 > (r->left - bounds.left) / con.cell_width) ? 0 : (r->left - bounds.left) / con.cell_width;
short maxCol = (80 < (r->right - bounds.left + con.cell_width - 1) / con.cell_width) ? 80 : (r->right - bounds.left + con.cell_width - 1) / con.cell_width;
EraseRect(r);
2020-07-24 01:47:02 +01:00
// don't clobber font settings
short save_font = qd.thePort->txFont;
short save_font_size = qd.thePort->txSize;
short save_font_face = qd.thePort->txFace;
TextFont(kFontIDMonaco);
TextSize(9);
TextFace(normal);
2020-08-29 03:14:43 +01:00
VTermScreenCell vtsc;
for(int i = minRow; i < maxRow; i++)
{
for (int j = minCol; j < maxCol; j++)
2020-08-22 02:29:34 +01:00
{
2020-08-29 03:14:43 +01:00
vterm_screen_get_cell(con.vts, (VTermPos){.row = i, .col = j}, &vtsc);
char c = (char)vtsc.chars[0];
draw_char(j, i, r, c);
2020-08-22 02:29:34 +01:00
}
}
// do the cursor if needed
if (con.cursor_state == 1 &&
con.cursor_y >= minRow &&
con.cursor_y <= maxRow &&
con.cursor_x >= minCol &&
con.cursor_x <= maxCol)
{
Rect cursor = cell_rect(con.cursor_x, con.cursor_y, con.win->portRect);
InvertRect(&cursor);
}
2020-07-24 01:47:02 +01:00
TextFont(save_font);
TextSize(save_font_size);
TextFace(save_font_face);
}
void ruler(Rect* r)
{
char itoc[] = {'0','1','2','3','4','5','6','7','8','9'};
for (int x = 0; x < 80; x++)
for (int y = 0; y < 24; y++)
draw_char(x, y, r, itoc[x%10]);
}
int is_printable(char c)
{
if (c >= 32 && c <= 126) return 1; else return 0;
}
void print_int(int d)
{
char itoc[] = {'0','1','2','3','4','5','6','7','8','9'};
char buffer[12] = {0};
int i = 10;
2020-08-22 20:16:30 +01:00
int negative = 0;
2020-07-24 00:58:25 +01:00
if (d == 0)
{
buffer[0] = '0';
i = -1;
}
2020-08-22 20:16:30 +01:00
if (d < 0)
{
negative = 1;
d *= -1;
}
for (; d > 0; i--)
{
buffer[i] = itoc[d % 10];
d /= 10;
}
2020-08-22 20:16:30 +01:00
if (negative) buffer[i] = '-';
print_string(buffer+i+1-negative);
}
void print_string(const char* c)
{
2020-08-29 03:14:43 +01:00
vterm_input_write(con.vterm, c, strlen(c));
}
2020-07-26 15:13:51 +01:00
void printf_i(const char* str, ...)
{
va_list args;
va_start(args, str);
while (*str != '\0')
{
if (*str == '%')
{
str++;
switch (*str)
{
case 'd':
print_int(va_arg(args, int));
break;
case 's':
print_string(va_arg(args, char*));
2020-08-29 03:14:43 +01:00
break;
case '\0':
vterm_input_write(con.vterm, str-1, 1);
break;
2020-07-26 15:13:51 +01:00
default:
va_arg(args, int); // ignore
2020-08-29 03:14:43 +01:00
vterm_input_write(con.vterm, str-1, 2);
2020-07-26 15:13:51 +01:00
break;
}
}
else
{
2020-08-29 03:14:43 +01:00
vterm_input_write(con.vterm, str, 1);
2020-07-26 15:13:51 +01:00
}
str++;
}
va_end(args);
}
void set_window_title(WindowPtr w, const char* c_name)
{
Str255 pascal_name;
strncpy((char *) &pascal_name[1], c_name, 255);
pascal_name[0] = strlen(c_name);
SetWTitle(w, pascal_name);
}
2020-08-29 03:14:43 +01:00
int bell(void* user)
{
SysBeep(30);
return 1;
}
int movecursor(VTermPos pos, VTermPos oldpos, int visible, void *user)
{
// if the cursor is dark, invalidate that location
if (con.cursor_state == 1)
{
Rect inval = cell_rect(con.cursor_x, con.cursor_y, (con.win->portRect));
InvalRect(&inval);
}
con.cursor_x = pos.col;
con.cursor_y = pos.row;
return 1;
}
Rect cell_rect(int x, int y, Rect bounds)
{
Rect r = { (short) (bounds.top + y * con.cell_height), (short) (bounds.left + x * con.cell_width + 2),
(short) (bounds.top + (y+1) * con.cell_height), (short) (bounds.left + (x+1) * con.cell_width + 2) };
return r;
}
int damage(VTermRect rect, void *user)
{
Rect topleft = cell_rect(rect.start_col, rect.start_row, (con.win->portRect));
Rect bottomright = cell_rect(rect.end_col, rect.end_row, (con.win->portRect));
UnionRect(&topleft, &bottomright, &topleft);
InvalRect(&topleft);
return 1;
}
const VTermScreenCallbacks vtscrcb =
{
.damage = damage,
.moverect = NULL,
.movecursor = movecursor,
.settermprop = NULL,
.bell = bell,
.resize = NULL,
.sb_pushline = NULL,
.sb_popline = NULL
};
void console_setup(void)
{
2020-07-24 01:47:02 +01:00
// don't clobber font settings
short save_font = qd.thePort->txFont;
short save_font_size = qd.thePort->txSize;
short save_font_face = qd.thePort->txFace;
TextFont(kFontIDMonaco);
TextSize(9);
TextFace(normal);
con.cell_height = 12;
con.cell_width = CharWidth('M');
2020-07-24 01:47:02 +01:00
TextFont(save_font);
TextSize(save_font_size);
TextFace(save_font_face);
Rect initial_window_bounds = qd.screenBits.bounds;
InsetRect(&initial_window_bounds, 20, 20);
initial_window_bounds.top += 40;
initial_window_bounds.bottom = initial_window_bounds.top + con.cell_height * 24 + 2;
initial_window_bounds.right = initial_window_bounds.left + con.cell_width * 80 + 4;
// limits on window size changes:
// top = min vertical
// bottom = max vertical
// left = min horizontal
// right = max horizontal
//Rect window_limits = { .top = 100, .bottom = 200, .left = 100, .right = 200 };
ConstStr255Param title = "\pssheven " SSHEVEN_VERSION;
WindowPtr win = NewWindow(NULL, &initial_window_bounds, title, true, noGrowDocProc, (WindowPtr)-1, true, 0);
Rect portRect = win->portRect;
SetPort(win);
EraseRect(&portRect);
int exit_main_loop = 0;
con.win = win;
memset(con.data, ' ', sizeof(char) * 24*80);
con.cursor_x = 0;
con.cursor_y = 0;
2020-08-29 03:14:43 +01:00
con.vterm = vterm_new(24, 80);
vterm_set_utf8(con.vterm, 0);
VTermState* vtermstate = vterm_obtain_state(con.vterm);
vterm_state_reset(vtermstate, 1);
2020-08-29 03:14:43 +01:00
con.vts = vterm_obtain_screen(con.vterm);
vterm_screen_reset(con.vts, 1);
vterm_screen_set_callbacks(con.vts, &vtscrcb, NULL);
}
2020-08-29 03:14:43 +01:00