2 * Written By: Garrett Banuk <mongoose@mongeese.org>
3 * Code Cleanup and heavily extended by: Clemens Wacha <reflex-2000@gmx.net>
4 * Ported to use native Descent interfaces by: Bradley Bell <btb@icculus.org>
6 * This is free, just be sure to give us credit when using it
7 * in any of your programs.
19 #include "CON_console.h"
26 #define FG_COLOR grd_curcanv->cv_font_fg_color
27 #define get_msecs() approx_fsec_to_msec(timer_get_approx_seconds())
30 /* This contains a pointer to the "topmost" console. The console that
31 * is currently taking keyboard input. */
32 static ConsoleInformation *Topmost;
34 /* Takes keys from the keyboard and inputs them to the console
35 If the event was not handled (i.e. WM events or unknown ctrl-shift
36 sequences) the function returns the event for further processing. */
37 int CON_Events(int event)
41 if(!CON_isVisible(Topmost))
44 if(event & KEY_CTRLED)
47 switch(event & ~KEY_CTRLED)
56 Clear_Command(Topmost);
59 Clear_History(Topmost);
60 CON_UpdateConsole(Topmost);
66 else if(event & KEY_ALTED)
68 //the console does not handle ALT combinations!
73 //first of all, check if the console hide key was pressed
74 if(event == Topmost->HideKey)
85 if(event & KEY_SHIFTED)
87 Topmost->ConsoleScrollBack = Topmost->LineBuffer-1;
88 CON_UpdateConsole(Topmost);
94 if(event & KEY_SHIFTED)
96 Topmost->ConsoleScrollBack = 0;
97 CON_UpdateConsole(Topmost);
103 Topmost->ConsoleScrollBack += CON_LINE_SCROLL;
104 if(Topmost->ConsoleScrollBack > Topmost->LineBuffer-1)
105 Topmost->ConsoleScrollBack = Topmost->LineBuffer-1;
107 CON_UpdateConsole(Topmost);
110 Topmost->ConsoleScrollBack -= CON_LINE_SCROLL;
111 if(Topmost->ConsoleScrollBack < 0)
112 Topmost->ConsoleScrollBack = 0;
113 CON_UpdateConsole(Topmost);
119 Command_Down(Topmost);
122 Cursor_Left(Topmost);
125 Cursor_Right(Topmost);
128 Cursor_BSpace(Topmost);
134 Topmost->InsMode = 1-Topmost->InsMode;
137 CON_TabCompletion(Topmost);
140 if(strlen(Topmost->Command) > 0) {
141 CON_NewLineCommand(Topmost);
143 // copy the input into the past commands strings
144 strcpy(Topmost->CommandLines[0], Topmost->Command);
146 // display the command including the prompt
147 CON_Out(Topmost, "%s%s", Topmost->Prompt, Topmost->Command);
148 CON_UpdateConsole(Topmost);
150 CON_Execute(Topmost, Topmost->Command);
151 //printf("Command: %s\n", Topmost->Command);
153 Clear_Command(Topmost);
154 Topmost->CommandScrollBack = -1;
162 if (key_to_ascii(event) == 255)
165 Cursor_Add(Topmost, event);
167 Cursor_Add(Topmost, event);
176 /* CON_AlphaGL() -- sets the alpha channel of an SDL_Surface to the
177 * specified value. Preconditions: the surface in question is RGBA.
178 * 0 <= a <= 255, where 0 is transparent and 255 is opaque. */
179 void CON_AlphaGL(SDL_Surface *s, int alpha) {
184 SDL_PixelFormat *format;
185 static char errorPrinted = 0;
188 /* debugging assertions -- these slow you down, but hey, crashing sucks */
190 PRINT_ERROR("NULL Surface passed to CON_AlphaGL\n");
194 /* clamp alpha value to 0...255 */
195 if(alpha < SDL_ALPHA_TRANSPARENT)
196 val = SDL_ALPHA_TRANSPARENT;
197 else if(alpha > SDL_ALPHA_OPAQUE)
198 val = SDL_ALPHA_OPAQUE;
202 /* loop over alpha channels of each pixel, setting them appropriately. */
206 switch (format->BytesPerPixel) {
208 /* 16-bit surfaces don't seem to support alpha channels. */
211 PRINT_ERROR("16-bit SDL surfaces do not support alpha-blending under OpenGL.\n");
215 /* we can do this very quickly in 32-bit mode. 24-bit is more
216 * difficult. And since 24-bit mode is reall the same as 32-bit,
217 * so it usually ends up taking this route too. Win! Unroll loop
218 * and use pointer arithmetic for extra speed. */
219 int numpixels = h * (w << 2);
220 Uint8 *pix = (Uint8 *) (s->pixels);
221 Uint8 *last = pix + numpixels;
223 if((numpixels & 0x7) == 0)
224 for(pixel = pix + 3; pixel < last; pixel += 32)
225 *pixel = *(pixel + 4) = *(pixel + 8) = *(pixel + 12) = *(pixel + 16) = *(pixel + 20) = *(pixel + 24) = *(pixel + 28) = val;
227 for(pixel = pix + 3; pixel < last; pixel += 4)
232 /* we have no choice but to do this slowly. <sigh> */
233 for(y = 0; y < h; ++y)
234 for(x = 0; x < w; ++x) {
236 /* Lock the surface for direct access to the pixels */
237 if(SDL_MUSTLOCK(s) && SDL_LockSurface(s) < 0) {
238 PRINT_ERROR("Can't lock surface: ");
239 fprintf(stderr, "%s\n", SDL_GetError());
242 pixel = DT_GetPixel(s, x, y);
245 SDL_GetRGBA(pixel, format, &r, &g, &b, &a);
246 pixel = SDL_MapRGBA(format, r, g, b, val);
247 SDL_GetRGBA(pixel, format, &r, &g, &b, &a);
248 DT_PutPixel(s, x, y, pixel);
250 /* unlock surface again */
252 SDL_UnlockSurface(s);
260 /* Updates the console buffer */
261 void CON_UpdateConsole(ConsoleInformation *console) {
265 grs_canvas *canv_save;
271 /* Due to the Blits, the update is not very fast: So only update if it's worth it */
272 if(!CON_isVisible(console))
275 Screenlines = console->ConsoleSurface->cv_h / (CON_LINE_SPACE + console->ConsoleSurface->cv_font->ft_h);
277 canv_save = grd_curcanv;
278 gr_set_current_canvas(console->ConsoleSurface);
281 SDL_FillRect(console->ConsoleSurface, NULL, SDL_MapRGBA(console->ConsoleSurface->format, 0, 0, 0, console->ConsoleAlpha));
287 if(console->OutputScreen->flags & SDL_OPENGLBLIT)
288 SDL_SetAlpha(console->ConsoleSurface, 0, SDL_ALPHA_OPAQUE);
291 /* draw the background image if there is one */
292 if(console->BackgroundImage)
293 gr_bitmap(0, 0, console->BackgroundImage);
295 /* Draw the text from the back buffers, calculate in the scrollback from the user
296 * this is a normal SDL software-mode blit, so we need to temporarily set the ColorKey
297 * for the font, and then clear it when we're done.
300 if((console->OutputScreen->flags & SDL_OPENGLBLIT) && (console->OutputScreen->format->BytesPerPixel > 2)) {
301 Uint32 *pix = (Uint32 *) (CurrentFont->FontSurface->pixels);
302 SDL_SetColorKey(CurrentFont->FontSurface, SDL_SRCCOLORKEY, *pix);
306 //now draw text from last but second line to top
307 for(loop = 0; loop < Screenlines-1 && loop < console->LineBuffer - console->ConsoleScrollBack; loop++) {
308 if(console->ConsoleScrollBack != 0 && loop == 0)
309 for(loop2 = 0; loop2 < (console->VChars / 5) + 1; loop2++)
311 orig_color = FG_COLOR;
312 gr_string(CON_CHAR_BORDER + (loop2*5*console->ConsoleSurface->cv_font->ft_w), (Screenlines - loop - 2) * (CON_LINE_SPACE + console->ConsoleSurface->cv_font->ft_h), CON_SCROLL_INDICATOR);
313 FG_COLOR = orig_color;
317 orig_color = FG_COLOR;
318 gr_string(CON_CHAR_BORDER, (Screenlines - loop - 2) * (CON_LINE_SPACE + console->ConsoleSurface->cv_font->ft_h), console->ConsoleLines[console->ConsoleScrollBack + loop]);
319 FG_COLOR = orig_color;
323 gr_set_current_canvas(canv_save);
326 if(console->OutputScreen->flags & SDL_OPENGLBLIT)
327 SDL_SetColorKey(CurrentFont->FontSurface, 0, 0);
331 void CON_UpdateOffset(ConsoleInformation* console) {
335 switch(console->Visible) {
337 console->RaiseOffset -= CON_OPENCLOSE_SPEED;
338 if(console->RaiseOffset <= 0) {
339 console->RaiseOffset = 0;
340 console->Visible = CON_CLOSED;
344 console->RaiseOffset += CON_OPENCLOSE_SPEED;
345 if(console->RaiseOffset >= console->ConsoleSurface->cv_h) {
346 console->RaiseOffset = console->ConsoleSurface->cv_h;
347 console->Visible = CON_OPEN;
356 /* Draws the console buffer to the screen if the console is "visible" */
357 void CON_DrawConsole(ConsoleInformation *console) {
358 grs_canvas *canv_save;
364 /* only draw if console is visible: here this means, that the console is not CON_CLOSED */
365 if(console->Visible == CON_CLOSED)
368 /* Update the scrolling offset */
369 CON_UpdateOffset(console);
371 /* Update the command line since it has a blinking cursor */
375 /* before drawing, make sure the alpha channel of the console surface is set
376 * properly. (sigh) I wish we didn't have to do this every frame... */
377 if(console->OutputScreen->flags & SDL_OPENGLBLIT)
378 CON_AlphaGL(console->ConsoleSurface, console->ConsoleAlpha);
381 canv_save = grd_curcanv;
382 gr_set_current_canvas(&console->OutputScreen->sc_canvas);
384 clip = gr_create_sub_bitmap(&console->ConsoleSurface->cv_bitmap, 0, console->ConsoleSurface->cv_h - console->RaiseOffset, console->ConsoleSurface->cv_w, console->RaiseOffset);
386 gr_bitmap(console->DispX, console->DispY, clip);
387 gr_free_sub_bitmap(clip);
390 if(console->OutputScreen->flags & SDL_OPENGLBLIT)
391 SDL_UpdateRects(console->OutputScreen, 1, &DestRect);
394 gr_set_current_canvas(canv_save);
398 /* Initializes the console */
399 ConsoleInformation *CON_Init(grs_font *Font, grs_screen *DisplayScreen, int lines, int x, int y, int w, int h)
402 ConsoleInformation *newinfo;
405 /* Create a new console struct and init it. */
406 if((newinfo = (ConsoleInformation *) d_malloc(sizeof(ConsoleInformation))) == NULL) {
407 //PRINT_ERROR("Could not allocate the space for a new console info struct.\n");
410 newinfo->Visible = CON_CLOSED;
411 newinfo->RaiseOffset = 0;
412 newinfo->ConsoleLines = NULL;
413 newinfo->CommandLines = NULL;
414 newinfo->TotalConsoleLines = 0;
415 newinfo->ConsoleScrollBack = 0;
416 newinfo->TotalCommands = 0;
417 newinfo->BackgroundImage = NULL;
419 newinfo->ConsoleAlpha = SDL_ALPHA_OPAQUE;
422 newinfo->InsMode = 1;
423 newinfo->CursorPos = 0;
424 newinfo->CommandScrollBack = 0;
425 newinfo->OutputScreen = DisplayScreen;
426 newinfo->Prompt = CON_DEFAULT_PROMPT;
427 newinfo->HideKey = CON_DEFAULT_HIDEKEY;
429 CON_SetExecuteFunction(newinfo, Default_CmdFunction);
430 CON_SetTabCompletion(newinfo, Default_TabFunction);
431 CON_SetHideFunction(newinfo, Default_HideFunction);
433 /* make sure that the size of the console is valid */
434 if(w > newinfo->OutputScreen->sc_w || w < Font->ft_w * 32)
435 w = newinfo->OutputScreen->sc_w;
436 if(h > newinfo->OutputScreen->sc_h || h < Font->ft_h)
437 h = newinfo->OutputScreen->sc_h;
438 if(x < 0 || x > newinfo->OutputScreen->sc_w - w)
442 if(y < 0 || y > newinfo->OutputScreen->sc_h - h)
447 /* load the console surface */
448 newinfo->ConsoleSurface = gr_create_canvas(w, h);
450 /* Load the consoles font */
452 grs_canvas *canv_save;
454 canv_save = grd_curcanv;
455 gr_set_current_canvas(newinfo->ConsoleSurface);
456 gr_set_curfont(Font);
457 gr_set_fontcolor(gr_getcolor(63,63,63), -1);
458 gr_set_current_canvas(canv_save);
462 /* Load the dirty rectangle for user input */
463 newinfo->InputBackground = gr_create_bitmap(w, newinfo->ConsoleSurface->cv_font->ft_h);
465 SDL_FillRect(newinfo->InputBackground, NULL, SDL_MapRGBA(newinfo->ConsoleSurface->format, 0, 0, 0, SDL_ALPHA_OPAQUE));
468 /* calculate the number of visible characters in the command line */
469 newinfo->VChars = (w - CON_CHAR_BORDER) / newinfo->ConsoleSurface->cv_font->ft_w;
470 if(newinfo->VChars > CON_CHARS_PER_LINE)
471 newinfo->VChars = CON_CHARS_PER_LINE;
473 /* We would like to have a minumum # of lines to guarentee we don't create a memory error */
474 if(h / (CON_LINE_SPACE + newinfo->ConsoleSurface->cv_font->ft_h) > lines)
475 newinfo->LineBuffer = h / (CON_LINE_SPACE + newinfo->ConsoleSurface->cv_font->ft_h);
477 newinfo->LineBuffer = lines;
480 newinfo->ConsoleLines = (char **)d_malloc(sizeof(char *) * newinfo->LineBuffer);
481 newinfo->CommandLines = (char **)d_malloc(sizeof(char *) * newinfo->LineBuffer);
482 for(loop = 0; loop <= newinfo->LineBuffer - 1; loop++) {
483 newinfo->ConsoleLines[loop] = (char *)d_calloc(CON_CHARS_PER_LINE, sizeof(char));
484 newinfo->CommandLines[loop] = (char *)d_calloc(CON_CHARS_PER_LINE, sizeof(char));
486 memset(newinfo->Command, 0, CON_CHARS_PER_LINE);
487 memset(newinfo->LCommand, 0, CON_CHARS_PER_LINE);
488 memset(newinfo->RCommand, 0, CON_CHARS_PER_LINE);
489 memset(newinfo->VCommand, 0, CON_CHARS_PER_LINE);
492 CON_Out(newinfo, "Console initialised.");
493 CON_NewLineConsole(newinfo);
494 //CON_ListCommands(newinfo);
499 /* Makes the console visible */
500 void CON_Show(ConsoleInformation *console) {
502 console->Visible = CON_OPENING;
503 CON_UpdateConsole(console);
507 /* Hides the console (make it invisible) */
508 void CON_Hide(ConsoleInformation *console) {
510 console->Visible = CON_CLOSING;
511 console->HideFunction();
514 /* tells wether the console is visible or not */
515 int CON_isVisible(ConsoleInformation *console) {
518 return((console->Visible == CON_OPEN) || (console->Visible == CON_OPENING));
521 /* Frees all the memory loaded by the console */
522 void CON_Destroy(ConsoleInformation *console) {
526 /* Frees all the memory loaded by the console */
527 void CON_Free(ConsoleInformation *console) {
533 //CON_DestroyCommands();
534 for(i = 0; i <= console->LineBuffer - 1; i++) {
535 d_free(console->ConsoleLines[i]);
536 d_free(console->CommandLines[i]);
538 d_free(console->ConsoleLines);
539 d_free(console->CommandLines);
541 console->ConsoleLines = NULL;
542 console->CommandLines = NULL;
544 gr_free_canvas(console->ConsoleSurface);
545 console->ConsoleSurface = NULL;
547 if (console->BackgroundImage)
548 gr_free_bitmap(console->BackgroundImage);
549 console->BackgroundImage = NULL;
551 gr_free_bitmap(console->InputBackground);
552 console->InputBackground = NULL;
558 /* Increments the console lines */
559 void CON_NewLineConsole(ConsoleInformation *console) {
566 temp = console->ConsoleLines[console->LineBuffer - 1];
568 for(loop = console->LineBuffer - 1; loop > 0; loop--)
569 console->ConsoleLines[loop] = console->ConsoleLines[loop - 1];
571 console->ConsoleLines[0] = temp;
573 memset(console->ConsoleLines[0], 0, CON_CHARS_PER_LINE);
574 if(console->TotalConsoleLines < console->LineBuffer - 1)
575 console->TotalConsoleLines++;
577 //Now adjust the ConsoleScrollBack
578 //dont scroll if not at bottom
579 if(console->ConsoleScrollBack != 0)
580 console->ConsoleScrollBack++;
582 if(console->ConsoleScrollBack > console->LineBuffer-1)
583 console->ConsoleScrollBack = console->LineBuffer-1;
588 /* Increments the command lines */
589 void CON_NewLineCommand(ConsoleInformation *console) {
596 temp = console->CommandLines[console->LineBuffer - 1];
599 for(loop = console->LineBuffer - 1; loop > 0; loop--)
600 console->CommandLines[loop] = console->CommandLines[loop - 1];
602 console->CommandLines[0] = temp;
604 memset(console->CommandLines[0], 0, CON_CHARS_PER_LINE);
605 if(console->TotalCommands < console->LineBuffer - 1)
606 console->TotalCommands++;
609 /* Draws the command line the user is typing in to the screen */
610 /* completely rewritten by C.Wacha */
611 void DrawCommandLine() {
615 grs_font* CurrentFont;
617 static unsigned int LastBlinkTime = 0; /* Last time the consoles cursor blinked */
618 static int LastCursorPos = 0; // Last Cursor Position
619 static int Blink = 0; /* Is the cursor currently blinking */
620 grs_canvas *canv_save;
626 commandbuffer = Topmost->VChars - strlen(Topmost->Prompt)-1; // -1 to make cursor visible
629 CurrentFont = Topmost->ConsoleSurface->cv_font;
632 //Concatenate the left and right side to command
633 strcpy(Topmost->Command, Topmost->LCommand);
634 strncat(Topmost->Command, Topmost->RCommand, strlen(Topmost->RCommand));
636 //calculate display offset from current cursor position
637 if(Topmost->Offset < Topmost->CursorPos - commandbuffer)
638 Topmost->Offset = Topmost->CursorPos - commandbuffer;
639 if(Topmost->Offset > Topmost->CursorPos)
640 Topmost->Offset = Topmost->CursorPos;
642 //first add prompt to visible part
643 strcpy(Topmost->VCommand, Topmost->Prompt);
645 //then add the visible part of the command
646 strncat(Topmost->VCommand, &Topmost->Command[Topmost->Offset], strlen(&Topmost->Command[Topmost->Offset]));
648 //now display the result
651 //once again we're drawing text, so in OpenGL context we need to temporarily set up
652 //software-mode transparency.
653 if(Topmost->OutputScreen->flags & SDL_OPENGLBLIT) {
654 Uint32 *pix = (Uint32 *) (CurrentFont->FontSurface->pixels);
655 SDL_SetColorKey(CurrentFont->FontSurface, SDL_SRCCOLORKEY, *pix);
659 canv_save = grd_curcanv;
660 gr_set_current_canvas(Topmost->ConsoleSurface);
662 //first of all restore InputBackground
663 gr_bitmap(0, Topmost->ConsoleSurface->cv_h - Topmost->ConsoleSurface->cv_font->ft_h, Topmost->InputBackground);
666 orig_color = FG_COLOR;
667 gr_string(CON_CHAR_BORDER, Topmost->ConsoleSurface->cv_h - Topmost->ConsoleSurface->cv_font->ft_h, Topmost->VCommand);
668 FG_COLOR = orig_color;
670 //at last add the cursor
671 //check if the blink period is over
672 if(get_msecs() > LastBlinkTime) {
673 LastBlinkTime = get_msecs() + CON_BLINK_RATE;
680 //check if cursor has moved - if yes display cursor anyway
681 if(Topmost->CursorPos != LastCursorPos) {
682 LastCursorPos = Topmost->CursorPos;
683 LastBlinkTime = get_msecs() + CON_BLINK_RATE;
688 int prompt_width, cmd_width, h, w;
690 gr_get_string_size(Topmost->Prompt, &prompt_width, &h, &w);
691 gr_get_string_size(Topmost->LCommand + Topmost->Offset, &cmd_width, &h, &w);
692 x = CON_CHAR_BORDER + prompt_width + cmd_width;
693 orig_color = FG_COLOR;
695 gr_string(x, Topmost->ConsoleSurface->cv_h - Topmost->ConsoleSurface->cv_font->ft_h, CON_INS_CURSOR);
697 gr_string(x, Topmost->ConsoleSurface->cv_h - Topmost->ConsoleSurface->cv_font->ft_h, CON_OVR_CURSOR);
698 FG_COLOR = orig_color;
701 gr_set_current_canvas(canv_save);
705 if(Topmost->OutputScreen->flags & SDL_OPENGLBLIT) {
706 SDL_SetColorKey(CurrentFont->FontSurface, 0, 0);
712 # define vsnprintf _vsnprintf
715 /* Outputs text to the console (in game), up to CON_CHARS_PER_LINE chars can be entered */
716 void CON_Out(ConsoleInformation *console, const char *str, ...) {
718 //keep some space free for stuff like CON_Out(console, "blablabla %s", console->Command);
719 char temp[CON_CHARS_PER_LINE + 128];
725 va_start(marker, str);
726 vsnprintf(temp, CON_CHARS_PER_LINE + 127, str, marker);
731 //temp now contains the complete string we want to output
732 // the only problem is that temp is maybe longer than the console
733 // width so we have to cut it into several pieces
735 if(console->ConsoleLines) {
736 while(strlen(ptemp) > console->VChars) {
737 CON_NewLineConsole(console);
738 strncpy(console->ConsoleLines[0], ptemp, console->VChars);
739 console->ConsoleLines[0][console->VChars] = '\0';
740 ptemp = &ptemp[console->VChars];
742 CON_NewLineConsole(console);
743 strncpy(console->ConsoleLines[0], ptemp, console->VChars);
744 console->ConsoleLines[0][console->VChars] = '\0';
745 CON_UpdateConsole(console);
748 /* And print to stdout */
749 //printf("%s\n", temp);
754 /* Sets the alpha level of the console, 0 turns off alpha blending */
755 void CON_Alpha(ConsoleInformation *console, unsigned char alpha) {
759 /* store alpha as state! */
760 console->ConsoleAlpha = alpha;
762 if((console->OutputScreen->flags & SDL_OPENGLBLIT) == 0) {
764 SDL_SetAlpha(console->ConsoleSurface, 0, alpha);
766 SDL_SetAlpha(console->ConsoleSurface, SDL_SRCALPHA, alpha);
769 // CON_UpdateConsole(console);
774 /* Adds background image to the console, scaled to size of console*/
775 int CON_Background(ConsoleInformation *console, grs_bitmap *image)
780 /* Free the background from the console */
782 if (console->BackgroundImage)
783 gr_free_bitmap(console->BackgroundImage);
784 console->BackgroundImage = NULL;
786 SDL_FillRect(console->InputBackground, NULL, SDL_MapRGBA(console->ConsoleSurface->format, 0, 0, 0, SDL_ALPHA_OPAQUE));
791 /* Load a new background */
792 if (console->BackgroundImage)
793 gr_free_bitmap(console->BackgroundImage);
794 console->BackgroundImage = gr_create_bitmap(console->ConsoleSurface->cv_w, console->ConsoleSurface->cv_h);
795 gr_bitmap_scale_to(image, console->BackgroundImage);
798 SDL_FillRect(console->InputBackground, NULL, SDL_MapRGBA(console->ConsoleSurface->format, 0, 0, 0, SDL_ALPHA_OPAQUE));
800 gr_bm_bitblt(console->BackgroundImage->bm_w, console->InputBackground->bm_h, 0, 0, 0, console->ConsoleSurface->cv_h - console->ConsoleSurface->cv_font->ft_h, console->BackgroundImage, console->InputBackground);
805 /* Sets font info for the console */
806 void CON_Font(ConsoleInformation *console, grs_font *font, int fg, int bg)
808 grs_canvas *canv_save;
810 canv_save = grd_curcanv;
811 gr_set_current_canvas(console->ConsoleSurface);
812 gr_set_curfont(font);
813 gr_set_fontcolor(fg, bg);
814 gr_set_current_canvas(canv_save);
817 /* takes a new x and y of the top left of the console window */
818 void CON_Position(ConsoleInformation *console, int x, int y) {
822 if(x < 0 || x > console->OutputScreen->sc_w - console->ConsoleSurface->cv_w)
827 if(y < 0 || y > console->OutputScreen->sc_h - console->ConsoleSurface->cv_h)
833 void gr_init_bitmap_alloc( grs_bitmap *bm, int mode, int x, int y, int w, int h, int bytesperline);
834 /* resizes the console, has to reset alot of stuff
835 * returns 1 on error */
836 int CON_Resize(ConsoleInformation *console, int x, int y, int w, int h)
841 /* make sure that the size of the console is valid */
842 if(w > console->OutputScreen->sc_w || w < console->ConsoleSurface->cv_font->ft_w * 32)
843 w = console->OutputScreen->sc_w;
844 if(h > console->OutputScreen->sc_h || h < console->ConsoleSurface->cv_font->ft_h)
845 h = console->OutputScreen->sc_h;
846 if(x < 0 || x > console->OutputScreen->sc_w - w)
850 if(y < 0 || y > console->OutputScreen->sc_h - h)
855 /* resize console surface */
856 gr_free_bitmap_data(&console->ConsoleSurface->cv_bitmap);
857 gr_init_bitmap_alloc(&console->ConsoleSurface->cv_bitmap, BM_LINEAR, 0, 0, w, h, w);
859 /* Load the dirty rectangle for user input */
860 gr_free_bitmap(console->InputBackground);
861 console->InputBackground = gr_create_bitmap(w, console->ConsoleSurface->cv_font->ft_h);
863 /* Now reset some stuff dependent on the previous size */
864 console->ConsoleScrollBack = 0;
866 /* Reload the background image (for the input text area) in the console */
867 if(console->BackgroundImage) {
869 SDL_FillRect(console->InputBackground, NULL, SDL_MapRGBA(console->ConsoleSurface->format, 0, 0, 0, SDL_ALPHA_OPAQUE));
871 gr_bm_bitblt(console->BackgroundImage->bm_w, console->InputBackground->bm_h, 0, 0, 0, console->ConsoleSurface->cv_h - console->ConsoleSurface->cv_font->ft_h, console->BackgroundImage, console->InputBackground);
875 /* restore the alpha level */
876 CON_Alpha(console, console->ConsoleAlpha);
881 /* Transfers the console to another screen surface, and adjusts size */
882 int CON_Transfer(ConsoleInformation *console, grs_screen *new_outputscreen, int x, int y, int w, int h)
887 console->OutputScreen = new_outputscreen;
889 return(CON_Resize(console, x, y, w, h));
892 /* Sets the topmost console for input */
893 void CON_Topmost(ConsoleInformation *console) {
894 grs_canvas *canv_save;
900 // Make sure the blinking cursor is gone
902 canv_save = grd_curcanv;
903 gr_set_current_canvas(Topmost->ConsoleSurface);
905 gr_bitmap(0, Topmost->ConsoleSurface->cv_h - Topmost->ConsoleSurface->cv_font->ft_h, Topmost->InputBackground);
906 orig_color = FG_COLOR;
907 gr_string(CON_CHAR_BORDER, Topmost->ConsoleSurface->cv_h - Topmost->ConsoleSurface->cv_font->ft_h, Topmost->VCommand);
908 FG_COLOR = orig_color;
910 gr_set_current_canvas(canv_save);
915 /* Sets the Prompt for console */
916 void CON_SetPrompt(ConsoleInformation *console, char* newprompt) {
920 //check length so we can still see at least 1 char :-)
921 if(strlen(newprompt) < console->VChars)
922 console->Prompt = d_strdup(newprompt);
924 CON_Out(console, "prompt too long. (max. %i chars)", console->VChars - 1);
927 /* Sets the key that deactivates (hides) the console. */
928 void CON_SetHideKey(ConsoleInformation *console, int key) {
930 console->HideKey = key;
933 void CON_SetHideFunction(ConsoleInformation *console, void(*HideFunction)(void)) {
935 console->HideFunction = HideFunction;
938 void Default_HideFunction(void) {
941 /* Executes the command entered */
942 void CON_Execute(ConsoleInformation *console, char* command) {
944 console->CmdFunction(console, command);
947 void CON_SetExecuteFunction(ConsoleInformation *console, void(*CmdFunction)(ConsoleInformation *console2, char* command)) {
949 console->CmdFunction = CmdFunction;
952 void Default_CmdFunction(ConsoleInformation *console, char* command) {
953 CON_Out(console, " No CommandFunction registered");
954 CON_Out(console, " use 'CON_SetExecuteFunction' to register one");
955 CON_Out(console, " ");
956 CON_Out(console, "Unknown Command \"%s\"", command);
959 void CON_SetTabCompletion(ConsoleInformation *console, char*(*TabFunction)(char* command)) {
961 console->TabFunction = TabFunction;
964 void CON_TabCompletion(ConsoleInformation *console) {
971 command = d_strdup(console->LCommand);
972 command = console->TabFunction(command);
975 return; //no tab completion took place so return silently
978 if(j > CON_CHARS_PER_LINE - 2)
979 j = CON_CHARS_PER_LINE-1;
981 memset(console->LCommand, 0, CON_CHARS_PER_LINE);
982 console->CursorPos = 0;
984 for(i = 0; i < j; i++) {
985 console->CursorPos++;
986 console->LCommand[i] = command[i];
988 //add a trailing space
989 console->CursorPos++;
990 console->LCommand[j] = ' ';
991 console->LCommand[j+1] = '\0';
994 char* Default_TabFunction(char* command) {
995 CON_Out(Topmost, " No TabFunction registered");
996 CON_Out(Topmost, " use 'CON_SetTabCompletion' to register one");
997 CON_Out(Topmost, " ");
1001 void Cursor_Left(ConsoleInformation *console) {
1002 char temp[CON_CHARS_PER_LINE];
1004 if(Topmost->CursorPos > 0) {
1005 Topmost->CursorPos--;
1006 strcpy(temp, Topmost->RCommand);
1007 strcpy(Topmost->RCommand, &Topmost->LCommand[strlen(Topmost->LCommand)-1]);
1008 strcat(Topmost->RCommand, temp);
1009 Topmost->LCommand[strlen(Topmost->LCommand)-1] = '\0';
1010 //CON_Out(Topmost, "L:%s, R:%s", Topmost->LCommand, Topmost->RCommand);
1014 void Cursor_Right(ConsoleInformation *console) {
1015 char temp[CON_CHARS_PER_LINE];
1017 if(Topmost->CursorPos < strlen(Topmost->Command)) {
1018 Topmost->CursorPos++;
1019 strncat(Topmost->LCommand, Topmost->RCommand, 1);
1020 strcpy(temp, Topmost->RCommand);
1021 strcpy(Topmost->RCommand, &temp[1]);
1022 //CON_Out(Topmost, "L:%s, R:%s", Topmost->LCommand, Topmost->RCommand);
1026 void Cursor_Home(ConsoleInformation *console) {
1027 char temp[CON_CHARS_PER_LINE];
1029 Topmost->CursorPos = 0;
1030 strcpy(temp, Topmost->RCommand);
1031 strcpy(Topmost->RCommand, Topmost->LCommand);
1032 strncat(Topmost->RCommand, temp, strlen(temp));
1033 memset(Topmost->LCommand, 0, CON_CHARS_PER_LINE);
1036 void Cursor_End(ConsoleInformation *console) {
1037 Topmost->CursorPos = strlen(Topmost->Command);
1038 strncat(Topmost->LCommand, Topmost->RCommand, strlen(Topmost->RCommand));
1039 memset(Topmost->RCommand, 0, CON_CHARS_PER_LINE);
1042 void Cursor_Del(ConsoleInformation *console) {
1043 char temp[CON_CHARS_PER_LINE];
1045 if(strlen(Topmost->RCommand) > 0) {
1046 strcpy(temp, Topmost->RCommand);
1047 strcpy(Topmost->RCommand, &temp[1]);
1051 void Cursor_BSpace(ConsoleInformation *console) {
1052 if(Topmost->CursorPos > 0) {
1053 Topmost->CursorPos--;
1055 if(Topmost->Offset < 0)
1056 Topmost->Offset = 0;
1057 Topmost->LCommand[strlen(Topmost->LCommand)-1] = '\0';
1061 void Cursor_Add(ConsoleInformation *console, int event)
1063 if(strlen(Topmost->Command) < CON_CHARS_PER_LINE - 1)
1065 Topmost->CursorPos++;
1066 Topmost->LCommand[strlen(Topmost->LCommand)] = key_to_ascii(event);
1067 Topmost->LCommand[strlen(Topmost->LCommand)] = '\0';
1071 void Clear_Command(ConsoleInformation *console) {
1072 Topmost->CursorPos = 0;
1073 memset(Topmost->VCommand, 0, CON_CHARS_PER_LINE);
1074 memset(Topmost->Command, 0, CON_CHARS_PER_LINE);
1075 memset(Topmost->LCommand, 0, CON_CHARS_PER_LINE);
1076 memset(Topmost->RCommand, 0, CON_CHARS_PER_LINE);
1079 void Clear_History(ConsoleInformation *console) {
1082 for(loop = 0; loop <= console->LineBuffer - 1; loop++)
1083 memset(console->ConsoleLines[loop], 0, CON_CHARS_PER_LINE);
1086 void Command_Up(ConsoleInformation *console) {
1087 if(console->CommandScrollBack < console->TotalCommands - 1) {
1088 /* move back a line in the command strings and copy the command to the current input string */
1089 console->CommandScrollBack++;
1090 memset(console->RCommand, 0, CON_CHARS_PER_LINE);
1091 console->Offset = 0;
1092 strcpy(console->LCommand, console->CommandLines[console->CommandScrollBack]);
1093 console->CursorPos = strlen(console->CommandLines[console->CommandScrollBack]);
1094 CON_UpdateConsole(console);
1098 void Command_Down(ConsoleInformation *console) {
1099 if(console->CommandScrollBack > -1) {
1100 /* move forward a line in the command strings and copy the command to the current input string */
1101 console->CommandScrollBack--;
1102 memset(console->RCommand, 0, CON_CHARS_PER_LINE);
1103 memset(console->LCommand, 0, CON_CHARS_PER_LINE);
1104 console->Offset = 0;
1105 if(console->CommandScrollBack > -1)
1106 strcpy(console->LCommand, console->CommandLines[console->CommandScrollBack]);
1107 console->CursorPos = strlen(console->LCommand);
1108 CON_UpdateConsole(console);