00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #include "CeylanConsole.h"
00028
00029
00030 #include "CeylanOperators.h"
00031 #include "CeylanUtils.h"
00032
00033 #ifdef CEYLAN_USES_CONFIG_H
00034 #include "CeylanConfig.h"
00035 #endif // CEYLAN_USES_CONFIG_H
00036
00037
00038 #if CEYLAN_ARCH_NINTENDO_DS
00039 #include "CeylanConfigForNintendoDS.h"
00040 #endif // CEYLAN_ARCH_NINTENDO_DS
00041
00042
00043 #include <iostream>
00044 #include <cstdio>
00045
00046
00047 using namespace Ceylan ;
00048 using namespace Ceylan::System ;
00049
00050
00051 using std::string ;
00052 using std::list ;
00053
00054
00055 #if CEYLAN_DEBUG_CONSOLE
00056
00057 #include "CeylanLogLight.h"
00058 #define CEYLAN_CONSOLE_LOG(message) CEYLAN_LOG((string(message)))
00059
00060 #else // CEYLAN_DEBUG_CONSOLE
00061
00062 #define CEYLAN_CONSOLE_LOG(message)
00063
00064 #endif // CEYLAN_DEBUG_CONSOLE
00065
00066
00067 const char * const Console::ForegroundColor::Red = "\033[91m" ;
00068 const char * const Console::ForegroundColor::Green = "\033[92m" ;
00069 const char * const Console::ForegroundColor::Blue = "\033[94m" ;
00070 const char * const Console::ForegroundColor::Cyan = "\033[96m" ;
00071 const char * const Console::ForegroundColor::White = "\033[97m" ;
00072 const char * const Console::ForegroundColor::Yellow = "\033[93m" ;
00073 const char * const Console::ForegroundColor::Magenta = "\033[95m" ;
00074 const char * const Console::ForegroundColor::Grey = "\033[90m" ;
00075 const char * const Console::ForegroundColor::Black = "\033[90m" ;
00076 const char * const Console::ForegroundColor::Default = "\033[99m" ;
00077
00078
00079 const char * const Console::BackgroundColor::Red = "\033[101m" ;
00080 const char * const Console::BackgroundColor::Green = "\033[102m" ;
00081 const char * const Console::BackgroundColor::Blue = "\033[104m" ;
00082 const char * const Console::BackgroundColor::Cyan = "\033[106m" ;
00083 const char * const Console::BackgroundColor::White = "\033[107m" ;
00084 const char * const Console::BackgroundColor::Yellow = "\033[103m" ;
00085 const char * const Console::BackgroundColor::Magenta = "\033[105m" ;
00086 const char * const Console::BackgroundColor::Grey = "\033[100m" ;
00087 const char * const Console::BackgroundColor::Black = "\033[100m" ;
00088 const char * const Console::BackgroundColor::Default = "\033[109m" ;
00089
00090
00091 const char * const Console::DefaultColors = "\033[0m" ;
00092
00093 const char * const Console::Bold = "\033[1m" ;
00094 const char * const Console::Faint = "\033[2m" ;
00095 const char * const Console::BoldAndFaintOff = "\033[22m" ;
00096
00097 const char * const Console::Underline = "\033[4m" ;
00098 const char * const Console::UnderlineOff = "\033[24m" ;
00099
00100 const char * const Console::Blinking = "\033[5m" ;
00101 const char * const Console::BlinkingOff = "\033[25m" ;
00102
00103 const char * const Console::NegativeImage = "\033[7m" ;
00104 const char * const Console::NegativeImageOff = "\033[27m" ;
00105
00106 const char * const Console::InvisibleImage = "\033[8m" ;
00107 const char * const Console::InvisibleImageOff = "\033[28m" ;
00108
00109
00110
00111
00112 Console::Console( bool startInForeground ) :
00113 _buffer( 0 ),
00114 _inForeground( false )
00115 {
00116
00117 #if CEYLAN_ARCH_NINTENDO_DS
00118
00119 #ifdef CEYLAN_RUNS_ON_ARM7
00120
00121 throw ConsoleException(
00122 "Console constructor: only available on the ARM9." ) ;
00123
00124 #elif defined(CEYLAN_RUNS_ON_ARM9)
00125
00126
00127 initConsole( 0, 0, 32, 24, TextBuffer::Raw, true,
00128 true ) ;
00129
00130 if ( startInForeground )
00131 setToForeground( true ) ;
00132
00133 #endif // CEYLAN_RUNS_ON_ARM7
00134
00135
00136 #else // CEYLAN_ARCH_NINTENDO_DS
00137
00138
00139 initConsole( 0, 0, 32, 24, TextBuffer::Raw ) ;
00140
00141 if ( startInForeground )
00142 setToForeground( true ) ;
00143
00144 #endif // CEYLAN_ARCH_NINTENDO_DS
00145
00146 }
00147
00148
00149
00150 Console::Console(
00151 TextBuffer::CharAbscissa startingX, TextBuffer::CharOrdinate startingY,
00152 TextBuffer::CharAbscissa width, TextBuffer::CharOrdinate height,
00153 TextBuffer::TextLayout layout, bool useBottomScreen, bool useSubCore,
00154 bool startInForeground ) :
00155 _buffer( 0 ),
00156 _inForeground( false )
00157 {
00158
00159 initConsole( startingX, startingY, width, height, layout,
00160 useBottomScreen, useSubCore ) ;
00161
00162 if ( startInForeground )
00163 setToForeground( true ) ;
00164
00165 }
00166
00167
00168
00169 Console::~Console() throw()
00170 {
00171
00172 #if CEYLAN_ARCH_NINTENDO_DS
00173
00174 #ifdef CEYLAN_RUNS_ON_ARM9
00175
00176
00177
00178 #endif // CEYLAN_RUNS_ON_ARM7
00179
00180
00181 #else // CEYLAN_ARCH_NINTENDO_DS
00182
00183
00184
00185 #endif // CEYLAN_ARCH_NINTENDO_DS
00186
00187 if ( _buffer != 0 )
00188 delete _buffer ;
00189
00190
00191
00192 }
00193
00194
00195
00196 void Console::goInteractive()
00197 {
00198
00199 #if CEYLAN_ARCH_NINTENDO_DS
00200
00201 #ifdef CEYLAN_RUNS_ON_ARM9
00202
00203 addInBuffer( "<Entered interactive mode, key controls are: X: go to previous paragraph, B: go to next paragraph, up: go to previous line, down: go to next line, Y: toggle text layout (raw/justified/word-wrapped), A: quit>" ) ;
00204
00205 setToForeground( true ) ;
00206
00207 bool quit = false ;
00208 KeyChar readKey ;
00209
00210 do
00211 {
00212
00213 readKey = getChar() ;
00214
00215 if ( readKey & ButtonX )
00216 jumpPreviousText() ;
00217
00218 if ( readKey & ButtonB )
00219 jumpNextText() ;
00220
00221 if ( readKey & ButtonUp )
00222 jumpPreviousLine() ;
00223
00224 if ( readKey & ButtonDown )
00225 jumpNextLine() ;
00226
00227
00228
00229 if ( readKey & ButtonY )
00230 {
00231
00232 TextBuffer::TextLayout layout ;
00233
00234 switch( getTextLayout() )
00235 {
00236
00237 case TextBuffer::Raw:
00238 layout = TextBuffer::WordWrapped ;
00239 break ;
00240
00241 case TextBuffer::WordWrapped:
00242 layout = TextBuffer::Justified ;
00243 break ;
00244
00245 case TextBuffer::Justified:
00246 layout = TextBuffer::Raw ;
00247 break ;
00248
00249 default:
00250 layout = TextBuffer::Raw ;
00251 break ;
00252
00253 }
00254
00255 setTextLayout( layout ) ;
00256
00257 }
00258
00259
00260 if ( readKey & ButtonA )
00261 quit = true ;
00262
00263 }
00264 while( ! quit ) ;
00265
00266 addInBuffer( "<Quitting interactive mode>" ) ;
00267
00268 #endif // CEYLAN_RUNS_ON_ARM9
00269
00270
00271 #else // CEYLAN_ARCH_NINTENDO_DS
00272
00273
00274
00275 #endif // CEYLAN_ARCH_NINTENDO_DS
00276
00277 }
00278
00279
00280
00281 Ceylan::TextBuffer::TextLayout Console::getTextLayout() const
00282 {
00283
00284 return _buffer->getTextLayout() ;
00285
00286 }
00287
00288
00289
00290 void Console::setTextLayout( TextBuffer::TextLayout newLayout )
00291 {
00292
00293 try
00294 {
00295
00296 _buffer->setTextLayout( newLayout ) ;
00297
00298 }
00299 catch( const TextBuffer::TextBufferException & e )
00300 {
00301
00302 throw ConsoleException( "Console::setTextLayout failed: "
00303 + e.toString() ) ;
00304
00305 }
00306
00307
00308 render() ;
00309
00310 }
00311
00312
00313
00314 bool Console::jumpNextText()
00315 {
00316
00317
00318
00319 if ( _buffer->jumpNextText() )
00320 {
00321 render() ;
00322 return true ;
00323 }
00324 else
00325 {
00326 return false ;
00327 }
00328
00329 }
00330
00331
00332
00333 bool Console::jumpPreviousText()
00334 {
00335
00336
00337
00338 if ( _buffer->jumpPreviousText() )
00339 {
00340 render() ;
00341 return true ;
00342 }
00343 else
00344 {
00345 return false ;
00346 }
00347
00348 }
00349
00350
00351
00352 bool Console::jumpNextLine()
00353 {
00354
00355
00356
00357 if ( _buffer->jumpNextLine() )
00358 {
00359 render() ;
00360 return true ;
00361 }
00362 else
00363 {
00364 return false ;
00365 }
00366
00367 }
00368
00369
00370
00371 bool Console::jumpPreviousLine()
00372 {
00373
00374
00375
00376 if ( _buffer->jumpPreviousLine() )
00377 {
00378 render() ;
00379 return true ;
00380 }
00381 else
00382 {
00383 return false ;
00384 }
00385
00386 }
00387
00388
00389
00390 void Console::addInBuffer( const std::string & text )
00391 {
00392
00393
00394
00395 _buffer->add( text ) ;
00396 render() ;
00397
00398 }
00399
00400
00401
00402 void Console::blankBuffer()
00403 {
00404
00405
00406
00407 _buffer->blank() ;
00408
00409 }
00410
00411
00412
00413 void Console::setToForeground( bool toForeground )
00414 {
00415
00416
00417 if ( _inForeground == toForeground )
00418 return ;
00419
00420 if ( toForeground )
00421 {
00422
00423
00424 Initialize( _useBottomScreen, _useSubCore, true ) ;
00425 _inForeground = true ;
00426
00427 }
00428 else
00429 {
00430
00431
00432 _inForeground = false ;
00433
00434
00435
00436 }
00437
00438 }
00439
00440
00441
00442 void Console::render()
00443 {
00444
00445 if ( _buffer == 0 || _inForeground == false )
00446 return ;
00447
00448 #if CEYLAN_ARCH_NINTENDO_DS
00449
00450 #ifdef CEYLAN_RUNS_ON_ARM9
00451
00452 consoleClear() ;
00453
00454 const std::list<char *> & charGrid( _buffer->getScreenLines() ) ;
00455
00456 TextBuffer::CharAbscissa width = _buffer->getWidth() ;
00457
00458 const char * currentLine ;
00459
00460 for ( list<char *>::const_iterator it = charGrid.begin() ;
00461 it != charGrid.end(); it++ )
00462 {
00463
00464 currentLine = (*it) ;
00465
00466 for ( TextBuffer::CharAbscissa i = 0; i < width; i++ )
00467 putchar( currentLine[i] ) ;
00468
00469 }
00470
00471
00472 #endif // CEYLAN_RUNS_ON_ARM9
00473
00474
00475 #else // CEYLAN_ARCH_NINTENDO_DS
00476
00477 const std::list<char *> & charGrid( _buffer->getScreenLines() ) ;
00478
00479 TextBuffer::CharAbscissa width = _buffer->getWidth() ;
00480
00481 const char * currentLine ;
00482
00483 for ( list<char *>::const_iterator it = charGrid.begin() ;
00484 it != charGrid.end(); it++ )
00485 {
00486
00487 currentLine = (*it) ;
00488
00489 for ( TextBuffer::CharAbscissa i = 0; i < width; i++ )
00490 putchar( currentLine[i] ) ;
00491
00492 putchar( '\n' ) ;
00493
00494 }
00495
00496 putchar( '\n' ) ;
00497
00498 #endif // CEYLAN_ARCH_NINTENDO_DS
00499
00500 }
00501
00502
00503
00504 const std::string Console::toString( Ceylan::VerbosityLevels level ) const
00505 {
00506
00507 string res = "Console whose upper-left corner is at ("
00508 + Ceylan::toNumericalString( _xstart ) + ","
00509 + Ceylan::toNumericalString( _ystart ) + ")" ;
00510
00511 if ( _buffer != 0 )
00512 res += ", storing its content in " + _buffer->toString( level ) ;
00513 else
00514 res += ", not having a text buffer" ;
00515
00516 return res ;
00517
00518 }
00519
00520
00521
00522 void Console::SetKeyRepeat( Millisecond durationBeforeFirstRepeat,
00523 Millisecond durationBetweenRepeats )
00524 {
00525
00526 #if CEYLAN_ARCH_NINTENDO_DS
00527
00528 #ifdef CEYLAN_RUNS_ON_ARM9
00529
00530
00531
00532
00533
00534
00535
00536
00537
00538
00539
00540
00541 keysSetRepeat(
00542
00543 ( durationBeforeFirstRepeat * 60 ) / 1000,
00544
00545 ( durationBetweenRepeats * 60 ) / 1000 ) ;
00546
00547 #else // CEYLAN_RUNS_ON_ARM9
00548
00549 throw ConsoleException( "Console::SetKeyRepeat: "
00550 "not available on this platform." ) ;
00551
00552 #endif // CEYLAN_RUNS_ON_ARM9
00553
00554
00555 #else // CEYLAN_ARCH_NINTENDO_DS
00556
00557 throw ConsoleException( "Console::SetKeyRepeat: "
00558 "not available on this platform." ) ;
00559
00560 #endif // CEYLAN_ARCH_NINTENDO_DS
00561
00562 }
00563
00564
00565
00566 void Console::Initialize( bool useBottomScreen, bool useSubCore, bool force )
00567 {
00568
00569 #if CEYLAN_ARCH_NINTENDO_DS
00570
00571 #ifdef CEYLAN_RUNS_ON_ARM7
00572
00573 throw ConsoleException( "Console::Initialize: not supported on the ARM7" ) ;
00574
00575 #else // CEYLAN_RUNS_ON_ARM7
00576
00577
00578 static bool alreadyInitialized = false ;
00579
00580
00581 if ( alreadyInitialized && (!force) )
00582 return ;
00583
00584
00585
00586
00587
00588
00589
00590
00591
00592
00593 if ( useSubCore )
00594 {
00595
00596 powerON( POWER_2D_B ) ;
00597
00598 if ( useBottomScreen )
00599 lcdMainOnTop() ;
00600 else
00601 lcdMainOnBottom() ;
00602
00603
00604 videoSetModeSub( MODE_0_2D | DISPLAY_BG0_ACTIVE ) ;
00605
00606
00607 vramSetBankC( VRAM_C_SUB_BG ) ;
00608
00609 SUB_BG0_CR = BG_MAP_BASE( 31 ) ;
00610
00611
00612 BG_PALETTE_SUB[255] = RGB15(31,31,31) ;
00613
00614 consoleInitDefault(
00615 (u16*) SCREEN_BASE_BLOCK_SUB(31),
00616 (u16*) CHAR_BASE_BLOCK_SUB(0),
00617 16 ) ;
00618
00619 }
00620 else
00621 {
00622
00623
00624
00625 powerON( POWER_2D_A ) ;
00626
00627 if ( useBottomScreen )
00628 lcdMainOnBottom() ;
00629 else
00630 lcdMainOnTop() ;
00631
00632
00633 videoSetMode( MODE_0_2D | DISPLAY_BG0_ACTIVE ) ;
00634
00635
00636 vramSetBankC( VRAM_C_MAIN_BG ) ;
00637
00638 BG0_CR = BG_MAP_BASE( 31 ) ;
00639
00640
00641 PALETTE_SUB[255] = RGB15(31,31,31) ;
00642
00643 consoleInitDefault(
00644 (u16*) SCREEN_BASE_BLOCK(31),
00645 (u16*) CHAR_BASE_BLOCK(0),
00646 16 ) ;
00647
00648 }
00649
00650 alreadyInitialized = true ;
00651
00652 #endif // CEYLAN_RUNS_ON_ARM7
00653
00654
00655 #else // CEYLAN_ARCH_NINTENDO_DS
00656
00657
00658
00659 #endif // CEYLAN_ARCH_NINTENDO_DS
00660
00661 }
00662
00663
00664
00665 void Console::initConsole(
00666 TextBuffer::CharAbscissa startingX,
00667 TextBuffer::CharOrdinate startingY,
00668 TextBuffer::CharAbscissa width,
00669 TextBuffer::CharOrdinate height,
00670 TextBuffer::TextLayout layout,
00671 bool useBottomScreen,
00672 bool useSubCore )
00673 {
00674
00675 if ( _buffer != 0 )
00676 delete _buffer ;
00677
00678 _buffer = new TextBuffer( width, height, layout ) ;
00679
00680 _useBottomScreen = useBottomScreen ;
00681 _useSubCore = useSubCore ;
00682
00683 #if CEYLAN_ARCH_NINTENDO_DS
00684
00685 #ifdef CEYLAN_RUNS_ON_ARM9
00686
00687 SetKeyRepeat() ;
00688
00689 #endif // CEYLAN_RUNS_ON_ARM9
00690
00691
00692 #else // CEYLAN_ARCH_NINTENDO_DS
00693
00694
00695
00696 #endif // CEYLAN_ARCH_NINTENDO_DS
00697
00698
00699 _xstart = startingX ;
00700 _ystart = startingY ;
00701
00702 CEYLAN_CONSOLE_LOG( "Console created" ) ;
00703
00704 }
00705