Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/trunk/src/util/shell.cc @ 5115

Last change on this file since 5115 was 5115, checked in by bensch, 19 years ago

orxonox/trunk: reimplemented the list functions, as i did before in revision 5110.
This time, i looked out for the bugs, and i think i found one

@patrick: i know, that you do not want to code at the moment… :/ → see mail

File size: 18.5 KB
RevLine 
[4744]1/*
[1853]2   orxonox - the future of 3D-vertical-scrollers
3
4   Copyright (C) 2004 orx
5
6   This program is free software; you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation; either version 2, or (at your option)
9   any later version.
[1855]10
11   ### File Specific:
[5068]12   main-programmer: Benjamin Grauer
[1855]13   co-programmer: ...
[1853]14*/
15
[3955]16//#define DEBUG_SPECIAL_MODULE DEBUG_MODULE_
[1853]17
[5068]18#include "shell.h"
[1853]19
[5072]20#include "text_engine.h"
21#include "list.h"
[5093]22#include "graphics_engine.h"
23#include "event_handler.h"
[5072]24
[5100]25#include "load_param.h"
[5113]26#include "class_list.h"
27
28#include "key_names.h"
[5093]29#include "debug.h"
[5075]30#include <stdarg.h>
31#include <stdio.h>
32
[1856]33using namespace std;
[1853]34
[1856]35
[3245]36/**
[4838]37 * standard constructor
[5068]38 */
39Shell::Shell ()
[3365]40{
[5072]41  this->setClassID(CL_SHELL, "Shell");
42  this->setName("Shell");
43
[5113]44  this->shellHeight = 400;
45  this->bActive = false;
[5072]46  this->buffer = new tList<char>;
47
[5113]48  this->textSize = 15;
49  this->lineSpacing = 5;
[5080]50
[5074]51  //this->bufferSize = 0;
[5080]52  this->bufferText = NULL;
[5072]53  this->setBufferSize(100);
[5113]54  this->bufferDisplaySize = 10;
[5083]55  this->setBufferDisplaySize(10);
[5113]56  this->setAbsCoor2D(3, -400);
[5095]57  this->delayed = 0;
[5097]58  this->setRepeatDelay(.3, .05);
[5095]59  this->pressedKey = SDLK_FIRST;
[5074]60
[5113]61  this->inputLineText = NULL;
[5093]62  this->inputLine = new char[1];
63  this->inputLine[0] = '\0';
64
[5113]65  this->rebuildText();
66  this->completionList = NULL;
[5093]67
[5113]68  // EVENT-Handler subscription of '`' to all States, and all other keyboard commands to ES_SEHLL
[5093]69  EventHandler* evh = EventHandler::getInstance();
[5096]70  evh->subscribe(this, ES_ALL, SDLK_BACKQUOTE);
[5095]71  for (int i = 1; i < SDLK_F15; i++)
72    evh->subscribe(this, ES_SHELL, i);
[5068]73}
[4320]74
[5068]75Shell* Shell::singletonRef = NULL;
[1853]76
[3245]77/**
[4838]78 * standard deconstructor
[5068]79 */
80Shell::~Shell ()
[3543]81{
[5099]82  // delete the displayable Buffers
[5080]83  for (int i = 0; i < this->bufferDisplaySize; i++)
84    delete this->bufferText[i];
[5113]85  delete[] this->bufferText;
[5093]86
[5099]87  // delete the inputLine
[5080]88  delete this->inputLineText;
[5093]89  delete this->inputLine;
[5079]90
[5099]91  // delete all the Chars in the Buffers
92  tIterator<char>* charIterator = this->buffer->getIterator();
[5115]93  char* charElem = charIterator->firstElement();
[5099]94  while (charElem != NULL)
95  {
96    delete charElem;
97    charElem = charIterator->nextElement();
98  }
99  delete charIterator;
100
[5113]101//  if (this->completionList != NULL)
102    //delete this->completionList;
103
[5068]104  Shell::singletonRef = NULL;
[3543]105}
[5068]106
[5113]107
108void Shell::activate()
109{
110  if (this->bActive == true)
111    PRINTF(3)("The shell is already active\n");
112  this->bActive = true;
113
114  EventHandler::getInstance()->setState(ES_SHELL);
115  this->setRelCoorSoft2D(0, 0, 1, 5);
116}
117
118void Shell::deactivate()
119{
120  if (this->bActive == false)
121    PRINTF(3)("The shell is already inactive\n");
122  this->bActive = false;
123
124  EventHandler::getInstance()->setState(ES_GAME);
125  this->setRelCoorSoft2D(0, -400, 1, 5);
126}
127
128void Shell::setTextSize(unsigned int textSize, unsigned int lineSpacing)
129{
130  this->textSize = textSize;
131  this->lineSpacing = lineSpacing;
132
133  this->rebuildText();
134}
135
136void Shell::rebuildText()
137{
138  if (this->inputLineText == NULL)
139    delete this->inputLineText;
140  this->inputLineText = TextEngine::getInstance()->createText("fonts/Aniron_Bold.ttf", this->textSize, TEXT_DYNAMIC, 255, 0, 0);
141  this->inputLineText->setAlignment(TEXT_ALIGN_LEFT);
142  this->inputLineText->setText(NULL);
143  this->inputLineText->setParent2D(this);
144  this->inputLineText->setRelCoor2D(5, (this->textSize + this->lineSpacing)*this->bufferDisplaySize);
145
146  this->setBufferDisplaySize(this->bufferDisplaySize);
147}
148
149
150
[5074]151/**
152 * sets The count of Lines to display in the buffer.
153 * @param bufferDisplaySize the count of lines to display in the Shell-Buffer.
154 */
[5072]155void Shell::setBufferDisplaySize(unsigned int bufferDisplaySize)
156{
[5080]157  if (this->bufferText != NULL)
[5072]158  {
[5080]159    for (unsigned int i = 0; i < this->bufferDisplaySize; i++)
160      delete this->bufferText[i];
[5113]161    delete[] this->bufferText;
[5072]162  }
[5080]163
164  this->bufferText = new Text*[bufferDisplaySize];
165  for (unsigned int i = 0; i < bufferDisplaySize; i++)
[5072]166  {
[5113]167    this->bufferText[i] = TextEngine::getInstance()->createText("fonts/Aniron_Bold.ttf", this->textSize, TEXT_DYNAMIC, 255, 0, 0);
[5080]168    this->bufferText[i]->setAlignment(TEXT_ALIGN_LEFT);
[5113]169    this->bufferText[i]->setRelCoor2D(5, (this->textSize + this->lineSpacing)*(bufferDisplaySize - i -1));
[5080]170    this->bufferText[i]->setText(NULL);
[5089]171    this->bufferText[i]->setParent2D(this);
[5072]172  }
[5113]173  this->bufferDisplaySize = bufferDisplaySize;
[5111]174
[5113]175  this->shellHeight = (this->textSize + this->lineSpacing) * (bufferDisplaySize+1);
[5072]176}
[5068]177
178/**
179 * deletes all the Buffers
180 */
181void Shell::flushBuffers()
182{
[5072]183  // remove all chars from the BufferTexts.
[5080]184  if (this->bufferText)
185    for (int i; i < this->bufferDisplaySize; i++)
186    {
187      this->bufferText[i]->setText(NULL);
188    }
[5068]189
[5072]190
191  // delete all the Chars in the Buffers
192  tIterator<char>* charIterator = this->buffer->getIterator();
[5115]193  char* charElem = charIterator->firstElement();
[5072]194
195  while (charElem != NULL)
196  {
197    delete charElem;
198
199    charElem = charIterator->nextElement();
200  }
201  delete charIterator;
[5068]202}
203
204/**
205 * adds a new Line to the List of Buffers
206 * @param line the Line as in the first argument in printf
207 * @param args the arguments as a va_list
208 */
[5075]209bool Shell::addBufferLineStatic(const char* line, ...)
[5068]210{
[5075]211  va_list arguments;
212  va_start(arguments, line);
[5072]213
[5092]214#if DEBUG < 3
[5075]215  if (Shell::singletonRef == NULL)
[5089]216#endif
217
218  vprintf(line, arguments);
[5092]219#if DEBUG < 3
[5075]220  else
[5092]221#else
222  if (Shell::singletonRef != NULL)
[5089]223#endif
[5075]224    Shell::singletonRef->addBufferLine(line, arguments);
225  return true;
226}
[5072]227
[5080]228/**
229 * add a Line to the List of Buffers
230 * @param line
231 * @param arguments
232 *
233 * This function Adds one line to the buffer.
234 * and displays the line as the First Line of the display-buffer
235 */
[5075]236void Shell::addBufferLine(const char* line, va_list arguments)
237{
[5078]238   vsprintf(this->bufferArray, line, arguments);
[5072]239
[5078]240   char* newLine = new char[strlen(this->bufferArray)+1];
241   strcpy(newLine, this->bufferArray);
[5073]242
[5080]243   this->buffer->add(newLine);
[5075]244
[5080]245   if (this->buffer->getSize() > this->bufferSize)
246   {
247     delete this->buffer->firstElement();
248     this->buffer->remove(this->buffer->firstElement());
249   }
250
[5113]251   if (this->bActive && likely(bufferText != NULL))
[5080]252   {
[5113]253     Text* lastText = this->bufferText[this->bufferDisplaySize-1];
254     Vector firstCoord = this->bufferText[0]->getRelCoorSoft2D();
255
256     Text* swapText;
257     Text* moveText = this->bufferText[0];
258     this->bufferText[0]->setRelCoorSoft2D(this->bufferText[1]->getRelCoorSoft2D(), 5);
259     for (unsigned int i = 1; i < this->bufferDisplaySize; i++)
[5080]260     {
[5113]261       if ( i < this->bufferDisplaySize-1)
262         this->bufferText[i]->setRelCoorSoft2D(this->bufferText[i+1]->getRelCoorSoft2D(),5);
263       swapText = this->bufferText[i];
264       this->bufferText[i] = moveText;
265       moveText = swapText;
[5080]266     }
[5113]267     lastText->setRelCoor2D(firstCoord);
268     this->bufferText[0] = lastText;
269
270     this->bufferText[0]->setText(newLine);
[5080]271   }
[5068]272}
273
274/**
275 * moves the buffer around lineCount lines upwards (negative values move down)
276 * @param lineCount the Count of lines to move upwards
[5072]277 *
278 * @todo
[5068]279 */
280void Shell::moveBuffer(int lineCount)
281{
282}
283
284/**
285 * @param lineNumber the n-th line from the bottom
286 * @returns the Buffer at Line lineNumber
287 */
288const char* Shell::getBufferLine(unsigned int lineNumber)
289{
[5072]290  tIterator<char>* charIterator = this->buffer->getIterator();
[5115]291  char* charElem = charIterator->firstElement();
[5072]292
293  int i = 1;
294  while (charElem != NULL)
295  {
296    if (i++ < lineNumber)
297    {
298      delete charIterator;
299      return charElem;
300    }
301
302    charElem = charIterator->nextElement();
303  }
304  delete charIterator;
[5068]305}
306
307/**
308 * deletes the InputLine
309 */
310void Shell::flushInputLine()
311{
[5072]312  if (likely(this->inputLine != NULL))
313  {
314    delete [] this->inputLine;
315  }
316  this->inputLine = new char[1];
317  *this->inputLine = '\0';
[5068]318}
319
320/**
321 * adds one character to the inputLine
322 * @param character the character to add to the inputLine
323 */
324void Shell::addCharacter(char character)
325{
[5072]326  char* addCharLine = new char[strlen(inputLine)+2];
327
328  sprintf(addCharLine, "%s%c", this->inputLine, character);
329  delete this->inputLine;
330  this->inputLine = addCharLine;
[5093]331  this->inputLineText->setText(inputLine);
[5068]332}
333
334/**
335 * adds multiple Characters to thr inputLine
336 * @param characters a '\0' terminated char-array to add to the InputLine
337 */
338void Shell::addCharacters(const char* characters)
339{
[5072]340  char* addCharLine = new char[strlen(inputLine)+strlen(characters)+1];
341
342  sprintf(addCharLine, "%s%s", this->inputLine, characters);
343  delete this->inputLine;
344  this->inputLine = addCharLine;
[5093]345  this->inputLineText->setText(inputLine);
[5068]346}
347
348/**
349 * removes characterCount characters from the InputLine
350 * @param characterCount the count of Characters to remove from the input Line
351 */
352void Shell::removeCharacters(unsigned int characterCount)
353{
[5093]354  if (strlen(this->inputLine) == 0)
355    return;
356
[5072]357  if (characterCount > strlen(this->inputLine))
358    characterCount = strlen(this->inputLine);
359
360  char* removeCharLine = new char[strlen(inputLine)-characterCount+1];
361
362  strncpy(removeCharLine, this->inputLine, strlen(inputLine)-characterCount);
[5093]363  removeCharLine[strlen(inputLine)-characterCount] = '\0';
[5072]364  delete this->inputLine;
365  this->inputLine = removeCharLine;
[5093]366  this->inputLineText->setText(inputLine);
[5068]367}
368
[5096]369/**
370 * executes the command stored in the inputLine
371 * @return true if the command was commited successfully, false otherwise
372 */
373bool Shell::executeCommand()
374{
375  this->addBufferLineStatic("Execute Command: %s\n", this->inputLine);
376  delete this->inputLine;
377  this->inputLine = new char[1];
378  this->inputLine[0]='\0';
379  this->inputLineText->setText(this->inputLine);
380  return false;
381}
382
[5097]383/**
384 * sets the Repeate-delay and rate
385 * @param repeatDelay the Delay it takes, to repeate a key
386 * @param repeatRate the rate to repeate a pressed key
387 */
388void Shell::setRepeatDelay(float repeatDelay, float repeatRate)
389{
390  this->repeatDelay = repeatDelay;
391  this->repeatRate = repeatRate;
392
393}
394
[5069]395/**
396 * listens for some event
397 * @param event the Event happened
398 */
399void Shell::process(const Event &event)
400{
[5093]401  if (event.bPressed)
402  {
403    PRINTF(4)("Shell received command %s\n", SDLKToKeyname(event.type));
404    if (event.type == SDLK_BACKQUOTE)
405    {
406      if (EventHandler::getInstance()->getState() == ES_GAME)
[5094]407      {
[5113]408        this->activate();
[5094]409      }
410
[5093]411      else
[5094]412      {
[5113]413        this->deactivate();
[5094]414      }
[5093]415    }
416    else if (event.type == SDLK_TAB)
417      this->autoComplete();
418    else if (event.type == SDLK_BACKSPACE)
[5095]419    {
420      this->delayed = this->repeatDelay;
421      this->pressedKey = SDLK_BACKSPACE;
[5093]422      this->removeCharacters(1);
[5095]423    }
[5096]424    else if (event.type == SDLK_RETURN)
425      this->executeCommand();
[5097]426    else if (likely(event.type < 127))
[5095]427    {
428      this->delayed = this->repeatDelay;
429      this->pressedKey = event.type;
[5093]430      this->addCharacter(event.type);
[5095]431    }
[5093]432  }
[5095]433  else // if(!event.bPressed)
434  {
435    if (this->pressedKey == event.type)
[5113]436    {
[5095]437      this->pressedKey = SDLK_FIRST;
[5113]438      this->delayed = 0.0;
439    }
[5095]440  }
[5069]441}
442
[5068]443/**
444 * ticks the Shell for dt Seconds
445 * @param dt the elapsed time since the last tick();
446 */
[5095]447void Shell::tick(float dt)
448{
449  if (this->delayed > 0.0)
450    this->delayed -= dt;
451  else if (this->pressedKey != SDLK_FIRST )
452  {
[5097]453    this->delayed = this->repeatRate;
[5095]454    if (this->pressedKey == SDLK_BACKSPACE)
455      this->removeCharacters(1);
456    else if (pressedKey < 127)
457      this->addCharacter(this->pressedKey);
458  }
459}
[5068]460
461/**
462 * displays the Shell
463 */
464void Shell::draw() const
465{
[5099]466  glPushMatrix();
467  // transform for alignment.
468  // setting the Blending effects
469
470  glColor4f(0.0f, 0.0f, 0.8f, .4);
471  glEnable(GL_BLEND);
472  glDisable(GL_TEXTURE_2D);
473  glBlendFunc(GL_SRC_ALPHA, GL_ONE);
474
475//  glBindTexture(GL_TEXTURE_2D, this->texture);
476  glBegin(GL_QUADS);
477
478//  glTexCoord2f(this->texCoord.minU, this->texCoord.minV);
479  glVertex2f(this->getAbsCoor2D().x,   this->getAbsCoor2D().);
480
481//  glTexCoord2f(this->texCoord.maxU, this->texCoord.minV);
[5113]482  glVertex2f(GraphicsEngine::getInstance()->getResolutionX() - this->getAbsCoor2D().x, this->getAbsCoor2D().);
[5099]483
484//  glTexCoord2f(this->texCoord.maxU, this->texCoord.maxV);
[5113]485  glVertex2f(GraphicsEngine::getInstance()->getResolutionX() - this->getAbsCoor2D().x, this->getAbsCoor2D().y + this->shellHeight);
[5099]486
487//  glTexCoord2f(this->texCoord.minU, this->texCoord.maxV);
[5113]488  glVertex2f(this->getAbsCoor2D().x, this->getAbsCoor2D().y + this->shellHeight);
[5099]489
490  glEnd();
[5068]491}
492
493
494/**
495 * autocompletes the Shell's inputLine
496 * @returns true, if a result was found, false otherwise
[5100]497 *
498 * @todo implement it!!
[5068]499 */
500bool Shell::autoComplete()
501{
[5100]502  //PRINTF(3)("AutoCompletion not implemented yet\n");
503
504  char* completionLine = new char[strlen(inputLine)+1];
505  strcpy(completionLine, this->inputLine);
506
[5113]507  char* commandBegin = strrchr(completionLine, ' ');
[5100]508  if (commandBegin == NULL)
509    commandBegin = completionLine;
510  else
511  {
512    if(commandBegin >= completionLine + strlen(completionLine))
513      commandBegin = completionLine + strlen(completionLine);
514    else
515      commandBegin++;
516  }
517
[5113]518  char* objectStart;
519  if (objectStart = strstr(commandBegin, "::"))
520  {
521    char* classIdentity = new char[objectStart - commandBegin +1];
522    strncpy(classIdentity, commandBegin, objectStart - commandBegin);
523    classIdentity[objectStart - commandBegin] = '\0';
524    this->objectComplete(objectStart+2, ClassList::StringToID(classIdentity));
525    delete[] classIdentity;
526  }
527  else
528    this->classComplete(commandBegin);
[5102]529
[5113]530  delete[] completionLine;
531}
[5102]532
[5113]533/**
534 * autocompletes a className
535 * @param classBegin the Beginning of a String to autoComplete
536 * @return true on success, false otherwise
537 */
538bool Shell::classComplete(const char* classBegin)
539{
540  if (unlikely(classBegin == NULL))
541    return false;
542  const tList<const char>* clList = ClassList::getClassList();
543  if (clList != NULL)
544  {
545    const tList<const char>* classList = this->createCompleteList(clList, classBegin);
546    if (classList != NULL)
547      this->generalComplete(classList, classBegin, "%s::", "::");
548    else
549      return false;
550  }
551  else
552    return false;
553  return true;
[5105]554}
555
556/**
[5113]557 * autocompletes an ObjectName
558 * @param objectBegin the beginning string of a Object
559 * @param classID the ID of the Class to search for.
560 * @return true on success, false otherwise
561 */
562bool Shell::objectComplete(const char* objectBegin, long classID)
563{
564  printf("%s\n", objectBegin);
565
566  if (unlikely(objectBegin == NULL))
567    return false;
568  tList<BaseObject>* boList = ClassList::getList(classID);
569  if (boList != NULL)
570  {
571    printf("\n", boList->firstElement()->getName());
572    const tList<const char>* objectList = this->createCompleteList(boList, objectBegin);
573    if (objectList != NULL)
574      this->generalComplete(objectList, objectBegin, "%s");
575    else
576      return false;
577  }
578  else
579    return false;
580  return true;
581}
582
583bool Shell::functionComplete(const char* functionBegin)
584{
585}
586
587/**
588 * completes the inputline on grounds of an inputList
589 * @param stringList the List to parse through
590 * @param begin the String to search in the inputList, and to extend with it.
591 * @param displayAs how to display the found value to the user, printf-style, !!with only one %s!! ex.: "::%s::"
592 * @param addBack what should be added at the end of the completion
593 * @param addFront what should be added to the front of one finished completion
594 * @return true if ok, false otherwise
595 */
596bool Shell::generalComplete(const tList<const char>* stringList, const char* begin, const char* displayAs, const char* addBack, const char* addFront)
597{
598  if (stringList->getSize() == 0)
599    return false;
600
601  const char* addString = stringList->firstElement();
602  unsigned int addLength = 0;
603  unsigned int inputLenght = strlen(begin);
604
605  if (addString != NULL)
606    addLength = strlen(addString);
607  tIterator<const char>* charIterator = stringList->getIterator();
[5115]608  const char* charElem = charIterator->firstElement();
[5113]609  while (charElem != NULL)
610  {
611    PRINTF(0)(displayAs, charElem);
612    for (unsigned int i = inputLenght; i < addLength; i++)
613      if (addString[i] != charElem[i])
614    {
615      addLength = i;
616      break;
617    }
618    charElem = charIterator->nextElement();
619  }
620  delete charIterator;
621
622  if (addLength >= inputLenght)
623  {
624    char* adder = new char[addLength+1];
625    strncpy(adder, addString, addLength);
626    adder[addLength] = '\0';
627    this->removeCharacters(inputLenght);
628    this->addCharacters(adder);
629    if (addBack != NULL && stringList->getSize() == 1)
630      this->addCharacters("::");
631    delete[] adder;
632  }
633  return true;
634}
635
636
637
638/**
639 * searches for classes, which beginn with classNameBegin
640 * @param inputList the List to parse through
641 * @param classNameBegin the beginning string
642 * @return a NEW char-array with ClassNames. The LIST should be deleted afterwards,
643 * !! The strings MUST NOT be deleted !!
644 */
645const tList<const char>* Shell::createCompleteList(const tList<const char>* inputList, const char* classNameBegin)
646{
647  if (inputList == NULL || classNameBegin == NULL)
648    return NULL;
649  unsigned int searchLength = strlen(classNameBegin);
650  if (this->completionList != NULL)
651    delete this->completionList;
652  this->completionList = new tList<const char>;
653
654//  tList<const char>* classList = ClassList::getClassList();
655
656  tIterator<const char>* iterator = inputList->getIterator();
[5115]657  const char* enumString = iterator->firstElement();
[5113]658  while (enumString != NULL)
659  {
660    if (strlen(enumString)>searchLength+1 &&
661        !strncasecmp(enumString, classNameBegin, searchLength))
662    {
663      this->completionList->add(enumString);
664    }
665    enumString = iterator->nextElement();
666  }
667  delete iterator;
668
669  return this->completionList;
670}
671
672/**
673 * searches for classes, which beginn with classNameBegin
674 * @param inputList the List to parse through
675 * @param classNameBegin the beginning string
676 * @return a NEW char-array with ClassNames. The LIST should be deleted afterwards,
677 * !! The strings MUST NOT be deleted !!
678 */
679const tList<const char>* Shell::createCompleteList(const tList<BaseObject>* inputList, const char* classNameBegin)
680{
681  if (inputList == NULL || classNameBegin == NULL)
682    return NULL;
683  unsigned int searchLength = strlen(classNameBegin);
684  if (this->completionList != NULL)
685    delete this->completionList;
686  this->completionList = new tList<const char>;
687
688  tIterator<BaseObject>* iterator = inputList->getIterator();
[5115]689  BaseObject* enumBO = iterator->firstElement();
[5113]690  while (enumBO != NULL)
691  {
692    if (enumBO->getName() != NULL &&
693        strlen(enumBO->getName())>searchLength+1 &&
694        !strncasecmp(enumBO->getName(), classNameBegin, searchLength))
695    {
696      this->completionList->add(enumBO->getName());
697    }
698    enumBO = iterator->nextElement();
699  }
700  delete iterator;
701
702  return this->completionList;
703}
704
705/**
[5068]706 * displays some nice output from the Shell
707 */
708void Shell::debug() const
709{
[5096]710  if (this->pressedKey != SDLK_FIRST)
711    printf("%s::%f %f\n", SDLKToKeyname(this->pressedKey), this->delayed, this->repeatDelay);
[5068]712}
Note: See TracBrowser for help on using the repository browser.