Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: better algorithm to find the ClassName.
Now this is done via the ClassList

File size: 13.9 KB
Line 
1/*
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.
10
11   ### File Specific:
12   main-programmer: Benjamin Grauer
13   co-programmer: ...
14*/
15
16//#define DEBUG_SPECIAL_MODULE DEBUG_MODULE_
17
18#include "shell.h"
19
20#include "text_engine.h"
21#include "list.h"
22#include "graphics_engine.h"
23#include "event_handler.h"
24
25#include "load_param.h"
26#include "class_list.h"
27#include "debug.h"
28#include <stdarg.h>
29#include <stdio.h>
30
31using namespace std;
32
33
34/**
35 * standard constructor
36 */
37Shell::Shell ()
38{
39  this->setClassID(CL_SHELL, "Shell");
40  this->setName("Shell");
41
42  this->buffer = new tList<char>;
43
44  this->textSize = 10;
45
46  //this->bufferSize = 0;
47  this->bufferText = NULL;
48  this->setBufferSize(100);
49  this->setBufferDisplaySize(10);
50  this->setAbsCoor2D(3, GraphicsEngine::getInstance()->getResolutionY());
51  this->delayed = 0;
52  this->setRepeatDelay(.3, .05);
53  this->pressedKey = SDLK_FIRST;
54
55  this->inputLineText = TextEngine::getInstance()->createText("fonts/earth.ttf", 10, TEXT_DYNAMIC, 255, 0, 0);
56  this->inputLineText->setAlignment(TEXT_ALIGN_LEFT);
57  this->inputLineText->setText(NULL);
58  this->inputLine = new char[1];
59  this->inputLine[0] = '\0';
60  this->inputLineText->setParent2D(this);
61
62  this->completionList = NULL;
63
64  EventHandler* evh = EventHandler::getInstance();
65  evh->subscribe(this, ES_ALL, SDLK_BACKQUOTE);
66  for (int i = 1; i < SDLK_F15; i++)
67    evh->subscribe(this, ES_SHELL, i);
68}
69
70Shell* Shell::singletonRef = NULL;
71
72/**
73 * standard deconstructor
74 */
75Shell::~Shell ()
76{
77  // delete the displayable Buffers
78  for (int i = 0; i < this->bufferDisplaySize; i++)
79    delete this->bufferText[i];
80  delete this->bufferText;
81
82  // delete the inputLine
83  delete this->inputLineText;
84  delete this->inputLine;
85
86  // delete all the Chars in the Buffers
87  tIterator<char>* charIterator = this->buffer->getIterator();
88  char* charElem = charIterator->nextElement();
89  while (charElem != NULL)
90  {
91    delete charElem;
92    charElem = charIterator->nextElement();
93  }
94  delete charIterator;
95
96//  if (this->completionList != NULL)
97    //delete this->completionList;
98
99  Shell::singletonRef = NULL;
100}
101
102/**
103 * sets The count of Lines to display in the buffer.
104 * @param bufferDisplaySize the count of lines to display in the Shell-Buffer.
105 */
106void Shell::setBufferDisplaySize(unsigned int bufferDisplaySize)
107{
108  if (this->bufferText != NULL)
109  {
110    for (unsigned int i = 0; i < this->bufferDisplaySize; i++)
111      delete this->bufferText[i];
112    delete this->bufferText;
113  }
114
115  this->bufferText = new Text*[bufferDisplaySize];
116  for (unsigned int i = 0; i < bufferDisplaySize; i++)
117  {
118    this->bufferText[i] = TextEngine::getInstance()->createText("fonts/earth.ttf", this->textSize, TEXT_DYNAMIC, 255, 0, 0);
119    this->bufferText[i]->setAlignment(TEXT_ALIGN_LEFT);
120    this->bufferText[i]->setRelCoor2D(5, 12+12*i);
121    this->bufferText[i]->setText(NULL);
122    this->bufferText[i]->setParent2D(this);
123  }
124
125
126  this->bufferDisplaySize = bufferDisplaySize;
127}
128
129/**
130 * deletes all the Buffers
131 */
132void Shell::flushBuffers()
133{
134  // remove all chars from the BufferTexts.
135  if (this->bufferText)
136    for (int i; i < this->bufferDisplaySize; i++)
137    {
138      this->bufferText[i]->setText(NULL);
139    }
140
141
142  // delete all the Chars in the Buffers
143  tIterator<char>* charIterator = this->buffer->getIterator();
144  char* charElem = charIterator->nextElement();
145
146  while (charElem != NULL)
147  {
148    delete charElem;
149
150    charElem = charIterator->nextElement();
151  }
152  delete charIterator;
153}
154
155/**
156 * adds a new Line to the List of Buffers
157 * @param line the Line as in the first argument in printf
158 * @param args the arguments as a va_list
159 *
160 * @todo optimize
161 */
162bool Shell::addBufferLineStatic(const char* line, ...)
163{
164  va_list arguments;
165  va_start(arguments, line);
166
167#if DEBUG < 3
168  if (Shell::singletonRef == NULL)
169#endif
170
171  vprintf(line, arguments);
172#if DEBUG < 3
173  else
174#else
175  if (Shell::singletonRef != NULL)
176#endif
177    Shell::singletonRef->addBufferLine(line, arguments);
178  return true;
179}
180int curr = 0;
181
182/**
183 * add a Line to the List of Buffers
184 * @param line
185 * @param arguments
186 *
187 * This function Adds one line to the buffer.
188 * and displays the line as the First Line of the display-buffer
189 */
190void Shell::addBufferLine(const char* line, va_list arguments)
191{
192   vsprintf(this->bufferArray, line, arguments);
193
194   char* newLine = new char[strlen(this->bufferArray)+1];
195   strcpy(newLine, this->bufferArray);
196
197   this->buffer->add(newLine);
198
199   if (this->buffer->getSize() > this->bufferSize)
200   {
201     delete this->buffer->firstElement();
202     this->buffer->remove(this->buffer->firstElement());
203   }
204
205   if (likely(bufferText != NULL))
206   {
207     Text* moveText = this->bufferText[this->bufferDisplaySize-1];
208     for (int i = this->bufferDisplaySize-1; i > 0; i--)
209     {
210       this->bufferText[i] = this->bufferText[i-1];
211     }
212     this->bufferText[0] = moveText;
213   }
214   this->bufferText[0]->setText(newLine);
215   // this->bufferText->
216//  this->inputLineText->setText(newLine);
217}
218
219/**
220 * moves the buffer around lineCount lines upwards (negative values move down)
221 * @param lineCount the Count of lines to move upwards
222 *
223 * @todo
224 */
225void Shell::moveBuffer(int lineCount)
226{
227}
228
229/**
230 * @param lineNumber the n-th line from the bottom
231 * @returns the Buffer at Line lineNumber
232 */
233const char* Shell::getBufferLine(unsigned int lineNumber)
234{
235  tIterator<char>* charIterator = this->buffer->getIterator();
236  char* charElem = charIterator->nextElement();
237
238  int i = 1;
239  while (charElem != NULL)
240  {
241    if (i++ < lineNumber)
242    {
243      delete charIterator;
244      return charElem;
245    }
246
247    charElem = charIterator->nextElement();
248  }
249  delete charIterator;
250}
251
252
253/**
254 * deletes the InputLine
255 */
256void Shell::flushInputLine()
257{
258  if (likely(this->inputLine != NULL))
259  {
260    delete [] this->inputLine;
261  }
262  this->inputLine = new char[1];
263  *this->inputLine = '\0';
264
265}
266
267/**
268 * adds one character to the inputLine
269 * @param character the character to add to the inputLine
270 */
271void Shell::addCharacter(char character)
272{
273  char* addCharLine = new char[strlen(inputLine)+2];
274
275  sprintf(addCharLine, "%s%c", this->inputLine, character);
276  delete this->inputLine;
277  this->inputLine = addCharLine;
278  this->inputLineText->setText(inputLine);
279}
280
281/**
282 * adds multiple Characters to thr inputLine
283 * @param characters a '\0' terminated char-array to add to the InputLine
284 */
285void Shell::addCharacters(const char* characters)
286{
287  char* addCharLine = new char[strlen(inputLine)+strlen(characters)+1];
288
289  sprintf(addCharLine, "%s%s", this->inputLine, characters);
290  delete this->inputLine;
291  this->inputLine = addCharLine;
292  this->inputLineText->setText(inputLine);
293}
294
295/**
296 * removes characterCount characters from the InputLine
297 * @param characterCount the count of Characters to remove from the input Line
298 */
299void Shell::removeCharacters(unsigned int characterCount)
300{
301  if (strlen(this->inputLine) == 0)
302    return;
303
304  if (characterCount > strlen(this->inputLine))
305    characterCount = strlen(this->inputLine);
306
307  char* removeCharLine = new char[strlen(inputLine)-characterCount+1];
308
309  strncpy(removeCharLine, this->inputLine, strlen(inputLine)-characterCount);
310  removeCharLine[strlen(inputLine)-characterCount] = '\0';
311  delete this->inputLine;
312  this->inputLine = removeCharLine;
313  this->inputLineText->setText(inputLine);
314}
315
316/**
317 * executes the command stored in the inputLine
318 * @return true if the command was commited successfully, false otherwise
319 */
320bool Shell::executeCommand()
321{
322
323  this->addBufferLineStatic("Execute Command: %s\n", this->inputLine);
324  delete this->inputLine;
325  this->inputLine = new char[1];
326  this->inputLine[0]='\0';
327  this->inputLineText->setText(this->inputLine);
328  return false;
329}
330
331/**
332 * sets the Repeate-delay and rate
333 * @param repeatDelay the Delay it takes, to repeate a key
334 * @param repeatRate the rate to repeate a pressed key
335 */
336void Shell::setRepeatDelay(float repeatDelay, float repeatRate)
337{
338  this->repeatDelay = repeatDelay;
339  this->repeatRate = repeatRate;
340
341}
342
343
344#include "key_names.h"
345/**
346 * listens for some event
347 * @param event the Event happened
348 */
349void Shell::process(const Event &event)
350{
351  if (event.bPressed)
352  {
353    PRINTF(4)("Shell received command %s\n", SDLKToKeyname(event.type));
354    if (event.type == SDLK_BACKQUOTE)
355    {
356      if (EventHandler::getInstance()->getState() == ES_GAME)
357      {
358        EventHandler::getInstance()->setState(ES_SHELL);
359        this->setRelCoorSoft2D(0, GraphicsEngine::getInstance()->getResolutionY()-150, 1, 5);
360      }
361
362      else
363      {
364        EventHandler::getInstance()->setState(ES_GAME);
365        this->setRelCoorSoft2D(0, GraphicsEngine::getInstance()->getResolutionY()+10, 1, 5);
366      }
367    }
368    else if (event.type == SDLK_TAB)
369      this->autoComplete();
370    else if (event.type == SDLK_BACKSPACE)
371    {
372      this->delayed = this->repeatDelay;
373      this->pressedKey = SDLK_BACKSPACE;
374      this->removeCharacters(1);
375    }
376    else if (event.type == SDLK_RETURN)
377      this->executeCommand();
378    else if (likely(event.type < 127))
379    {
380      this->delayed = this->repeatDelay;
381      this->pressedKey = event.type;
382      this->addCharacter(event.type);
383    }
384  }
385  else // if(!event.bPressed)
386  {
387    if (this->pressedKey == event.type)
388    {
389      this->pressedKey = SDLK_FIRST;
390      this->delayed = 0.0;
391    }
392  }
393}
394
395/**
396 * ticks the Shell for dt Seconds
397 * @param dt the elapsed time since the last tick();
398 */
399void Shell::tick(float dt)
400{
401  if (this->delayed > 0.0)
402    this->delayed -= dt;
403  else if (this->pressedKey != SDLK_FIRST )
404  {
405    this->delayed = this->repeatRate;
406    if (this->pressedKey == SDLK_BACKSPACE)
407      this->removeCharacters(1);
408    else if (pressedKey < 127)
409      this->addCharacter(this->pressedKey);
410  }
411}
412
413/**
414 * displays the Shell
415 */
416void Shell::draw() const
417{
418  glPushMatrix();
419  // transform for alignment.
420  // setting the Blending effects
421
422  glColor4f(0.0f, 0.0f, 0.8f, .4);
423  glEnable(GL_BLEND);
424  glDisable(GL_TEXTURE_2D);
425  glBlendFunc(GL_SRC_ALPHA, GL_ONE);
426
427//  glBindTexture(GL_TEXTURE_2D, this->texture);
428  glBegin(GL_QUADS);
429
430//  glTexCoord2f(this->texCoord.minU, this->texCoord.minV);
431  glVertex2f(this->getAbsCoor2D().x,   this->getAbsCoor2D().);
432
433//  glTexCoord2f(this->texCoord.maxU, this->texCoord.minV);
434  glVertex2f(this->getAbsCoor2D().x + 800, this->getAbsCoor2D().);
435
436//  glTexCoord2f(this->texCoord.maxU, this->texCoord.maxV);
437  glVertex2f(this->getAbsCoor2D().x + 800, this->getAbsCoor2D().y + 150);
438
439//  glTexCoord2f(this->texCoord.minU, this->texCoord.maxV);
440  glVertex2f(this->getAbsCoor2D().x, this->getAbsCoor2D().y + 150);
441
442  glEnd();
443}
444
445
446/**
447 * autocompletes the Shell's inputLine
448 * @returns true, if a result was found, false otherwise
449 *
450 * @todo implement it!!
451 */
452bool Shell::autoComplete()
453{
454  //PRINTF(3)("AutoCompletion not implemented yet\n");
455
456  char* completionLine = new char[strlen(inputLine)+1];
457  strcpy(completionLine, this->inputLine);
458
459   char* commandBegin = strrchr(completionLine, ' ');
460  if (commandBegin == NULL)
461    commandBegin = completionLine;
462  else
463  {
464    if(commandBegin >= completionLine + strlen(completionLine))
465      commandBegin = completionLine + strlen(completionLine);
466    else
467      commandBegin++;
468  }
469
470  this->classComplete(commandBegin);
471
472  delete[] completionLine;
473}
474
475/**
476 * autocompletes a className
477 * @param classBegin the Beginning of a String to autoComplete
478 * @return true on success, false otherwise
479 */
480bool Shell::classComplete(const char* classBegin)
481{
482  if (unlikely(classBegin == NULL))
483    return false;
484  const tList<const char>* classList = this->searchClassWithShort(classBegin);
485  if (classList->getSize() == 0)
486  {
487     //PRINTF(0)("no completion found for %s\n", commandBegin);
488    return false;
489  }
490
491  const char* addString = classList->firstElement();
492  unsigned int addLength = 0;
493  unsigned int inputLenght = strlen(classBegin);
494
495  if (addString != NULL)
496    addLength = strlen(addString);
497  tIterator<const char>* charIterator = classList->getIterator();
498  const char* charElem = charIterator->nextElement();
499  while (charElem != NULL)
500  {
501    PRINTF(0)("%s:: ", charElem);
502    {
503      for (unsigned int i = inputLenght; i < addLength; i++)
504        if (addString[i] != charElem[i])
505      {
506        addLength = i;
507        break;
508      }
509    }
510
511    charElem = charIterator->nextElement();
512  }
513  delete charIterator;
514
515  if (addLength >= inputLenght)
516  {
517    char* adder = new char[addLength+1];
518    strncpy(adder, addString, addLength);
519    adder[addLength] = '\0';
520    this->removeCharacters(inputLenght);
521    this->addCharacters(adder);
522//    this->addCharacters("::");
523    delete[] adder;
524  }
525}
526
527bool Shell::objectComplete(const char* objectBegin, ClassID classID)
528{
529
530}
531
532bool Shell::functionComplete(const char* functionBegin)
533{
534}
535
536
537/**
538 * searches for classes, which beginn with classNameBegin
539 * @param classNameBegin the beginning string of a Class
540 * @return a NEW char-array with ClassNames. The LIST should be deleted afterwards,
541 * !! The strings MUST NOT be deleted !!
542 */
543const tList<const char>* Shell::searchClassWithShort(const char* classNameBegin)
544{
545  unsigned int searchLength = strlen(classNameBegin);
546  if (this->completionList != NULL)
547    delete this->completionList;
548  this->completionList = new tList<const char>;
549
550//  tList<const char>* classList = ClassList::getClassList();
551
552  tIterator<const char>* iterator = ClassList::getClassList()->getIterator();
553  const char* enumString = iterator->nextElement();
554  while (enumString != NULL)
555  {
556    if (strlen(enumString)>searchLength+1 &&
557        !strncasecmp(enumString, classNameBegin, searchLength))
558    {
559      this->completionList->add(enumString);
560    }
561    enumString = iterator->nextElement();
562  }
563  delete iterator;
564
565  return this->completionList;
566}
567
568
569
570/**
571 * displays some nice output from the Shell
572 */
573void Shell::debug() const
574{
575  if (this->pressedKey != SDLK_FIRST)
576    printf("%s::%f %f\n", SDLKToKeyname(this->pressedKey), this->delayed, this->repeatDelay);
577}
Note: See TracBrowser for help on using the repository browser.