Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: class-autocompletion is nice now

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