2 * Code for controlling the console
3 * Based on an early version of SDL_Console
5 * Written By: Garrett Banuk <mongoose@mongeese.org>
6 * Code Cleanup and heavily extended by: Clemens Wacha <reflex-2000@gmx.net>
7 * Ported to use native Descent interfaces by: Bradley Bell <btb@icculus.org>
9 * This is free, just be sure to give us credit when using it
10 * in any of your programs.
27 #define FG_COLOR grd_curcanv->cv_font_fg_color
28 #define get_msecs() approx_fsec_to_msec(timer_get_approx_seconds())
30 #define CON_BG_HIRES (cfexist("scoresb.pcx")?"scoresb.pcx":"scores.pcx")
31 #define CON_BG_LORES (cfexist("scores.pcx")?"scores.pcx":"scoresb.pcx") // Mac datafiles only have scoresb.pcx
32 #define CON_BG ((SWIDTH>=640)?CON_BG_HIRES:CON_BG_LORES)
34 #define CON_NUM_LINES 128
35 // Cut the buffer line if it becomes longer than this
36 #define CON_CHARS_PER_LINE 128
37 // Cursor blink frequency in ms
38 #define CON_BLINK_RATE 500
39 // Border in pixels from the most left to the first letter
40 #define CON_CHAR_BORDER 4
41 // Default prompt used at the commandline
42 #define CON_DEFAULT_PROMPT "]"
43 // Cursor shown if we are in insert mode
44 #define CON_INS_CURSOR "_"
45 // Cursor shown if we are in overwrite mode
46 #define CON_OVR_CURSOR "|"
49 /* The console's data */
50 static char **CommandLines; // List of all the past commands
51 static int TotalCommands; // Number of commands in the Back Commands
52 static int LineBuffer; // The number of visible lines in the console (autocalculated)
53 static int VChars; // The number of visible characters in one console line (autocalculated)
54 static char *Prompt; // Prompt displayed in command line
55 static char Command[CON_CHARS_PER_LINE]; // current command in command line = lcommand + rcommand
56 static char LCommand[CON_CHARS_PER_LINE]; // right hand side of cursor
57 static char RCommand[CON_CHARS_PER_LINE]; // left hand side of cursor
58 static char VCommand[CON_CHARS_PER_LINE]; // current visible command line
59 static int CursorPos; // Current cursor position in CurrentCommand
60 static int Offset; // CommandOffset (first visible char of command) - if command is too long to fit into console
61 int InsMode; // Insert or Overwrite characters?
62 static int CommandScrollBack; // How much the users scrolled back in the command lines
65 /* Frees all the memory loaded by the console */
66 static void CON_Free(void);
67 /* shift command history (the one you can switch with the up/down keys) */
68 static void CON_NewLineCommand(void);
71 /* Initializes the console */
80 CommandScrollBack = 0;
81 Prompt = d_strdup(CON_DEFAULT_PROMPT);
83 VChars = CON_CHARS_PER_LINE - 1;
84 LineBuffer = CON_NUM_LINES;
86 CommandLines = (char **)d_malloc(sizeof(char *) * LineBuffer);
87 for (loop = 0; loop <= LineBuffer - 1; loop++) {
88 CommandLines[loop] = (char *)d_calloc(CON_CHARS_PER_LINE, sizeof(char));
90 memset(Command, 0, CON_CHARS_PER_LINE);
91 memset(LCommand, 0, CON_CHARS_PER_LINE);
92 memset(RCommand, 0, CON_CHARS_PER_LINE);
93 memset(VCommand, 0, CON_CHARS_PER_LINE);
99 /* Frees all the memory loaded by the console */
100 static void CON_Free(void)
104 for (i = 0; i <= LineBuffer - 1; i++) {
105 d_free(CommandLines[i]);
107 d_free(CommandLines);
115 /* Increments the command lines */
116 static void CON_NewLineCommand(void)
121 temp = CommandLines[LineBuffer - 1];
123 for (loop = LineBuffer - 1; loop > 0; loop--)
124 CommandLines[loop] = CommandLines[loop - 1];
126 CommandLines[0] = temp;
128 memset(CommandLines[0], 0, CON_CHARS_PER_LINE);
129 if (TotalCommands < LineBuffer - 1)
134 /* Draws the command line the user is typing in to the screen */
135 /* completely rewritten by C.Wacha */
136 void DrawCommandLine(int y)
140 static unsigned int LastBlinkTime = 0; // Last time the consoles cursor blinked
141 static int LastCursorPos = 0; // Last Cursor Position
142 static int Blink = 0; // Is the cursor currently blinking
144 commandbuffer = VChars - (int)strlen(Prompt) - 1; // -1 to make cursor visible
146 // Concatenate the left and right side to command
147 strcpy(Command, LCommand);
148 strncat(Command, RCommand, strlen(RCommand));
150 //calculate display offset from current cursor position
151 if (Offset < CursorPos - commandbuffer)
152 Offset = CursorPos - commandbuffer;
153 if(Offset > CursorPos)
156 // first add prompt to visible part
157 strcpy(VCommand, Prompt);
159 // then add the visible part of the command
160 strncat(VCommand, &Command[Offset], strlen(&Command[Offset]));
162 // now display the result
163 gr_string(CON_CHAR_BORDER, y - grd_curfont->ft_h, VCommand);
165 // at last add the cursor
166 // check if the blink period is over
167 if (get_msecs() > LastBlinkTime) {
168 LastBlinkTime = get_msecs() + CON_BLINK_RATE;
175 // check if cursor has moved - if yes display cursor anyway
176 if (CursorPos != LastCursorPos) {
177 LastCursorPos = CursorPos;
178 LastBlinkTime = get_msecs() + CON_BLINK_RATE;
183 int prompt_width, cmd_width, h, w;
185 gr_get_string_size(Prompt, &prompt_width, &h, &w);
186 gr_get_string_size(LCommand + Offset, &cmd_width, &h, &w);
187 x = CON_CHAR_BORDER + prompt_width + cmd_width;
189 gr_string(x, y - grd_curfont->ft_h, CON_INS_CURSOR);
191 gr_string(x, y - grd_curfont->ft_h, CON_OVR_CURSOR);
196 /* Sets the Prompt for console */
197 void CON_SetPrompt(char* newprompt) {
198 // check length so we can still see at least 1 char :-)
199 if (strlen(newprompt) < VChars) {
201 Prompt = d_strdup(newprompt);
203 CON_Out("prompt too long. (max. %i chars)\n", VChars - 1);
207 /* Executes the command entered */
208 void CON_Execute(void)
210 if(strlen(Command) > 0) {
211 CON_NewLineCommand();
213 // copy the input into the past commands strings
214 strcpy(CommandLines[0], Command);
216 // display the command including the prompt
217 CON_Out("%s%s\n", Prompt, Command);
222 CommandScrollBack = -1;
227 void CON_TabCompletion(void)
232 command = cmd_complete(LCommand);
235 return; // no tab completion took place so return silently
237 j = (int)strlen(command);
238 if (j > CON_CHARS_PER_LINE - 2)
239 j = CON_CHARS_PER_LINE-1;
241 memset(LCommand, 0, CON_CHARS_PER_LINE);
244 for (i = 0; i < j; i++) {
246 LCommand[i] = command[i];
248 // add a trailing space
251 LCommand[j+1] = '\0';
255 void Cursor_Left(void)
257 char temp[CON_CHARS_PER_LINE];
261 strcpy(temp, RCommand);
262 strcpy(RCommand, &LCommand[strlen(LCommand)-1]);
263 strcat(RCommand, temp);
264 LCommand[strlen(LCommand)-1] = '\0';
269 void Cursor_Right(void)
271 char temp[CON_CHARS_PER_LINE];
273 if(CursorPos < strlen(Command)) {
275 strncat(LCommand, RCommand, 1);
276 strcpy(temp, RCommand);
277 strcpy(RCommand, &temp[1]);
282 void Cursor_Home(void)
284 char temp[CON_CHARS_PER_LINE];
287 strcpy(temp, RCommand);
288 strcpy(RCommand, LCommand);
289 strncat(RCommand, temp, strlen(temp));
290 memset(LCommand, 0, CON_CHARS_PER_LINE);
294 void Cursor_End(void)
296 CursorPos = (int)strlen(Command);
297 strncat(LCommand, RCommand, strlen(RCommand));
298 memset(RCommand, 0, CON_CHARS_PER_LINE);
302 void Cursor_Del(void)
304 char temp[CON_CHARS_PER_LINE];
306 if (strlen(RCommand) > 0) {
307 strcpy(temp, RCommand);
308 strcpy(RCommand, &temp[1]);
312 void Cursor_BSpace(void)
319 LCommand[strlen(LCommand)-1] = '\0';
324 void Cursor_Add(char character)
326 if (strlen(Command) < CON_CHARS_PER_LINE - 1)
329 LCommand[strlen(LCommand)] = character;
330 LCommand[strlen(LCommand)] = '\0';
335 void Clear_Command(void)
338 memset( Command, 0, CON_CHARS_PER_LINE);
339 memset(LCommand, 0, CON_CHARS_PER_LINE);
340 memset(RCommand, 0, CON_CHARS_PER_LINE);
341 memset(VCommand, 0, CON_CHARS_PER_LINE);
345 void Command_Up(void)
347 if(CommandScrollBack < TotalCommands - 1) {
348 /* move back a line in the command strings and copy the command to the current input string */
350 memset(RCommand, 0, CON_CHARS_PER_LINE);
352 strcpy(LCommand, CommandLines[CommandScrollBack]);
353 CursorPos = (int)strlen(CommandLines[CommandScrollBack]);
358 void Command_Down(void)
360 if(CommandScrollBack > -1) {
361 /* move forward a line in the command strings and copy the command to the current input string */
363 memset(RCommand, 0, CON_CHARS_PER_LINE);
364 memset(LCommand, 0, CON_CHARS_PER_LINE);
366 if(CommandScrollBack > -1)
367 strcpy(LCommand, CommandLines[CommandScrollBack]);
368 CursorPos = (int)strlen(LCommand);