/* ScummVM - Scumm Interpreter * Copyright (C) 2004 The ScummVM project * * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * $Header$ * */ // Console module #include "reinherit.h" #include "font_mod.h" #include "cvar_mod.h" #include "events_mod.h" #include "gfx_mod.h" #include "console_mod.h" #include "console.h" namespace Saga { static R_CONSOLEINFO ConInfo = { 0, R_CON_DEFAULTPOS, R_CON_DEFAULTLINES, R_CON_DEFAULTCMDS, 0, 0, 0, 0, 0, "", 0 }; static R_CON_SCROLLBACK ConScrollback; static R_CON_SCROLLBACK ConHistory; static int CV_ConResize = R_CON_DEFAULTPOS; static int CV_ConDroptime = R_CON_DROPTIME; int CON_Register() { CVAR_Register_I(&CV_ConResize, "con_h", NULL, R_CVAR_NONE, 12, R_CON_DEFAULTPOS); CVAR_Register_I(&CV_ConDroptime, "con_droptime", NULL, R_CVAR_NONE, 0, 5000); CVAR_Register_I(&ConInfo.line_max, "con_lines", NULL, R_CVAR_NONE, 5, 5000); return R_SUCCESS; } int CON_Init() { return R_SUCCESS; } int CON_Shutdown() { debug(0, "CON_Shutdown(): Deleting console scrollback and command history."); CON_DeleteScroll(&ConScrollback); CON_DeleteScroll(&ConHistory); return R_SUCCESS; } int CON_Activate() { R_EVENT con_event; if (ConInfo.active) { return R_FAILURE; } con_event.type = R_CONTINUOUS_EVENT; con_event.code = R_CONSOLE_EVENT | R_NODESTROY; con_event.op = EVENT_ACTIVATE; con_event.time = 0; con_event.duration = CV_ConDroptime; EVENT_Queue(&con_event); ConInfo.active = 1; return R_SUCCESS; } int CON_Deactivate() { R_EVENT con_event; if (!ConInfo.active) { return R_FAILURE; } con_event.type = R_CONTINUOUS_EVENT; con_event.code = R_CONSOLE_EVENT | R_NODESTROY; con_event.op = EVENT_DEACTIVATE; con_event.time = 0; con_event.duration = CV_ConDroptime; EVENT_Queue(&con_event); return R_SUCCESS; } int CON_IsActive(void) { return ConInfo.active; } // Responsible for processing character input to the console and maintaining // the console input buffer. // Input buffer is processed by EXPR_Parse on enter. // High ASCII characters are ignored. int CON_Type(int in_char) { int input_pos = ConInfo.input_pos; const char *expr; int expr_len; int result; //char *lvalue; char *rvalue = NULL; R_CVAR_P con_cvar = NULL; const char *expr_err; const char *err_str; if (ConInfo.y_pos != ConInfo.y_max) { // Ignore keypress until console fully down return R_SUCCESS; } if ((in_char > 127) || (!in_char)) { // Ignore non-ascii codes return R_SUCCESS; } switch (in_char) { case '\r': expr = ConInfo.input_buf; CON_Print("> %s", ConInfo.input_buf); expr_len = strlen(ConInfo.input_buf); result = EXPR_Parse(&expr, &expr_len, &con_cvar, &rvalue); CON_AddLine(&ConHistory, ConInfo.hist_max, ConInfo.input_buf); memset(ConInfo.input_buf, 0, R_CON_INPUTBUF_LEN); ConInfo.input_pos = 0; ConInfo.hist_pos = 0; if (result != R_SUCCESS) { EXPR_GetError(&expr_err); CON_Print("Parse error: %s", expr_err); break; } if (rvalue == NULL) { CVAR_Print(con_cvar); break; } if (CVAR_IsFunc(con_cvar)) { CVAR_Exec(con_cvar, rvalue); } else if (CVAR_SetValue(con_cvar, rvalue) != R_SUCCESS) { CVAR_GetError(&err_str); CON_Print("Illegal assignment: %s.", err_str); } break; case '\b': ConInfo.input_buf[input_pos] = 0; if (input_pos > 0) { ConInfo.input_pos--; ConInfo.input_buf[ConInfo.input_pos] = 0; } break; default: if (input_pos < R_CON_INPUTBUF_LEN) { ConInfo.input_buf[input_pos] = (char)in_char; ConInfo.input_pos++; } break; } if (rvalue) free(rvalue); return R_SUCCESS; } int CON_Draw(R_SURFACE *ds) { int line_y; R_CONSOLE_LINE *walk_ptr; R_CONSOLE_LINE *start_ptr; int txt_fgcolor; int txt_shcolor; R_RECT fill_rect; int i; if (!ConInfo.active) { return R_FAILURE; } if (CV_ConResize != ConInfo.y_max) { ConInfo.y_max = CV_ConResize; ConInfo.y_pos = CV_ConResize; } fill_rect.top = 0; fill_rect.left = 0; fill_rect.bottom = ConInfo.y_pos; fill_rect.right = ds->buf_w - 1; GFX_DrawRect(ds, &fill_rect, GFX_MatchColor(R_CONSOLE_BGCOLOR)); txt_fgcolor = GFX_MatchColor(R_CONSOLE_TXTCOLOR); txt_shcolor = GFX_MatchColor(R_CONSOLE_TXTSHADOW); FONT_Draw(SMALL_FONT_ID, ds, ">", 1, 2, ConInfo.y_pos - 10, txt_fgcolor, txt_shcolor, FONT_SHADOW); FONT_Draw(SMALL_FONT_ID, ds, ConInfo.input_buf, strlen(ConInfo.input_buf), 10, ConInfo.y_pos - 10, txt_fgcolor, txt_shcolor, FONT_SHADOW); line_y = ConInfo.y_pos - (R_CON_INPUT_H + R_CON_LINE_H); start_ptr = ConScrollback.head; for (i = 0; i < ConInfo.line_pos; i++) { if (start_ptr->next) { start_ptr = start_ptr->next; } else { break; } } for (walk_ptr = start_ptr; walk_ptr; walk_ptr = walk_ptr->next) { FONT_Draw(SMALL_FONT_ID, ds, walk_ptr->str_p, walk_ptr->str_len, 2, line_y, txt_fgcolor, txt_shcolor, FONT_SHADOW); line_y -= R_CON_LINE_H; if (line_y < -R_CON_LINE_H) break; } return R_SUCCESS; } int CON_Print(const char *fmt_str, ...) { char vsstr_p[R_CON_PRINTFLIMIT + 1]; va_list argptr; int ret_val; va_start(argptr, fmt_str); ret_val = vsprintf(vsstr_p, fmt_str, argptr); CON_AddLine(&ConScrollback, ConInfo.line_max, vsstr_p); va_end(argptr); ConInfo.line_pos = 0; return ret_val; } int CON_CmdUp() { R_CONSOLE_LINE *start_ptr = ConHistory.head; int i; if (!start_ptr) { return R_SUCCESS; } if (ConInfo.hist_pos < ConHistory.lines) { ConInfo.hist_pos++; } for (i = 1; (i < ConInfo.hist_pos); i++) { if (start_ptr->next) { start_ptr = start_ptr->next; } else { break; } } memset(ConInfo.input_buf, 0, R_CON_INPUTBUF_LEN); strcpy(ConInfo.input_buf, start_ptr->str_p); ConInfo.input_pos = start_ptr->str_len - 1; debug(0, "History pos: %d/%d", ConInfo.hist_pos, ConHistory.lines); return R_SUCCESS; } int CON_CmdDown(void) { R_CONSOLE_LINE *start_ptr = ConHistory.head; int i; if (ConInfo.hist_pos == 1) { debug(0, "Erased input buffer."); memset(ConInfo.input_buf, 0, R_CON_INPUTBUF_LEN); ConInfo.input_pos = 0; ConInfo.hist_pos--; return R_SUCCESS; } else if (ConInfo.hist_pos) { ConInfo.hist_pos--; } else { return R_SUCCESS; } for (i = 1; i < ConInfo.hist_pos; i++) { if (start_ptr->next) { start_ptr = start_ptr->next; } else { break; } } memset(ConInfo.input_buf, 0, R_CON_INPUTBUF_LEN); strcpy(ConInfo.input_buf, start_ptr->str_p); ConInfo.input_pos = start_ptr->str_len - 1; debug(0, "History pos: %d/%d", ConInfo.hist_pos, ConHistory.lines); return R_SUCCESS; } int CON_PageUp() { int n_lines; n_lines = (ConInfo.y_max - R_CON_INPUT_H) / R_CON_LINE_H; if (ConInfo.line_pos < (ConScrollback.lines - n_lines)) { ConInfo.line_pos += n_lines; } debug(0, "Line pos: %d", ConInfo.line_pos); return R_SUCCESS; } int CON_PageDown() { int n_lines; n_lines = (ConInfo.y_max - R_CON_INPUT_H) / R_CON_LINE_H; if (ConInfo.line_pos > n_lines) { ConInfo.line_pos -= n_lines; } else { ConInfo.line_pos = 0; } return R_SUCCESS; } int CON_DropConsole(double percent) { R_SURFACE *back_buf; if (percent > 1.0) { percent = 1.0; } back_buf = GFX_GetBackBuffer(); CON_SetDropPos(percent); CON_Draw(back_buf); return R_SUCCESS; } int CON_RaiseConsole(double percent) { R_SURFACE *back_buf; if (percent >= 1.0) { percent = 1.0; ConInfo.active = 0; } back_buf = GFX_GetBackBuffer(); CON_SetDropPos(1.0 - percent); CON_Draw(back_buf); return R_SUCCESS; } static int CON_SetDropPos(double percent) { double exp_percent; if (percent > 1.0) percent = 1.0; if (percent < 0.0) percent = 0.0; exp_percent = percent * percent; ConInfo.y_pos = (int)(ConInfo.y_max * exp_percent); return R_SUCCESS; } static int CON_AddLine(R_CON_SCROLLBACK *scroll, int line_max, const char *constr_p) { int constr_len; char *newstr_p; R_CONSOLE_LINE *newline_p; int del_lines; int i; constr_len = strlen(constr_p) + 1; newstr_p = (char *)malloc(constr_len); if (newstr_p == NULL) { return R_MEM; } newline_p = (R_CONSOLE_LINE *)malloc(sizeof(R_CONSOLE_LINE)); if (newline_p == NULL) { return R_MEM; } newline_p->next = NULL; newline_p->prev = NULL; strcpy(newstr_p, constr_p); newline_p->str_p = newstr_p; newline_p->str_len = constr_len; if (scroll->head == NULL) { scroll->head = newline_p; scroll->tail = newline_p; } else { scroll->head->prev = newline_p; newline_p->next = scroll->head; scroll->head = newline_p; } scroll->lines++; if (scroll->lines > line_max) { del_lines = scroll->lines - line_max; for (i = 0; i < del_lines; i++) { CON_DeleteLine(scroll); } } return R_SUCCESS; } static int CON_DeleteLine(R_CON_SCROLLBACK *scroll) { R_CONSOLE_LINE *temp_p = scroll->tail; if (temp_p->prev == NULL) { scroll->head = NULL; scroll->tail = NULL; } else { temp_p->prev->next = NULL; scroll->tail = temp_p->prev; } if (temp_p->str_p) free(temp_p->str_p); free(temp_p); scroll->lines--; return R_SUCCESS; } static int CON_DeleteScroll(R_CON_SCROLLBACK * scroll) { R_CONSOLE_LINE *walk_ptr; R_CONSOLE_LINE *temp_ptr; for (walk_ptr = scroll->head; walk_ptr; walk_ptr = temp_ptr) { if (walk_ptr->str_p) free(walk_ptr->str_p); temp_ptr = walk_ptr->next; free(walk_ptr); } return R_SUCCESS; } } // End of namespace Saga