[console] Fix a lot of the console view placement issues

Things seem to be at least close to the right place now.

Input line handling has been made more object-oriented in that the
collection of objects required for a single input line (command, say,
say_team) are bundled into one object with just one set of handlers for
resize and draw. Much tidier.
This commit is contained in:
Bill Currie 2022-09-21 12:17:44 +09:00
parent 230e23db5d
commit 0921235aa6

View file

@ -66,7 +66,6 @@
static general_data_t plugin_info_general_data;
console_data_t con_data;
//static con_buffer_t *con_chat;
static con_buffer_t *con;
static float con_cursorspeed = 4;
@ -144,7 +143,6 @@ static cvar_t cl_conmode_cvar = {
.value = { .type = &cl_conmode_type, .value = &con_data.exec_line },
};
static int con_totallines; // total lines in console scrollback
static con_state_t con_state;
static int con_event_id;
static int con_saved_focos;
@ -152,8 +150,18 @@ static int con_saved_focos;
static qboolean con_debuglog;
static qboolean chat_team;
typedef struct {
const char *prompt;
inputline_t *input_line;
view_t *view;
draw_charbuffer_t *buffer;
} con_input_t;
#define MAXCMDLINE 256
static inputline_t *input_line;
static con_input_t cmd_line;
static con_input_t say_line;
static con_input_t team_line;
#define CON_BUFFER_SIZE 32768
#define CON_LINES 1024
@ -162,11 +170,6 @@ static draw_charbuffer_t *console_buffer;
static con_buffer_t *con_main;
static int view_offset;
static view_t *say_view;
static draw_charbuffer_t *say_buffer;
static inputline_t *say_line;
static inputline_t *say_team_line;
#define NOTIFY_LINES 4
static view_t *notify_view;
static draw_charbuffer_t *notify_buffer;
@ -200,12 +203,12 @@ C_SetState (con_state_t state)
}
if (state == con_message) {
const char *prompt = "say:";
say_line.prompt = "say:";
if (chat_team) {
prompt = "say_team:";
say_line.prompt = "say_team:";
}
say_buffer->cursx = 0;
Draw_PrintBuffer (say_buffer, prompt);
say_line.buffer->cursx = 0;
Draw_PrintBuffer (say_line.buffer, say_line.prompt);
}
if (con_state == con_menu && old_state != con_menu) {
@ -229,97 +232,11 @@ ToggleConsole_f (void)
case con_fullscreen:
break;
}
Con_ClearTyping (input_line, 0);
Con_ClearTyping (cmd_line.input_line, 0);
ClearNotify ();
}
static void
Clear_f (void)
{
Con_ClearBuffer (con_main);
//Con_ClearBuffer (con_chat);
}
static void
MessageMode_f (void)
{
if (con_state != con_inactive)
return;
chat_team = false;
C_SetState (con_message);
}
static void
MessageMode2_f (void)
{
if (con_state != con_inactive)
return;
chat_team = true;
C_SetState (con_message);
}
static void
Resize (con_buffer_t *con)
{
int width, oldwidth, oldtotallines, numlines, numchars;
width = (r_data->vid->conview->xlen >> 3) - 2;
if (width < 1) { // video hasn't been initialized yet
width = 38;
con_linewidth = width;
} else {
oldwidth = con_linewidth;
con_linewidth = width;
oldtotallines = con_totallines;
numlines = oldtotallines;
if (con_totallines < numlines)
numlines = con_totallines;
numchars = oldwidth;
if (con_linewidth < numchars)
numchars = con_linewidth;
ClearNotify ();
}
input_line->width = con_linewidth;
}
static void
Condump_f (void)
{
QFile *file;
const char *name;
if (Cmd_Argc () != 2) {
Sys_Printf ("usage: condump <filename>\n");
return;
}
if (strchr (Cmd_Argv (1), '/') || strchr (Cmd_Argv (1), '\\')) {
Sys_Printf ("invalid character in filename\n");
return;
}
name = va (0, "%s/%s.txt", qfs_gamedir->dir.def, Cmd_Argv (1));//FIXME
if (!(file = QFS_WOpen (name, 0))) {
Sys_Printf ("could not open %s for writing: %s\n", name,
strerror (errno));
return;
}
for (uint32_t line_ind = con->line_tail; line_ind != con->line_head;
line_ind = (line_ind + 1) % con->max_lines) {
con_line_t *line = &con->lines[line_ind];
Qwrite (file, con->buffer + line->text, line->len);
}
Qclose (file);
}
static int
cl_exec_line_command (void *data, const char *line)
{
@ -456,6 +373,18 @@ C_Print (const char *fmt, va_list args)
/* DRAWING */
static void
draw_cursor (int x, int y, inputline_t *il)
{
if (!con_data.realtime) {
return;
}
float t = *con_data.realtime * con_cursorspeed;
int ch = 10 + ((int) (t) & 1);
r_funcs->Draw_Character (x + ((il->linepos - il->scroll) * 8), y, ch);
}
static void
DrawInputLine (int x, int y, int cursor, inputline_t *il)
{
@ -467,13 +396,11 @@ DrawInputLine (int x, int y, int cursor, inputline_t *il)
} else {
r_funcs->Draw_nString (x, y, s, il->width - 1);
}
if (cursor && con_data.realtime) {
float t = *con_data.realtime * con_cursorspeed;
int ch = 10 + ((int) (t) & 1);
r_funcs->Draw_Character (x + ((il->linepos - il->scroll) << 3), y, ch);
if (cursor) {
draw_cursor (x, y, il);
}
if (strlen (s) >= il->width)
r_funcs->Draw_Character (x + ((il->width - 1) << 3), y, '>' | 0x80);
r_funcs->Draw_Character (x + ((il->width - 1) * 8), y, '>' | 0x80);
}
void
@ -482,13 +409,53 @@ C_DrawInputLine (inputline_t *il)
DrawInputLine (il->x, il->y, il->cursor, il);
}
static void
draw_input_line (inputline_t *il, draw_charbuffer_t *buffer)
{
char *dst = buffer->chars + buffer->cursx;
char *src = il->lines[il->edit_line] + il->scroll + 1;
size_t i;
*dst++ = il->scroll ? '<' | 0x80 : il->lines[il->edit_line][0];
for (i = 0; i < il->width - 2 && *src; i++) {
*dst++ = *src++;
}
while (i++ < il->width - 2) {
*dst++ = ' ';
}
*dst++ = *src ? '>' | 0x80 : ' ';
}
static void
draw_input (view_t *view)
{
if (con_state == con_inactive)
return;
__auto_type inp = (con_input_t *) view->data;
DrawInputLine (view->xabs + 8, view->yabs, 1, input_line);
Draw_CharBuffer (view->xabs, view->yabs, inp->buffer);
draw_cursor (view->xabs + inp->buffer->cursx * 8, view->yabs,
inp->input_line);
}
static void
input_line_draw (inputline_t *il)
{
__auto_type inp = (con_input_t *) il->user_data;
draw_input_line (il, inp->buffer);
}
static void
resize_input (view_t *view)
{
__auto_type inp = (con_input_t *) view->data;
if (inp->buffer) {
Draw_DestroyBuffer (inp->buffer);
}
inp->buffer = Draw_CreateBuffer (view->xlen / 8, 1);
Draw_ClearBuffer (inp->buffer);
Draw_PrintBuffer (inp->buffer, inp->prompt);
inp->buffer->chars[inp->buffer->cursx] = inp->input_line->prompt_char;
inp->input_line->width = inp->buffer->width - inp->buffer->cursx;
}
static void
@ -544,6 +511,27 @@ draw_console_text (view_t *view)
Draw_CharBuffer (view->xabs, view->yabs, console_buffer);
}
static void
clear_console_text (void)
{
Draw_ClearBuffer (console_buffer);
console_buffer->cursy = console_buffer->height - 1;
}
static void
resize_console_text (view_t *view)
{
int width = view->xlen / 8;
int height = view->ylen / 8;
ClearNotify ();
con_linewidth = width;
Draw_DestroyBuffer (console_buffer);
console_buffer = Draw_CreateBuffer (width, height);
clear_console_text ();
}
static void
draw_con_scrollback (void)
{
@ -586,64 +574,6 @@ draw_console (view_t *view)
view_draw (view);
}
static void
draw_say (view_t *view)
{
r_data->scr_copytop = 1;
Draw_CharBuffer (view->xabs, view->yabs, say_buffer);
}
static void
draw_input_line (inputline_t *il, draw_charbuffer_t *buffer)
{
char *dst = buffer->chars + buffer->cursx;
char *src = il->lines[il->edit_line] + il->scroll;
size_t i;
*dst++ = il->scroll ? '<' | 0x80 : ' ';
for (i = 0; i < il->width - 2 && *src; i++) {
*dst++ = *src++;
}
while (i++ < il->width - 2) {
*dst++ = ' ';
}
*dst++ = *src ? '>' | 0x80 : ' ';
}
static void
say_line_draw (inputline_t *il)
{
say_buffer->cursx = 4;
draw_input_line (il, say_buffer);
}
static void
say_team_line_draw (inputline_t *il)
{
say_buffer->cursx = 9;
draw_input_line (il, say_buffer);
}
static void
resize_console (view_t *view)
{
Draw_DestroyBuffer (console_buffer);
console_buffer = Draw_CreateBuffer (view->xlen / 8, view->ylen / 8);
Draw_ClearBuffer (console_buffer);
}
static void
resize_say (view_t *view)
{
Draw_DestroyBuffer (say_buffer);
say_buffer = Draw_CreateBuffer (view->xlen / 8, 1);
Draw_ClearBuffer (say_buffer);
say_team_line->width = say_buffer->width - 9;
say_line->width = say_buffer->width - 4;
}
static void
draw_notify (view_t *view)
{
@ -710,10 +640,8 @@ C_DrawConsole (void)
{
setup_console ();
if (console_view->ylen != con_data.lines)
view_resize (console_view, console_view->xlen, con_data.lines);
say_view->visible = con_state == con_message;
say_line.view->visible = con_state == con_message ? !chat_team : 0;
team_line.view->visible = con_state == con_message ? chat_team : 0;
console_view->visible = con_data.lines != 0;
menu_view->visible = con_state == con_menu;
@ -750,6 +678,21 @@ exec_line (inputline_t *il)
Con_ExecLine (il->line);
}
static void
con_app_window (const IE_event_t *event)
{
static int old_xlen;
static int old_ylen;
if (old_xlen != event->app_window.xlen
|| old_ylen != event->app_window.ylen) {
old_xlen = event->app_window.xlen;
old_ylen = event->app_window.ylen;
view_resize (con_data.view, r_data->vid->conview->xlen,
r_data->vid->conview->ylen);
}
}
static void
con_key_event (const IE_event_t *event)
{
@ -772,9 +715,9 @@ con_key_event (const IE_event_t *event)
#endif
if (con_state == con_message) {
if (chat_team) {
il = say_team_line;
il = team_line.input_line;
} else {
il = say_line;
il = say_line.input_line;
}
if (key->code == QFK_ESCAPE) {
con_end_message (il);
@ -810,7 +753,7 @@ con_key_event (const IE_event_t *event)
default:
break;
}
il = input_line;
il = cmd_line.input_line;
}
if (old_view_offset != view_offset) {
draw_con_scrollback ();
@ -836,6 +779,7 @@ con_event_handler (const IE_event_t *ie_event, void *data)
return Menu_EventHandler (ie_event);
}
static void (*handlers[ie_event_count]) (const IE_event_t *ie_event) = {
[ie_app_window] = con_app_window,
[ie_key] = con_key_event,
[ie_mouse] = con_mouse_event,
};
@ -847,6 +791,63 @@ con_event_handler (const IE_event_t *ie_event, void *data)
return 1;
}
static void
Clear_f (void)
{
Con_ClearBuffer (con_main);
clear_console_text ();
}
static void
MessageMode_f (void)
{
if (con_state != con_inactive)
return;
chat_team = false;
C_SetState (con_message);
}
static void
MessageMode2_f (void)
{
if (con_state != con_inactive)
return;
chat_team = true;
C_SetState (con_message);
}
static void
Condump_f (void)
{
QFile *file;
const char *name;
if (Cmd_Argc () != 2) {
Sys_Printf ("usage: condump <filename>\n");
return;
}
if (strchr (Cmd_Argv (1), '/') || strchr (Cmd_Argv (1), '\\')) {
Sys_Printf ("invalid character in filename\n");
return;
}
name = va (0, "%s/%s.txt", qfs_gamedir->dir.def, Cmd_Argv (1));//FIXME
if (!(file = QFS_WOpen (name, 0))) {
Sys_Printf ("could not open %s for writing: %s\n", name,
strerror (errno));
return;
}
for (uint32_t line_ind = con->line_tail; line_ind != con->line_head;
line_ind = (line_ind + 1) % con->max_lines) {
con_line_t *line = &con->lines[line_ind];
Qwrite (file, con->buffer + line->text, line->len);
}
Qclose (file);
}
static void
C_Init (void)
{
@ -872,12 +873,51 @@ C_Init (void)
// The console will get resized, so assume initial size is 320x200
con_data.view = view_new (0, 0, 320, 200, grav_northeast);
console_view = view_new (0, 0, 320, 200, grav_northwest);
say_view = view_new (0, 0, 320, 8, grav_northwest);
notify_view = view_new (8, 8, 312, NOTIFY_LINES * 8, grav_northwest);
menu_view = view_new (0, 0, 320, 200, grav_center);
hud_view = view_new (0, 0, 320, 200, grav_northeast);
view_add (con_data.view, say_view);
cmd_line.prompt = "";
cmd_line.input_line = Con_CreateInputLine (32, MAXCMDLINE, ']');
cmd_line.input_line->complete = Con_BasicCompleteCommandLine;
cmd_line.input_line->enter = exec_line;
cmd_line.input_line->width = con_linewidth;
cmd_line.input_line->user_data = &cmd_line;
cmd_line.input_line->draw = input_line_draw;
cmd_line.view = view_new_data (0, 12, 320, 10, grav_southwest, &cmd_line);
cmd_line.view->draw = draw_input;
cmd_line.view->setgeometry = resize_input;
cmd_line.view->resize_x = 1;
view_add (console_view, cmd_line.view);
say_line.prompt = "say:";
say_line.input_line = Con_CreateInputLine (32, MAXCMDLINE, ' ');
say_line.input_line->complete = 0;
say_line.input_line->enter = C_Say;
say_line.input_line->width = con_linewidth - 5;
say_line.input_line->user_data = &say_line;
say_line.input_line->draw = input_line_draw;
say_line.view = view_new_data (0, 0, 320, 8, grav_northwest, &say_line);
say_line.view->draw = draw_input;
say_line.view->setgeometry = resize_input;
say_line.view->visible = 0;
say_line.view->resize_x = 1;
view_add (con_data.view, say_line.view);
team_line.prompt = "say_team:";
team_line.input_line = Con_CreateInputLine (32, MAXCMDLINE, ' ');
team_line.input_line->complete = 0;
team_line.input_line->enter = C_SayTeam;
team_line.input_line->width = con_linewidth - 10;
team_line.input_line->user_data = &team_line;
team_line.input_line->draw = input_line_draw;
team_line.view = view_new_data (0, 0, 320, 8, grav_northwest, &team_line);
team_line.view->draw = draw_input;
team_line.view->setgeometry = resize_input;
team_line.view->visible = 0;
team_line.view->resize_x = 1;
view_add (con_data.view, team_line.view);
view_add (con_data.view, notify_view);
view_add (con_data.view, hud_view);
view_add (con_data.view, console_view);
@ -888,16 +928,9 @@ C_Init (void)
Draw_ClearBuffer (console_buffer);
con_main = Con_CreateBuffer (CON_BUFFER_SIZE, CON_LINES);
console_view->draw = draw_console;
say_view->setgeometry = resize_console;
console_view->visible = 0;
console_view->resize_x = console_view->resize_y = 1;
say_buffer = Draw_CreateBuffer (say_view->xlen / 8, 1);
Draw_ClearBuffer (say_buffer);
say_view->draw = draw_say;
say_view->setgeometry = resize_say;
say_view->visible = 0;
say_view->resize_x = 1;
notify_buffer = Draw_CreateBuffer (notify_view->xlen / 8, NOTIFY_LINES + 1);
Draw_ClearBuffer (notify_buffer);
@ -911,16 +944,12 @@ C_Init (void)
hud_view->draw = Menu_Draw_Hud;
hud_view->visible = 0;
view = view_new (0, 0, 320, 170, grav_northwest);
view = view_new (8, 16, 320, 168, grav_southwest);
view->draw = draw_console_text;
view->setgeometry = resize_console_text;
view->resize_x = view->resize_y = 1;
view_add (console_view, view);
view = view_new (0, 12, 320, 10, grav_southwest);
view->draw = draw_input;
view->resize_x = 1;
view_add (console_view, view);
view = view_new (0, 2, 320, 11, grav_southwest);
view->draw = draw_download;
view->resize_x = 1;
@ -929,28 +958,8 @@ C_Init (void)
con = con_main;
con_linewidth = -1;
input_line = Con_CreateInputLine (32, MAXCMDLINE, ']');
input_line->complete = Con_BasicCompleteCommandLine;
input_line->enter = exec_line;
input_line->width = con_linewidth;
input_line->user_data = 0;
input_line->draw = 0;
say_line = Con_CreateInputLine (32, MAXCMDLINE, ' ');
say_line->complete = 0;
say_line->enter = C_Say;
say_line->width = con_linewidth - 5;
say_line->user_data = 0;
say_line->draw = say_line_draw;
say_team_line = Con_CreateInputLine (32, MAXCMDLINE, ' ');
say_team_line->complete = 0;
say_team_line->enter = C_SayTeam;
say_team_line->width = con_linewidth - 10;
say_team_line->user_data = 0;
say_team_line->draw = say_team_line_draw;
C_CheckResize ();
Sys_Printf ("Console initialized.\n");