2 * Written By: Garrett Banuk <mongoose@mongeese.org>
3 * Code Cleanup and heavily extended by: Clemens Wacha <reflex-2000@gmx.net>
5 * This is free, just be sure to give us credit when using it
6 * in any of your programs.
14 #include "SDL_image.h"
15 #include "CON_console.h"
16 #include "DT_drawtext.h"
20 /* This contains a pointer to the "topmost" console. The console that
21 * is currently taking keyboard input. */
22 static ConsoleInformation *Topmost;
24 /* Takes keys from the keyboard and inputs them to the console
25 If the event was not handled (i.e. WM events or unknown ctrl-shift
26 sequences) the function returns the event for further processing. */
27 SDL_Event* CON_Events(SDL_Event *event) {
30 if(!CON_isVisible(Topmost))
33 if(event->type == SDL_KEYDOWN) {
34 if(event->key.keysym.mod & KMOD_CTRL) {
36 switch(event->key.keysym.sym) {
44 Clear_Command(Topmost);
47 Clear_History(Topmost);
48 CON_UpdateConsole(Topmost);
53 } else if(event->key.keysym.mod & KMOD_ALT) {
54 //the console does not handle ALT combinations!
57 //first of all, check if the console hide key was pressed
58 if(event->key.keysym.sym == Topmost->HideKey) {
62 switch (event->key.keysym.sym) {
64 if(event->key.keysym.mod & KMOD_SHIFT) {
65 Topmost->ConsoleScrollBack = Topmost->LineBuffer-1;
66 CON_UpdateConsole(Topmost);
72 if(event->key.keysym.mod & KMOD_SHIFT) {
73 Topmost->ConsoleScrollBack = 0;
74 CON_UpdateConsole(Topmost);
80 Topmost->ConsoleScrollBack += CON_LINE_SCROLL;
81 if(Topmost->ConsoleScrollBack > Topmost->LineBuffer-1)
82 Topmost->ConsoleScrollBack = Topmost->LineBuffer-1;
84 CON_UpdateConsole(Topmost);
87 Topmost->ConsoleScrollBack -= CON_LINE_SCROLL;
88 if(Topmost->ConsoleScrollBack < 0)
89 Topmost->ConsoleScrollBack = 0;
90 CON_UpdateConsole(Topmost);
96 Command_Down(Topmost);
102 Cursor_Right(Topmost);
105 Cursor_BSpace(Topmost);
111 Topmost->InsMode = 1-Topmost->InsMode;
114 CON_TabCompletion(Topmost);
117 if(strlen(Topmost->Command) > 0) {
118 CON_NewLineCommand(Topmost);
120 // copy the input into the past commands strings
121 strcpy(Topmost->CommandLines[0], Topmost->Command);
123 // display the command including the prompt
124 CON_Out(Topmost, "%s%s", Topmost->Prompt, Topmost->Command);
125 CON_UpdateConsole(Topmost);
127 CON_Execute(Topmost, Topmost->Command);
128 //printf("Command: %s\n", Topmost->Command);
130 Clear_Command(Topmost);
131 Topmost->CommandScrollBack = -1;
140 Cursor_Add(Topmost, event);
142 Cursor_Add(Topmost, event);
152 /* CON_AlphaGL() -- sets the alpha channel of an SDL_Surface to the
153 * specified value. Preconditions: the surface in question is RGBA.
154 * 0 <= a <= 255, where 0 is transparent and 255 is opaque. */
155 void CON_AlphaGL(SDL_Surface *s, int alpha) {
160 SDL_PixelFormat *format;
161 static char errorPrinted = 0;
164 /* debugging assertions -- these slow you down, but hey, crashing sucks */
166 PRINT_ERROR("NULL Surface passed to CON_AlphaGL\n");
170 /* clamp alpha value to 0...255 */
171 if(alpha < SDL_ALPHA_TRANSPARENT)
172 val = SDL_ALPHA_TRANSPARENT;
173 else if(alpha > SDL_ALPHA_OPAQUE)
174 val = SDL_ALPHA_OPAQUE;
178 /* loop over alpha channels of each pixel, setting them appropriately. */
182 switch (format->BytesPerPixel) {
184 /* 16-bit surfaces don't seem to support alpha channels. */
187 PRINT_ERROR("16-bit SDL surfaces do not support alpha-blending under OpenGL.\n");
191 /* we can do this very quickly in 32-bit mode. 24-bit is more
192 * difficult. And since 24-bit mode is reall the same as 32-bit,
193 * so it usually ends up taking this route too. Win! Unroll loop
194 * and use pointer arithmetic for extra speed. */
195 int numpixels = h * (w << 2);
196 Uint8 *pix = (Uint8 *) (s->pixels);
197 Uint8 *last = pix + numpixels;
199 if((numpixels & 0x7) == 0)
200 for(pixel = pix + 3; pixel < last; pixel += 32)
201 *pixel = *(pixel + 4) = *(pixel + 8) = *(pixel + 12) = *(pixel + 16) = *(pixel + 20) = *(pixel + 24) = *(pixel + 28) = val;
203 for(pixel = pix + 3; pixel < last; pixel += 4)
208 /* we have no choice but to do this slowly. <sigh> */
209 for(y = 0; y < h; ++y)
210 for(x = 0; x < w; ++x) {
212 /* Lock the surface for direct access to the pixels */
213 if(SDL_MUSTLOCK(s) && SDL_LockSurface(s) < 0) {
214 PRINT_ERROR("Can't lock surface: ");
215 fprintf(stderr, "%s\n", SDL_GetError());
218 pixel = DT_GetPixel(s, x, y);
221 SDL_GetRGBA(pixel, format, &r, &g, &b, &a);
222 pixel = SDL_MapRGBA(format, r, g, b, val);
223 SDL_GetRGBA(pixel, format, &r, &g, &b, &a);
224 DT_PutPixel(s, x, y, pixel);
226 /* unlock surface again */
228 SDL_UnlockSurface(s);
235 /* Updates the console buffer */
236 void CON_UpdateConsole(ConsoleInformation *console) {
241 BitFont *CurrentFont = DT_FontPointer(console->FontNumber);
246 /* Due to the Blits, the update is not very fast: So only update if it's worth it */
247 if(!CON_isVisible(console))
250 Screenlines = console->ConsoleSurface->h / console->FontHeight;
253 SDL_FillRect(console->ConsoleSurface, NULL, SDL_MapRGBA(console->ConsoleSurface->format, 0, 0, 0, console->ConsoleAlpha));
255 if(console->OutputScreen->flags & SDL_OPENGLBLIT)
256 SDL_SetAlpha(console->ConsoleSurface, 0, SDL_ALPHA_OPAQUE);
258 /* draw the background image if there is one */
259 if(console->BackgroundImage) {
260 DestRect.x = console->BackX;
261 DestRect.y = console->BackY;
262 DestRect.w = console->BackgroundImage->w;
263 DestRect.h = console->BackgroundImage->h;
264 SDL_BlitSurface(console->BackgroundImage, NULL, console->ConsoleSurface, &DestRect);
267 /* Draw the text from the back buffers, calculate in the scrollback from the user
268 * this is a normal SDL software-mode blit, so we need to temporarily set the ColorKey
269 * for the font, and then clear it when we're done.
271 if((console->OutputScreen->flags & SDL_OPENGLBLIT) && (console->OutputScreen->format->BytesPerPixel > 2)) {
272 Uint32 *pix = (Uint32 *) (CurrentFont->FontSurface->pixels);
273 SDL_SetColorKey(CurrentFont->FontSurface, SDL_SRCCOLORKEY, *pix);
277 //now draw text from last but second line to top
278 for(loop = 0; loop < Screenlines-1 && loop < console->LineBuffer - console->ConsoleScrollBack; loop++) {
279 if(console->ConsoleScrollBack != 0 && loop == 0)
280 for(loop2 = 0; loop2 < (console->VChars / 5) + 1; loop2++)
281 DT_DrawText(CON_SCROLL_INDICATOR, console->ConsoleSurface, console->FontNumber, CON_CHAR_BORDER + (loop2*5*console->FontWidth), (Screenlines - loop - 2) * console->FontHeight);
283 DT_DrawText(console->ConsoleLines[console->ConsoleScrollBack + loop], console->ConsoleSurface, console->FontNumber, CON_CHAR_BORDER, (Screenlines - loop - 2) * console->FontHeight);
286 if(console->OutputScreen->flags & SDL_OPENGLBLIT)
287 SDL_SetColorKey(CurrentFont->FontSurface, 0, 0);
290 void CON_UpdateOffset(ConsoleInformation* console) {
294 switch(console->Visible) {
296 console->RaiseOffset -= CON_OPENCLOSE_SPEED;
297 if(console->RaiseOffset <= 0) {
298 console->RaiseOffset = 0;
299 console->Visible = CON_CLOSED;
303 console->RaiseOffset += CON_OPENCLOSE_SPEED;
304 if(console->RaiseOffset >= console->ConsoleSurface->h) {
305 console->RaiseOffset = console->ConsoleSurface->h;
306 console->Visible = CON_OPEN;
315 /* Draws the console buffer to the screen if the console is "visible" */
316 void CON_DrawConsole(ConsoleInformation *console) {
323 /* only draw if console is visible: here this means, that the console is not CON_CLOSED */
324 if(console->Visible == CON_CLOSED)
327 /* Update the scrolling offset */
328 CON_UpdateOffset(console);
330 /* Update the command line since it has a blinking cursor */
333 /* before drawing, make sure the alpha channel of the console surface is set
334 * properly. (sigh) I wish we didn't have to do this every frame... */
335 if(console->OutputScreen->flags & SDL_OPENGLBLIT)
336 CON_AlphaGL(console->ConsoleSurface, console->ConsoleAlpha);
339 SrcRect.y = console->ConsoleSurface->h - console->RaiseOffset;
340 SrcRect.w = console->ConsoleSurface->w;
341 SrcRect.h = console->RaiseOffset;
343 /* Setup the rect the console is being blitted into based on the output screen */
344 DestRect.x = console->DispX;
345 DestRect.y = console->DispY;
346 DestRect.w = console->ConsoleSurface->w;
347 DestRect.h = console->ConsoleSurface->h;
349 SDL_BlitSurface(console->ConsoleSurface, &SrcRect, console->OutputScreen, &DestRect);
351 if(console->OutputScreen->flags & SDL_OPENGLBLIT)
352 SDL_UpdateRects(console->OutputScreen, 1, &DestRect);
356 /* Initializes the console */
357 ConsoleInformation *CON_Init(const char *FontName, SDL_Surface *DisplayScreen, int lines, SDL_Rect rect) {
360 ConsoleInformation *newinfo;
363 /* Create a new console struct and init it. */
364 if((newinfo = (ConsoleInformation *) malloc(sizeof(ConsoleInformation))) == NULL) {
365 PRINT_ERROR("Could not allocate the space for a new console info struct.\n");
368 newinfo->Visible = CON_CLOSED;
369 newinfo->WasUnicode = 0;
370 newinfo->RaiseOffset = 0;
371 newinfo->ConsoleLines = NULL;
372 newinfo->CommandLines = NULL;
373 newinfo->TotalConsoleLines = 0;
374 newinfo->ConsoleScrollBack = 0;
375 newinfo->TotalCommands = 0;
376 newinfo->BackgroundImage = NULL;
377 newinfo->ConsoleAlpha = SDL_ALPHA_OPAQUE;
379 newinfo->InsMode = 1;
380 newinfo->CursorPos = 0;
381 newinfo->CommandScrollBack = 0;
382 newinfo->OutputScreen = DisplayScreen;
383 newinfo->Prompt = CON_DEFAULT_PROMPT;
384 newinfo->HideKey = CON_DEFAULT_HIDEKEY;
386 CON_SetExecuteFunction(newinfo, Default_CmdFunction);
387 CON_SetTabCompletion(newinfo, Default_TabFunction);
389 /* Load the consoles font */
390 if(-1 == (newinfo->FontNumber = DT_LoadFont(FontName, TRANS_FONT))) {
391 PRINT_ERROR("Could not load the font ");
392 fprintf(stderr, "\"%s\" for the console!\n", FontName);
396 newinfo->FontHeight = DT_FontHeight(newinfo->FontNumber);
397 newinfo->FontWidth = DT_FontWidth(newinfo->FontNumber);
399 /* make sure that the size of the console is valid */
400 if(rect.w > newinfo->OutputScreen->w || rect.w < newinfo->FontWidth * 32)
401 rect.w = newinfo->OutputScreen->w;
402 if(rect.h > newinfo->OutputScreen->h || rect.h < newinfo->FontHeight)
403 rect.h = newinfo->OutputScreen->h;
404 if(rect.x < 0 || rect.x > newinfo->OutputScreen->w - rect.w)
407 newinfo->DispX = rect.x;
408 if(rect.y < 0 || rect.y > newinfo->OutputScreen->h - rect.h)
411 newinfo->DispY = rect.y;
413 /* load the console surface */
414 Temp = SDL_CreateRGBSurface(SDL_SWSURFACE, rect.w, rect.h, newinfo->OutputScreen->format->BitsPerPixel, 0, 0, 0, 0);
416 PRINT_ERROR("Couldn't create the ConsoleSurface\n");
419 newinfo->ConsoleSurface = SDL_DisplayFormat(Temp);
420 SDL_FreeSurface(Temp);
421 SDL_FillRect(newinfo->ConsoleSurface, NULL, SDL_MapRGBA(newinfo->ConsoleSurface->format, 0, 0, 0, newinfo->ConsoleAlpha));
423 /* Load the dirty rectangle for user input */
424 Temp = SDL_CreateRGBSurface(SDL_SWSURFACE, rect.w, newinfo->FontHeight, newinfo->OutputScreen->format->BitsPerPixel, 0, 0, 0, SDL_ALPHA_OPAQUE);
426 PRINT_ERROR("Couldn't create the InputBackground\n");
429 newinfo->InputBackground = SDL_DisplayFormat(Temp);
430 SDL_FreeSurface(Temp);
431 SDL_FillRect(newinfo->InputBackground, NULL, SDL_MapRGBA(newinfo->ConsoleSurface->format, 0, 0, 0, SDL_ALPHA_OPAQUE));
433 /* calculate the number of visible characters in the command line */
434 newinfo->VChars = (rect.w - CON_CHAR_BORDER) / newinfo->FontWidth;
435 if(newinfo->VChars > CON_CHARS_PER_LINE)
436 newinfo->VChars = CON_CHARS_PER_LINE;
438 /* We would like to have a minumum # of lines to guarentee we don't create a memory error */
439 if(rect.h / newinfo->FontHeight > lines)
440 newinfo->LineBuffer = rect.h / newinfo->FontHeight;
442 newinfo->LineBuffer = lines;
445 newinfo->ConsoleLines = (char **)malloc(sizeof(char *) * newinfo->LineBuffer);
446 newinfo->CommandLines = (char **)malloc(sizeof(char *) * newinfo->LineBuffer);
447 for(loop = 0; loop <= newinfo->LineBuffer - 1; loop++) {
448 newinfo->ConsoleLines[loop] = (char *)calloc(CON_CHARS_PER_LINE, sizeof(char));
449 newinfo->CommandLines[loop] = (char *)calloc(CON_CHARS_PER_LINE, sizeof(char));
451 memset(newinfo->Command, 0, CON_CHARS_PER_LINE);
452 memset(newinfo->LCommand, 0, CON_CHARS_PER_LINE);
453 memset(newinfo->RCommand, 0, CON_CHARS_PER_LINE);
454 memset(newinfo->VCommand, 0, CON_CHARS_PER_LINE);
457 CON_Out(newinfo, "Console initialised.");
458 CON_NewLineConsole(newinfo);
459 //CON_ListCommands(newinfo);
464 /* Makes the console visible */
465 void CON_Show(ConsoleInformation *console) {
467 console->Visible = CON_OPENING;
468 CON_UpdateConsole(console);
470 console->WasUnicode = SDL_EnableUNICODE(-1);
471 SDL_EnableUNICODE(1);
475 /* Hides the console (make it invisible) */
476 void CON_Hide(ConsoleInformation *console) {
478 console->Visible = CON_CLOSING;
479 SDL_EnableUNICODE(console->WasUnicode);
483 /* tells wether the console is visible or not */
484 int CON_isVisible(ConsoleInformation *console) {
487 return((console->Visible == CON_OPEN) || (console->Visible == CON_OPENING));
490 /* Frees all the memory loaded by the console */
491 void CON_Destroy(ConsoleInformation *console) {
492 DT_DestroyDrawText();
496 /* Frees all the memory loaded by the console */
497 void CON_Free(ConsoleInformation *console) {
503 //CON_DestroyCommands();
504 for(i = 0; i <= console->LineBuffer - 1; i++) {
505 free(console->ConsoleLines[i]);
506 free(console->CommandLines[i]);
508 free(console->ConsoleLines);
509 free(console->CommandLines);
511 console->ConsoleLines = NULL;
512 console->CommandLines = NULL;
517 /* Increments the console lines */
518 void CON_NewLineConsole(ConsoleInformation *console) {
525 temp = console->ConsoleLines[console->LineBuffer - 1];
527 for(loop = console->LineBuffer - 1; loop > 0; loop--)
528 console->ConsoleLines[loop] = console->ConsoleLines[loop - 1];
530 console->ConsoleLines[0] = temp;
532 memset(console->ConsoleLines[0], 0, CON_CHARS_PER_LINE);
533 if(console->TotalConsoleLines < console->LineBuffer - 1)
534 console->TotalConsoleLines++;
536 //Now adjust the ConsoleScrollBack
537 //dont scroll if not at bottom
538 if(console->ConsoleScrollBack != 0)
539 console->ConsoleScrollBack++;
541 if(console->ConsoleScrollBack > console->LineBuffer-1)
542 console->ConsoleScrollBack = console->LineBuffer-1;
547 /* Increments the command lines */
548 void CON_NewLineCommand(ConsoleInformation *console) {
555 temp = console->CommandLines[console->LineBuffer - 1];
558 for(loop = console->LineBuffer - 1; loop > 0; loop--)
559 console->CommandLines[loop] = console->CommandLines[loop - 1];
561 console->CommandLines[0] = temp;
563 memset(console->CommandLines[0], 0, CON_CHARS_PER_LINE);
564 if(console->TotalCommands < console->LineBuffer - 1)
565 console->TotalCommands++;
568 /* Draws the command line the user is typing in to the screen */
569 /* completely rewritten by C.Wacha */
570 void DrawCommandLine() {
574 BitFont* CurrentFont;
575 static Uint32 LastBlinkTime = 0; /* Last time the consoles cursor blinked */
576 static int LastCursorPos = 0; // Last Cursor Position
577 static int Blink = 0; /* Is the cursor currently blinking */
582 commandbuffer = Topmost->VChars - strlen(Topmost->Prompt)-1; // -1 to make cursor visible
584 CurrentFont = DT_FontPointer(Topmost->FontNumber);
586 //Concatenate the left and right side to command
587 strcpy(Topmost->Command, Topmost->LCommand);
588 strncat(Topmost->Command, Topmost->RCommand, strlen(Topmost->RCommand));
590 //calculate display offset from current cursor position
591 if(Topmost->Offset < Topmost->CursorPos - commandbuffer)
592 Topmost->Offset = Topmost->CursorPos - commandbuffer;
593 if(Topmost->Offset > Topmost->CursorPos)
594 Topmost->Offset = Topmost->CursorPos;
596 //first add prompt to visible part
597 strcpy(Topmost->VCommand, Topmost->Prompt);
599 //then add the visible part of the command
600 strncat(Topmost->VCommand, &Topmost->Command[Topmost->Offset], strlen(&Topmost->Command[Topmost->Offset]));
602 //now display the result
604 //once again we're drawing text, so in OpenGL context we need to temporarily set up
605 //software-mode transparency.
606 if(Topmost->OutputScreen->flags & SDL_OPENGLBLIT) {
607 Uint32 *pix = (Uint32 *) (CurrentFont->FontSurface->pixels);
608 SDL_SetColorKey(CurrentFont->FontSurface, SDL_SRCCOLORKEY, *pix);
611 //first of all restore InputBackground
613 rect.y = Topmost->ConsoleSurface->h - Topmost->FontHeight;
614 rect.w = Topmost->InputBackground->w;
615 rect.h = Topmost->InputBackground->h;
616 SDL_BlitSurface(Topmost->InputBackground, NULL, Topmost->ConsoleSurface, &rect);
619 DT_DrawText(Topmost->VCommand, Topmost->ConsoleSurface, Topmost->FontNumber, CON_CHAR_BORDER, Topmost->ConsoleSurface->h - Topmost->FontHeight);
621 //at last add the cursor
622 //check if the blink period is over
623 if(SDL_GetTicks() > LastBlinkTime) {
624 LastBlinkTime = SDL_GetTicks() + CON_BLINK_RATE;
631 //check if cursor has moved - if yes display cursor anyway
632 if(Topmost->CursorPos != LastCursorPos) {
633 LastCursorPos = Topmost->CursorPos;
634 LastBlinkTime = SDL_GetTicks() + CON_BLINK_RATE;
639 x = CON_CHAR_BORDER + Topmost->FontWidth * (Topmost->CursorPos - Topmost->Offset + strlen(Topmost->Prompt));
641 DT_DrawText(CON_INS_CURSOR, Topmost->ConsoleSurface, Topmost->FontNumber, x, Topmost->ConsoleSurface->h - Topmost->FontHeight);
643 DT_DrawText(CON_OVR_CURSOR, Topmost->ConsoleSurface, Topmost->FontNumber, x, Topmost->ConsoleSurface->h - Topmost->FontHeight);
647 if(Topmost->OutputScreen->flags & SDL_OPENGLBLIT) {
648 SDL_SetColorKey(CurrentFont->FontSurface, 0, 0);
652 /* Outputs text to the console (in game), up to CON_CHARS_PER_LINE chars can be entered */
653 void CON_Out(ConsoleInformation *console, const char *str, ...) {
655 //keep some space free for stuff like CON_Out(console, "blablabla %s", console->Command);
656 char temp[CON_CHARS_PER_LINE + 128];
662 va_start(marker, str);
663 vsnprintf(temp, CON_CHARS_PER_LINE + 127, str, marker);
668 //temp now contains the complete string we want to output
669 // the only problem is that temp is maybe longer than the console
670 // width so we have to cut it into several pieces
672 if(console->ConsoleLines) {
673 while(strlen(ptemp) > console->VChars) {
674 CON_NewLineConsole(console);
675 strncpy(console->ConsoleLines[0], ptemp, console->VChars);
676 console->ConsoleLines[0][console->VChars] = '\0';
677 ptemp = &ptemp[console->VChars];
679 CON_NewLineConsole(console);
680 strncpy(console->ConsoleLines[0], ptemp, console->VChars);
681 console->ConsoleLines[0][console->VChars] = '\0';
682 CON_UpdateConsole(console);
685 /* And print to stdout */
686 //printf("%s\n", temp);
690 /* Sets the alpha level of the console, 0 turns off alpha blending */
691 void CON_Alpha(ConsoleInformation *console, unsigned char alpha) {
695 /* store alpha as state! */
696 console->ConsoleAlpha = alpha;
698 if((console->OutputScreen->flags & SDL_OPENGLBLIT) == 0) {
700 SDL_SetAlpha(console->ConsoleSurface, 0, alpha);
702 SDL_SetAlpha(console->ConsoleSurface, SDL_SRCALPHA, alpha);
705 // CON_UpdateConsole(console);
709 /* Adds background image to the console, x and y based on consoles x and y */
710 int CON_Background(ConsoleInformation *console, const char *image, int x, int y) {
712 SDL_Rect backgroundsrc, backgrounddest;
717 /* Free the background from the console */
719 if(console->BackgroundImage ==NULL)
720 SDL_FreeSurface(console->BackgroundImage);
721 console->BackgroundImage = NULL;
722 SDL_FillRect(console->InputBackground, NULL, SDL_MapRGBA(console->ConsoleSurface->format, 0, 0, 0, SDL_ALPHA_OPAQUE));
726 /* Load a new background */
727 temp = IMG_Load(image);
729 CON_Out(console, "Cannot load background %s.", image);
733 console->BackgroundImage = SDL_DisplayFormat(temp);
734 SDL_FreeSurface(temp);
739 backgroundsrc.y = console->ConsoleSurface->h - console->FontHeight - console->BackY;
740 backgroundsrc.w = console->BackgroundImage->w;
741 backgroundsrc.h = console->InputBackground->h;
743 backgrounddest.x = console->BackX;
744 backgrounddest.y = 0;
745 backgrounddest.w = console->BackgroundImage->w;
746 backgrounddest.h = console->FontHeight;
748 SDL_FillRect(console->InputBackground, NULL, SDL_MapRGBA(console->ConsoleSurface->format, 0, 0, 0, SDL_ALPHA_OPAQUE));
749 SDL_BlitSurface(console->BackgroundImage, &backgroundsrc, console->InputBackground, &backgrounddest);
754 /* takes a new x and y of the top left of the console window */
755 void CON_Position(ConsoleInformation *console, int x, int y) {
759 if(x < 0 || x > console->OutputScreen->w - console->ConsoleSurface->w)
764 if(y < 0 || y > console->OutputScreen->h - console->ConsoleSurface->h)
770 /* resizes the console, has to reset alot of stuff
771 * returns 1 on error */
772 int CON_Resize(ConsoleInformation *console, SDL_Rect rect) {
774 SDL_Rect backgroundsrc, backgrounddest;
779 /* make sure that the size of the console is valid */
780 if(rect.w > console->OutputScreen->w || rect.w < console->FontWidth * 32)
781 rect.w = console->OutputScreen->w;
782 if(rect.h > console->OutputScreen->h || rect.h < console->FontHeight)
783 rect.h = console->OutputScreen->h;
784 if(rect.x < 0 || rect.x > console->OutputScreen->w - rect.w)
787 console->DispX = rect.x;
788 if(rect.y < 0 || rect.y > console->OutputScreen->h - rect.h)
791 console->DispY = rect.y;
793 /* load the console surface */
794 SDL_FreeSurface(console->ConsoleSurface);
795 Temp = SDL_CreateRGBSurface(SDL_SWSURFACE, rect.w, rect.h, console->OutputScreen->format->BitsPerPixel, 0, 0, 0, 0);
797 PRINT_ERROR("Couldn't create the console->ConsoleSurface\n");
800 console->ConsoleSurface = SDL_DisplayFormat(Temp);
801 SDL_FreeSurface(Temp);
803 /* Load the dirty rectangle for user input */
804 SDL_FreeSurface(console->InputBackground);
805 Temp = SDL_CreateRGBSurface(SDL_SWSURFACE, rect.w, console->FontHeight, console->OutputScreen->format->BitsPerPixel, 0, 0, 0, 0);
807 PRINT_ERROR("Couldn't create the input background\n");
810 console->InputBackground = SDL_DisplayFormat(Temp);
811 SDL_FreeSurface(Temp);
813 /* Now reset some stuff dependent on the previous size */
814 console->ConsoleScrollBack = 0;
816 /* Reload the background image (for the input text area) in the console */
817 if(console->BackgroundImage) {
819 backgroundsrc.y = console->ConsoleSurface->h - console->FontHeight - console->BackY;
820 backgroundsrc.w = console->BackgroundImage->w;
821 backgroundsrc.h = console->InputBackground->h;
823 backgrounddest.x = console->BackX;
824 backgrounddest.y = 0;
825 backgrounddest.w = console->BackgroundImage->w;
826 backgrounddest.h = console->FontHeight;
828 SDL_FillRect(console->InputBackground, NULL, SDL_MapRGBA(console->ConsoleSurface->format, 0, 0, 0, SDL_ALPHA_OPAQUE));
829 SDL_BlitSurface(console->BackgroundImage, &backgroundsrc, console->InputBackground, &backgrounddest);
832 /* restore the alpha level */
833 CON_Alpha(console, console->ConsoleAlpha);
837 /* Transfers the console to another screen surface, and adjusts size */
838 int CON_Transfer(ConsoleInformation* console, SDL_Surface* new_outputscreen, SDL_Rect rect) {
842 console->OutputScreen = new_outputscreen;
844 return( CON_Resize(console, rect) );
847 /* Sets the topmost console for input */
848 void CON_Topmost(ConsoleInformation *console) {
854 // Make sure the blinking cursor is gone
857 rect.y = Topmost->ConsoleSurface->h - Topmost->FontHeight;
858 rect.w = Topmost->InputBackground->w;
859 rect.h = Topmost->InputBackground->h;
860 SDL_BlitSurface(Topmost->InputBackground, NULL, Topmost->ConsoleSurface, &rect);
861 DT_DrawText(Topmost->VCommand, Topmost->ConsoleSurface, Topmost->FontNumber, CON_CHAR_BORDER, Topmost->ConsoleSurface->h - Topmost->FontHeight);
866 /* Sets the Prompt for console */
867 void CON_SetPrompt(ConsoleInformation *console, char* newprompt) {
871 //check length so we can still see at least 1 char :-)
872 if(strlen(newprompt) < console->VChars)
873 console->Prompt = strdup(newprompt);
875 CON_Out(console, "prompt too long. (max. %i chars)", console->VChars - 1);
878 /* Sets the key that deactivates (hides) the console. */
879 void CON_SetHideKey(ConsoleInformation *console, int key) {
881 console->HideKey = key;
884 /* Executes the command entered */
885 void CON_Execute(ConsoleInformation *console, char* command) {
887 console->CmdFunction(console, command);
890 void CON_SetExecuteFunction(ConsoleInformation *console, void(*CmdFunction)(ConsoleInformation *console2, char* command)) {
892 console->CmdFunction = CmdFunction;
895 void Default_CmdFunction(ConsoleInformation *console, char* command) {
896 CON_Out(console, " No CommandFunction registered");
897 CON_Out(console, " use 'CON_SetExecuteFunction' to register one");
898 CON_Out(console, " ");
899 CON_Out(console, "Unknown Command \"%s\"", command);
902 void CON_SetTabCompletion(ConsoleInformation *console, char*(*TabFunction)(char* command)) {
904 console->TabFunction = TabFunction;
907 void CON_TabCompletion(ConsoleInformation *console) {
914 command = strdup(console->LCommand);
915 command = console->TabFunction(command);
918 return; //no tab completion took place so return silently
921 if(j > CON_CHARS_PER_LINE - 2)
922 j = CON_CHARS_PER_LINE-1;
924 memset(console->LCommand, 0, CON_CHARS_PER_LINE);
925 console->CursorPos = 0;
927 for(i = 0; i < j; i++) {
928 console->CursorPos++;
929 console->LCommand[i] = command[i];
931 //add a trailing space
932 console->CursorPos++;
933 console->LCommand[j] = ' ';
934 console->LCommand[j+1] = '\0';
937 char* Default_TabFunction(char* command) {
938 CON_Out(Topmost, " No TabFunction registered");
939 CON_Out(Topmost, " use 'CON_SetTabCompletion' to register one");
940 CON_Out(Topmost, " ");
944 void Cursor_Left(ConsoleInformation *console) {
945 char temp[CON_CHARS_PER_LINE];
947 if(Topmost->CursorPos > 0) {
948 Topmost->CursorPos--;
949 strcpy(temp, Topmost->RCommand);
950 strcpy(Topmost->RCommand, &Topmost->LCommand[strlen(Topmost->LCommand)-1]);
951 strcat(Topmost->RCommand, temp);
952 Topmost->LCommand[strlen(Topmost->LCommand)-1] = '\0';
953 //CON_Out(Topmost, "L:%s, R:%s", Topmost->LCommand, Topmost->RCommand);
957 void Cursor_Right(ConsoleInformation *console) {
958 char temp[CON_CHARS_PER_LINE];
960 if(Topmost->CursorPos < strlen(Topmost->Command)) {
961 Topmost->CursorPos++;
962 strncat(Topmost->LCommand, Topmost->RCommand, 1);
963 strcpy(temp, Topmost->RCommand);
964 strcpy(Topmost->RCommand, &temp[1]);
965 //CON_Out(Topmost, "L:%s, R:%s", Topmost->LCommand, Topmost->RCommand);
969 void Cursor_Home(ConsoleInformation *console) {
970 char temp[CON_CHARS_PER_LINE];
972 Topmost->CursorPos = 0;
973 strcpy(temp, Topmost->RCommand);
974 strcpy(Topmost->RCommand, Topmost->LCommand);
975 strncat(Topmost->RCommand, temp, strlen(temp));
976 memset(Topmost->LCommand, 0, CON_CHARS_PER_LINE);
979 void Cursor_End(ConsoleInformation *console) {
980 Topmost->CursorPos = strlen(Topmost->Command);
981 strncat(Topmost->LCommand, Topmost->RCommand, strlen(Topmost->RCommand));
982 memset(Topmost->RCommand, 0, CON_CHARS_PER_LINE);
985 void Cursor_Del(ConsoleInformation *console) {
986 char temp[CON_CHARS_PER_LINE];
988 if(strlen(Topmost->RCommand) > 0) {
989 strcpy(temp, Topmost->RCommand);
990 strcpy(Topmost->RCommand, &temp[1]);
994 void Cursor_BSpace(ConsoleInformation *console) {
995 if(Topmost->CursorPos > 0) {
996 Topmost->CursorPos--;
998 if(Topmost->Offset < 0)
1000 Topmost->LCommand[strlen(Topmost->LCommand)-1] = '\0';
1004 void Cursor_Add(ConsoleInformation *console, SDL_Event *event) {
1005 if(strlen(Topmost->Command) < CON_CHARS_PER_LINE - 1 && event->key.keysym.unicode) {
1006 Topmost->CursorPos++;
1007 Topmost->LCommand[strlen(Topmost->LCommand)] = (char)event->key.keysym.unicode;
1008 Topmost->LCommand[strlen(Topmost->LCommand)] = '\0';
1012 void Clear_Command(ConsoleInformation *console) {
1013 Topmost->CursorPos = 0;
1014 memset(Topmost->VCommand, 0, CON_CHARS_PER_LINE);
1015 memset(Topmost->Command, 0, CON_CHARS_PER_LINE);
1016 memset(Topmost->LCommand, 0, CON_CHARS_PER_LINE);
1017 memset(Topmost->RCommand, 0, CON_CHARS_PER_LINE);
1020 void Clear_History(ConsoleInformation *console) {
1023 for(loop = 0; loop <= console->LineBuffer - 1; loop++)
1024 memset(console->ConsoleLines[loop], 0, CON_CHARS_PER_LINE);
1027 void Command_Up(ConsoleInformation *console) {
1028 if(console->CommandScrollBack < console->TotalCommands - 1) {
1029 /* move back a line in the command strings and copy the command to the current input string */
1030 console->CommandScrollBack++;
1031 memset(console->RCommand, 0, CON_CHARS_PER_LINE);
1032 console->Offset = 0;
1033 strcpy(console->LCommand, console->CommandLines[console->CommandScrollBack]);
1034 console->CursorPos = strlen(console->CommandLines[console->CommandScrollBack]);
1035 CON_UpdateConsole(console);
1039 void Command_Down(ConsoleInformation *console) {
1040 if(console->CommandScrollBack > -1) {
1041 /* move forward a line in the command strings and copy the command to the current input string */
1042 console->CommandScrollBack--;
1043 memset(console->RCommand, 0, CON_CHARS_PER_LINE);
1044 memset(console->LCommand, 0, CON_CHARS_PER_LINE);
1045 console->Offset = 0;
1046 if(console->CommandScrollBack > -1)
1047 strcpy(console->LCommand, console->CommandLines[console->CommandScrollBack]);
1048 console->CursorPos = strlen(console->LCommand);
1049 CON_UpdateConsole(console);