00001
00002
00003 #include "console.h"
00004
00005 IC_Console* mLuaConsole;
00006
00007
00008 static int luaPrint( lua_State* L )
00009 {
00010 if( mLuaConsole ) {
00011 stringc message="";
00012
00013 for( int i=1; i<=lua_gettop(L); i++ ) {
00014 if( i>1 )
00015 message.append( '\t' );
00016 if( lua_isstring(L, i) )
00017 message.append( lua_tostring(L, i) );
00018 else if( lua_isnil(L, i) )
00019 message.append( "nil" );
00020 else if( lua_isboolean(L, i) )
00021 message.append( lua_toboolean(L, i) ? "true" : "false" );
00022 else {
00023 message.append( lua_typename(L, lua_type(L, i)) );
00024 message.append( ':' );
00025 message.append( stringc((unsigned int)(lua_topointer(L, i))) );
00026 }
00027 }
00028
00029
00030 mLuaConsole->appendMessage( IC_StrConv::toWideString(message) );
00031 }
00032
00033 return 0;
00034 }
00035
00036
00037 static int luaAlert( lua_State *L )
00038 {
00039 if( mLuaConsole )
00040 mLuaConsole->appendMessage( IC_StrConv::toWideString(stringc(lua_tostring(L, 1))) );
00041
00042 return 0;
00043 }
00044
00045
00047 void IC_MessageSink::logMessage( irr::ELOG_LEVEL logLevel, const stringw message )
00048 {
00049 stringw wstr = getLevelTag( logLevel );
00050 wstr += message;
00051 appendMessage( wstr );
00052 }
00053
00054
00056 const stringw IC_MessageSink::getLevelTag( irr::ELOG_LEVEL logLevel )
00057 {
00058 switch( logLevel ) {
00059 case irr::ELL_INFORMATION:
00060 return L"<info> ";
00061 case irr::ELL_WARNING:
00062 return L"<warning> ";
00063 case irr::ELL_ERROR:
00064 return L"<error> ";
00065 default:
00066 return L"";
00067 }
00068 }
00069
00070
00072 const wchar_t IC_Console::IC_KEY_TILDE = 0xc0;
00073
00074
00076 IC_Console::IC_Console( lua_State *L ) : mLuaState( L ), bVisible( false ), guiFont( 0 ),
00077 consoleRect( 0, 0, 0, 0 ), consoleHistoryIndex( 0 )
00078 {
00079 mLuaConsole = this;
00080
00081
00082
00083 lua_register( mLuaState, "print", luaPrint );
00084 lua_register( mLuaState, "_ALERT", luaAlert );
00085 }
00086
00087
00089 void IC_Console::initializeConsole( irr::IrrlichtDevice* device )
00090 {
00091 irr::gui::IGUIEnvironment* guienv=device->getGUIEnvironment();
00092
00093
00094 guiFont = guienv->getFont( consoleConfig.fontName.c_str() );
00095 if( guiFont == 0 )
00096 guiFont = guienv->getBuiltInFont();
00097
00098
00099 cout << "font loaded!!" << endl;
00100
00101
00102 calculateConsoleRect( device->getVideoDriver()->getScreenSize() );
00103
00104
00105 appendMessage( L"IrrLuaConsole initialized" );
00106
00107
00108 resizeMessages();
00109 }
00110
00111
00113 void IC_Console::loadDefaultCommands( irr::IrrlichtDevice* device )
00114 {
00115 }
00116
00117
00119 void IC_Console::resizeMessages()
00120 {
00121 u32 maxLines = 0;
00122 u32 lineHeight = 0;
00123 s32 fontHeight = 0;
00124 if(calculateLimits(maxLines,lineHeight,fontHeight))
00125 {
00126 u32 messageCount = consoleMessages.size();
00127 if(messageCount > maxLines)
00128 {
00129 consoleMessages.erase(0,messageCount - maxLines);
00130 }
00131 }
00132 }
00133
00134
00136 bool IC_Console::isVisible()
00137 {
00138 return bVisible;
00139 }
00140
00141
00143 void IC_Console::setVisible( bool bV )
00144 {
00145 bVisible = bV;
00146 }
00147
00148
00150 void IC_Console::toggleVisible()
00151 {
00152 setVisible( !isVisible() );
00153 }
00154
00155
00157 void IC_Console::appendMessage( const stringw message )
00158 {
00159 consoleMessages.push_back( message );
00160 resizeMessages();
00161 }
00162
00163
00165 void IC_Console::clearMessages()
00166 {
00167 consoleMessages.clear();
00168 }
00169
00170
00172 void IC_Console::renderConsole(irr::gui::IGUIEnvironment* guienv, irr::video::IVideoDriver *videoDriver, const u32 deltaMillis)
00173 {
00174
00175 if(isVisible())
00176 {
00177
00178 if(consoleConfig.bShowBG)
00179 {
00180
00181 videoDriver->draw2DRectangle(consoleConfig.bgColor,consoleRect);
00182 }
00183
00184 rect<s32> textRect,shellRect;
00185 calculatePrintRects(textRect,shellRect);
00186
00187
00188
00189 u32 maxLines, lineHeight;
00190 s32 fontHeight;
00191 if(!calculateLimits(maxLines,lineHeight,fontHeight))
00192 {
00193 return;
00194 }
00195
00196 rect<s32> lineRect(textRect.UpperLeftCorner.X,textRect.UpperLeftCorner.Y,textRect.LowerRightCorner.X,textRect.UpperLeftCorner.Y + lineHeight);
00197 for(u32 i = 0; i < consoleMessages.size(); i++)
00198 {
00199
00200 guiFont->draw(consoleMessages[i].c_str(), lineRect, consoleConfig.fontColor, false, true);
00201
00202
00203 lineRect.UpperLeftCorner.Y += lineHeight;
00204 lineRect.LowerRightCorner.Y += lineHeight;
00205 }
00206
00207
00208
00209 stringw shellText = IC_StrConv::toWideString(consoleConfig.prompt);
00210 shellText += L"$>";
00211 shellText += currentCommand;
00212
00213
00214 static u32 blinkCounter = 0;
00215 blinkCounter ++;
00216 if(blinkCounter > 100)
00217 {
00218 blinkCounter = 0;
00219 }
00220 else if(blinkCounter <= 50)
00221 {
00222 shellText += L"_";
00223 }
00224
00225
00226 guiFont->draw(shellText.c_str(),shellRect,consoleConfig.fontColor,false,true);
00227
00228 }
00229 }
00230
00231
00233 void IC_Console::handleKeyPress( wchar_t keyChar, irr::EKEY_CODE keyCode, bool bShiftDown, bool bControlDown )
00234 {
00235
00236
00237 if( keyChar ) {
00238
00239 wchar_t buf[2];
00240 buf[0] = keyChar;
00241 buf[1] = 0;
00242 stringw astr = buf;
00243 if( bShiftDown )
00244 astr.make_upper();
00245 currentCommand += astr;
00246 } else if( keyCode == irr::KEY_RETURN ) {
00247
00248 addToHistory( currentCommand );
00249 handleCommandstringc( currentCommand );
00250 currentCommand = L"";
00251 consoleHistoryIndex = 0;
00252 } else if( keyCode == irr::KEY_BACK || keyCode == irr::KEY_DELETE || (keyCode == irr::KEY_KEY_H && bControlDown) ) {
00253
00254 if( currentCommand.size() > 0 )
00255 currentCommand = currentCommand.subString( 0, currentCommand.size()-1 );
00256 } else if( keyCode == irr::KEY_UP ) {
00257
00258 if( consoleHistory.size() > 0 ) {
00259 s32 index = consoleHistory.size() - 1 - consoleHistoryIndex;
00260 if( index >= 0 && index < (s32)(consoleHistory.size()) ) {
00261 consoleHistoryIndex++;
00262 currentCommand = consoleHistory[index];
00263 } else
00264 consoleHistoryIndex = 0;
00265 } else
00266 consoleHistoryIndex = 0;
00267 } else if( keyCode == irr::KEY_DOWN ) {
00268
00269 if( consoleHistory.size() > 0 ) {
00270 s32 index = consoleHistory.size() - consoleHistoryIndex;
00271 if( index >= 0 && index < (s32)(consoleHistory.size()) ) {
00272 consoleHistoryIndex--;
00273 currentCommand = consoleHistory[index];
00274 } else
00275 consoleHistoryIndex = consoleHistory.size() - 1;
00276 } else
00277 consoleHistoryIndex = 0;
00278 } else if( keyCode == irr::KEY_TAB ) {
00279
00280 tabComplete();
00281 }
00282 }
00283
00284
00286 void IC_Console::handleCommandstringc( stringw& wstr )
00287 {
00288
00289 if( wstr.size()>0 && wstr[0]==(wchar_t)'\\' ) {
00290 stringw cmdLine = wstr.subString( 1, wstr.size()-1 );
00291 cout << "Command Received : " << cmdLine << endl;
00292
00293
00294 stringw msg = L">> Command : ";
00295 msg += cmdLine;
00296 appendMessage( msg );
00297
00298
00299 int ret_val = lua_dostring( mLuaState, IC_StrConv::toString(cmdLine.c_str()).c_str() );
00300 } else {
00301
00302 appendMessage( wstr );
00303 }
00304 }
00305
00306
00308 void IC_Console::addToHistory(stringw& wstr)
00309 {
00310 if(consoleHistory.size() >= consoleConfig.commandHistorySize)
00311 consoleHistory.erase(0,1);
00312 consoleHistory.push_back(wstr);
00313 }
00314
00315
00317 void IC_Console::calculateConsoleRect(const irr::core::dimension2d<s32>& screenSize)
00318 {
00319 if(consoleConfig.dimensionRatios.X == 0 || consoleConfig.dimensionRatios.Y == 0)
00320 {
00321 consoleRect = rect<s32>(0,0,0,0);
00322 }
00323 else
00324 {
00325
00326 dimension2d<s32> consoleDim = screenSize;
00327 consoleDim.Width = (s32)((f32)consoleDim.Width * consoleConfig.dimensionRatios.X);
00328 consoleDim.Height= (s32)((f32)consoleDim.Height * consoleConfig.dimensionRatios.Y);
00329
00330
00331 if(consoleConfig.valign == VAL_TOP)
00332 {
00333 consoleRect.UpperLeftCorner.Y = 0;
00334 }
00335 else if(consoleConfig.valign == VAL_BOTTOM)
00336 {
00337 consoleRect.UpperLeftCorner.Y = screenSize.Height - consoleDim.Height;
00338 }
00339 else if(consoleConfig.valign == VAL_MIDDLE)
00340 {
00341 consoleRect.UpperLeftCorner.Y = (screenSize.Height - consoleDim.Height) / 2;
00342 }
00343
00344
00345 if(consoleConfig.halign == HAL_LEFT)
00346 {
00347 consoleRect.UpperLeftCorner.X = 0;
00348 }
00349 else if(consoleConfig.halign == HAL_RIGHT)
00350 {
00351 consoleRect.UpperLeftCorner.X = screenSize.Width - consoleDim.Width;
00352 }
00353 else if(consoleConfig.halign == HAL_CENTER)
00354 {
00355 consoleRect.UpperLeftCorner.X = (screenSize.Width - consoleDim.Width) / 2;
00356 }
00357
00358
00359 consoleRect.LowerRightCorner.X = consoleRect.UpperLeftCorner.X + consoleDim.Width;
00360 consoleRect.LowerRightCorner.Y = consoleRect.UpperLeftCorner.Y + consoleDim.Height;
00361
00362
00363 }
00364 }
00365
00367 void IC_Console::calculatePrintRects(rect<s32>& textRect,rect<s32>& shellRect)
00368 {
00369 u32 maxLines, lineHeight;
00370 s32 fontHeight;
00371 if(calculateLimits(maxLines,lineHeight,fontHeight))
00372 {
00373
00374
00375 shellRect.LowerRightCorner.X = consoleRect.LowerRightCorner.X;
00376 shellRect.LowerRightCorner.Y = consoleRect.LowerRightCorner.Y;
00377 shellRect.UpperLeftCorner.X = consoleRect.UpperLeftCorner.X;
00378 shellRect.UpperLeftCorner.Y = consoleRect.LowerRightCorner.Y - lineHeight;
00379
00380
00381 textRect.UpperLeftCorner.X = consoleRect.UpperLeftCorner.X;
00382 textRect.UpperLeftCorner.Y = consoleRect.UpperLeftCorner.Y;
00383 shellRect.LowerRightCorner.X = consoleRect.LowerRightCorner.X;
00384 shellRect.LowerRightCorner.Y = shellRect.UpperLeftCorner.Y;
00385
00386
00387 }
00388 else
00389 {
00390 textRect = rect<s32>(0,0,0,0);
00391 shellRect = rect<s32>(0,0,0,0);
00392 }
00393 }
00394
00395 bool IC_Console::calculateLimits(u32& maxLines, u32& lineHeight,s32& fontHeight)
00396 {
00397 u32 consoleHeight = consoleRect.getHeight();
00398 if(guiFont != 0 && consoleHeight > 0)
00399 {
00400 fontHeight = guiFont->getDimension(L"X").Height;
00401 lineHeight = fontHeight + consoleConfig.lineSpacing;
00402 maxLines = consoleHeight / lineHeight;
00403 if(maxLines > 2)
00404 {
00405 maxLines -= 2;
00406 }
00407 return true;
00408 }
00409 else
00410 {
00411 return false;
00412 }
00413 }
00414
00415 void IC_Console::tabComplete()
00416 {
00417 if(currentCommand.size() == 0)
00418 {
00419 return;
00420 }
00421 else if(currentCommand[0] != (wchar_t)('\\'))
00422 {
00423 return;
00424 }
00425 stringw ccStr = currentCommand.subString(1,currentCommand.size() - 1);
00426 array<stringw> names;
00427
00428 for(u32 i = 0; i < names.size(); i++)
00429 {
00430 stringw thisCmd = names[i];
00431 if(thisCmd.size() == ccStr.size())
00432 {
00433 if(thisCmd == ccStr)
00434 {
00435 return;
00436 }
00437 }
00438 else if(thisCmd.size() > ccStr.size())
00439 {
00440 if(thisCmd.subString(0,ccStr.size()) == ccStr)
00441 {
00442 currentCommand = L"\\";
00443 currentCommand += thisCmd;
00444
00445 return;
00446 }
00447 }
00448 }
00449 }
00450
00451
00452 stringw IC_StrConv::toWideString( const stringc str )
00453 {
00454 int len = str.size() + 1;
00455 wchar_t* buf = new wchar_t[len];
00456
00457 ::mbstowcs(buf,str.c_str(),len);
00458 stringw wstr = buf;
00459 delete[] buf;
00460 return wstr;
00461 }
00462
00463
00464 stringc IC_StrConv::toString(const stringw str)
00465 {
00466 int len = str.size() + 1;
00467 c8* buf = new c8[len];
00468 ::wcstombs(buf,str.c_str(),len);
00469 stringc wstr = buf;
00470 delete[] buf;
00471 return wstr;
00472 }
00473
00474