]> icculus.org git repositories - btb/d2x.git/blob - main/cli.c
get rid of unused alpha, font color stuff
[btb/d2x.git] / main / cli.c
1 /*
2  *  Code for controlling the console
3  *  Based on an early version of SDL_Console
4  *
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>
8  *
9  *  This is free, just be sure to give us credit when using it
10  *  in any of your programs.
11  */
12
13 #ifdef HAVE_CONFIG_H
14 #include <conf.h>
15 #endif
16
17 #include <string.h>
18
19 #include "inferno.h"
20 #include "maths.h"
21 #include "gr.h"
22 #include "timer.h"
23 #include "u_mem.h"
24 #include "strutil.h"
25
26
27 #define get_msecs() approx_fsec_to_msec(timer_get_approx_seconds())
28
29 #define CON_BG_HIRES (cfexist("scoresb.pcx")?"scoresb.pcx":"scores.pcx")
30 #define CON_BG_LORES (cfexist("scores.pcx")?"scores.pcx":"scoresb.pcx") // Mac datafiles only have scoresb.pcx
31 #define CON_BG ((SWIDTH>=640)?CON_BG_HIRES:CON_BG_LORES)
32
33 #define CON_NUM_LINES           128
34 // Cut the buffer line if it becomes longer than this
35 #define CON_CHARS_PER_LINE      128
36 // Cursor blink frequency in ms
37 #define CON_BLINK_RATE          500
38 // Border in pixels from the most left to the first letter
39 #define CON_CHAR_BORDER         4
40 // Default prompt used at the commandline
41 #define CON_DEFAULT_PROMPT      "]"
42 // Cursor shown if we are in insert mode
43 #define CON_INS_CURSOR          "_"
44 // Cursor shown if we are in overwrite mode
45 #define CON_OVR_CURSOR          "|"
46
47
48 /* The console's data */
49 static char **CommandLines;     // List of all the past commands
50 static int TotalCommands;       // Number of commands in the Back Commands
51 static int LineBuffer;          // The number of visible lines in the console (autocalculated)
52 static int VChars;              // The number of visible characters in one console line (autocalculated)
53 static char *Prompt;            // Prompt displayed in command line
54 static char  Command[CON_CHARS_PER_LINE];   // current command in command line = lcommand + rcommand
55 static char LCommand[CON_CHARS_PER_LINE];   // right hand side of cursor
56 static char RCommand[CON_CHARS_PER_LINE];   // left hand side of cursor
57 static char VCommand[CON_CHARS_PER_LINE];   // current visible command line
58 static int CursorPos;           // Current cursor position in CurrentCommand
59 static int Offset;              // CommandOffset (first visible char of command) - if command is too long to fit into console
60 int InsMode;                    // Insert or Overwrite characters?
61 static int CommandScrollBack;   // How much the users scrolled back in the command lines
62
63
64 /* Frees all the memory loaded by the console */
65 static void CON_Free(void);
66 /* shift command history (the one you can switch with the up/down keys) */
67 static void CON_NewLineCommand(void);
68
69
70 /* Initializes the console */
71 void cli_init()
72 {
73         int loop;
74
75         CommandLines = NULL;
76         TotalCommands = 0;
77         InsMode = 1;
78         CursorPos = 0;
79         CommandScrollBack = 0;
80         Prompt = d_strdup(CON_DEFAULT_PROMPT);
81
82         VChars = CON_CHARS_PER_LINE - 1;
83         LineBuffer = CON_NUM_LINES;
84
85         CommandLines = (char **)d_malloc(sizeof(char *) * LineBuffer);
86         for (loop = 0; loop <= LineBuffer - 1; loop++) {
87                 CommandLines[loop] = (char *)d_calloc(CON_CHARS_PER_LINE, sizeof(char));
88         }
89         memset(Command, 0, CON_CHARS_PER_LINE);
90         memset(LCommand, 0, CON_CHARS_PER_LINE);
91         memset(RCommand, 0, CON_CHARS_PER_LINE);
92         memset(VCommand, 0, CON_CHARS_PER_LINE);
93
94         atexit(CON_Free);
95 }
96
97
98 /* Frees all the memory loaded by the console */
99 static void CON_Free(void)
100 {
101         int i;
102
103         for (i = 0; i <= LineBuffer - 1; i++) {
104                 d_free(CommandLines[i]);
105         }
106         d_free(CommandLines);
107
108         CommandLines = NULL;
109
110         d_free(Prompt);
111 }
112
113
114 /* Increments the command lines */
115 static void CON_NewLineCommand(void)
116 {
117         int loop;
118         char *temp;
119
120         temp  = CommandLines[LineBuffer - 1];
121
122         for (loop = LineBuffer - 1; loop > 0; loop--)
123                 CommandLines[loop] = CommandLines[loop - 1];
124
125         CommandLines[0] = temp;
126
127         memset(CommandLines[0], 0, CON_CHARS_PER_LINE);
128         if (TotalCommands < LineBuffer - 1)
129                 TotalCommands++;
130 }
131
132
133 /* Draws the command line the user is typing in to the screen */
134 /* completely rewritten by C.Wacha */
135 void DrawCommandLine(int y)
136 {
137         int x;
138         int commandbuffer;
139         static unsigned int LastBlinkTime = 0;  // Last time the consoles cursor blinked
140         static int LastCursorPos = 0;           // Last Cursor Position
141         static int Blink = 0;                   // Is the cursor currently blinking
142
143         commandbuffer = VChars - (int)strlen(Prompt) - 1; // -1 to make cursor visible
144
145         // Concatenate the left and right side to command
146         strcpy(Command, LCommand);
147         strncat(Command, RCommand, strlen(RCommand));
148
149         //calculate display offset from current cursor position
150         if (Offset < CursorPos - commandbuffer)
151                 Offset = CursorPos - commandbuffer;
152         if(Offset > CursorPos)
153                 Offset = CursorPos;
154
155         // first add prompt to visible part
156         strcpy(VCommand, Prompt);
157
158         // then add the visible part of the command
159         strncat(VCommand, &Command[Offset], strlen(&Command[Offset]));
160
161         // now display the result
162         gr_string(CON_CHAR_BORDER, y - grd_curfont->ft_h, VCommand);
163
164         // at last add the cursor
165         // check if the blink period is over
166         if (get_msecs() > LastBlinkTime) {
167                 LastBlinkTime = get_msecs() + CON_BLINK_RATE;
168                 if(Blink)
169                         Blink = 0;
170                 else
171                         Blink = 1;
172         }
173
174         // check if cursor has moved - if yes display cursor anyway
175         if (CursorPos != LastCursorPos) {
176                 LastCursorPos = CursorPos;
177                 LastBlinkTime = get_msecs() + CON_BLINK_RATE;
178                 Blink = 1;
179         }
180
181         if (Blink) {
182                 int prompt_width, cmd_width, h, w;
183
184                 gr_get_string_size(Prompt, &prompt_width, &h, &w);
185                 gr_get_string_size(LCommand + Offset, &cmd_width, &h, &w);
186                 x = CON_CHAR_BORDER + prompt_width + cmd_width;
187                 if (InsMode)
188                         gr_string(x, y - grd_curfont->ft_h, CON_INS_CURSOR);
189                 else
190                         gr_string(x, y - grd_curfont->ft_h, CON_OVR_CURSOR);
191         }
192 }
193
194
195 /* Sets the Prompt for console */
196 void CON_SetPrompt(char* newprompt) {
197         // check length so we can still see at least 1 char :-)
198         if (strlen(newprompt) < VChars) {
199                 d_free(Prompt);
200                 Prompt = d_strdup(newprompt);
201         } else
202                 CON_Out("prompt too long. (max. %i chars)\n", VChars - 1);
203 }
204
205
206 /* Executes the command entered */
207 void CON_Execute(void)
208 {
209         if(strlen(Command) > 0) {
210                 CON_NewLineCommand();
211
212                 // copy the input into the past commands strings
213                 strcpy(CommandLines[0], Command);
214
215                 // display the command including the prompt
216                 CON_Out("%s%s\n", Prompt, Command);
217
218                 cmd_append(Command);
219
220                 Clear_Command();
221                 CommandScrollBack = -1;
222         }
223 }
224
225
226 void CON_TabCompletion(void)
227 {
228         int i, j;
229         char *command;
230
231         command = cmd_complete(LCommand);
232
233         if (!command)
234                 return; // no tab completion took place so return silently
235
236         j = (int)strlen(command);
237         if (j > CON_CHARS_PER_LINE - 2)
238                 j = CON_CHARS_PER_LINE-1;
239
240         memset(LCommand, 0, CON_CHARS_PER_LINE);
241         CursorPos = 0;
242
243         for (i = 0; i < j; i++) {
244                 CursorPos++;
245                 LCommand[i] = command[i];
246         }
247         // add a trailing space
248         CursorPos++;
249         LCommand[j] = ' ';
250         LCommand[j+1] = '\0';
251 }
252
253
254 void Cursor_Left(void)
255 {
256         char temp[CON_CHARS_PER_LINE];
257
258         if (CursorPos > 0) {
259                 CursorPos--;
260                 strcpy(temp, RCommand);
261                 strcpy(RCommand, &LCommand[strlen(LCommand)-1]);
262                 strcat(RCommand, temp);
263                 LCommand[strlen(LCommand)-1] = '\0';
264         }
265 }
266
267
268 void Cursor_Right(void)
269 {
270         char temp[CON_CHARS_PER_LINE];
271
272         if(CursorPos < strlen(Command)) {
273                 CursorPos++;
274                 strncat(LCommand, RCommand, 1);
275                 strcpy(temp, RCommand);
276                 strcpy(RCommand, &temp[1]);
277         }
278 }
279
280
281 void Cursor_Home(void)
282 {
283         char temp[CON_CHARS_PER_LINE];
284
285         CursorPos = 0;
286         strcpy(temp, RCommand);
287         strcpy(RCommand, LCommand);
288         strncat(RCommand, temp, strlen(temp));
289         memset(LCommand, 0, CON_CHARS_PER_LINE);
290 }
291
292
293 void Cursor_End(void)
294 {
295         CursorPos = (int)strlen(Command);
296         strncat(LCommand, RCommand, strlen(RCommand));
297         memset(RCommand, 0, CON_CHARS_PER_LINE);
298 }
299
300
301 void Cursor_Del(void)
302 {
303         char temp[CON_CHARS_PER_LINE];
304
305         if (strlen(RCommand) > 0) {
306                 strcpy(temp, RCommand);
307                 strcpy(RCommand, &temp[1]);
308         }
309 }
310
311 void Cursor_BSpace(void)
312 {
313         if (CursorPos > 0) {
314                 CursorPos--;
315                 Offset--;
316                 if (Offset < 0)
317                         Offset = 0;
318                 LCommand[strlen(LCommand)-1] = '\0';
319         }
320 }
321
322
323 void Cursor_Add(char character)
324 {
325         if (strlen(Command) < CON_CHARS_PER_LINE - 1)
326         {
327                 CursorPos++;
328                 LCommand[strlen(LCommand)] = character;
329                 LCommand[strlen(LCommand)] = '\0';
330         }
331 }
332
333
334 void Clear_Command(void)
335 {
336         CursorPos = 0;
337         memset( Command, 0, CON_CHARS_PER_LINE);
338         memset(LCommand, 0, CON_CHARS_PER_LINE);
339         memset(RCommand, 0, CON_CHARS_PER_LINE);
340         memset(VCommand, 0, CON_CHARS_PER_LINE);
341 }
342
343
344 void Command_Up(void)
345 {
346         if(CommandScrollBack < TotalCommands - 1) {
347                 /* move back a line in the command strings and copy the command to the current input string */
348                 CommandScrollBack++;
349                 memset(RCommand, 0, CON_CHARS_PER_LINE);
350                 Offset = 0;
351                 strcpy(LCommand, CommandLines[CommandScrollBack]);
352                 CursorPos = (int)strlen(CommandLines[CommandScrollBack]);
353         }
354 }
355
356
357 void Command_Down(void)
358 {
359         if(CommandScrollBack > -1) {
360                 /* move forward a line in the command strings and copy the command to the current input string */
361                 CommandScrollBack--;
362                 memset(RCommand, 0, CON_CHARS_PER_LINE);
363                 memset(LCommand, 0, CON_CHARS_PER_LINE);
364                 Offset = 0;
365                 if(CommandScrollBack > -1)
366                         strcpy(LCommand, CommandLines[CommandScrollBack]);
367                 CursorPos = (int)strlen(LCommand);
368         }
369 }