00001
00007 #include <Slang++/ecra.H>
00008
00009 #include <Utilitarios/ignoradores.H>
00010 #include <Erros/erros.H>
00011
00012 using namespace std;
00013
00014
00015
00016 Slang::Posicao::Posicao(istream& entrada)
00017 {
00018 assert(entrada.good());
00019
00020 entrada >> linha_ >> Utilitarios::il >> coluna_ >> Utilitarios::il;
00021
00022 if(not entrada.good())
00023 throw Erros::ErroAoCarregar("Posicao");
00024
00025 assert(cumpreInvariante());
00026 }
00027
00028 void Slang::Posicao::guardaEm(ostream& saida) const
00029 {
00030 assert(cumpreInvariante());
00031
00032 if(not (saida << linha_ << endl << coluna_ << endl))
00033 throw Erros::ErroAoGuardar("Posicao");
00034 }
00035
00036
00037
00038
00039 Slang::Dimensao::Dimensao(istream& entrada)
00040 {
00041 assert(entrada.good());
00042
00043 entrada >> numero_de_linhas >> Utilitarios::il
00044 >> numero_de_colunas >> Utilitarios::il;
00045
00046 if(not entrada.good())
00047 throw Erros::ErroAoCarregar("Dimensao");
00048
00049 assert(cumpreInvariante());
00050 }
00051
00052 void Slang::Dimensao::guardaEm(ostream& saida) const
00053 {
00054 assert(cumpreInvariante());
00055
00056 if(not (saida << numero_de_linhas << endl << numero_de_colunas << endl))
00057 throw Erros::ErroAoGuardar("Dimensao");
00058 }
00059
00060
00061
00062
00063 void Slang::Caixa::guardaEm(ostream& saida) const
00064 {
00065 assert(cumpreInvariante());
00066
00067 origem_.guardaEm(saida);
00068 dimensao_.guardaEm(saida);
00069 }
00070
00071
00072
00073
00074 istream& Slang::operator>>(istream& entrada, Slang::Cor& cor)
00075 {
00076 string nome;
00077 if(entrada >> nome) {
00078 for(int c = Slang::primeira_cor; c != Slang::numero_de_cores; ++c)
00079 if(Slang::nomes_das_cores[c] == nome) {
00080 cor = Slang::Cor(c);
00081
00082 return entrada;
00083 }
00084 entrada.clear(ios_base::badbit);
00085 }
00086
00087 return entrada;
00088 }
00089
00090
00091
00092
00093 Slang::Ecra::Ecra(Cor cor_do_texto, Cor cor_do_fundo,
00094 bool cursor_deve_ser_limitado)
00095 : cursor_esta_limitado_ao_ecra_real(cursor_deve_ser_limitado),
00096 redimensionado_(false),
00097 cursor_imovel_na_proxima_operacao_de_escrita(false),
00098 justificacao_actual(a_esquerda),
00099 largura_da_proxima_operacao_de_escrita(0),
00100 ocupacao_dos_objectos(ObjectoCor::numero_de_objectos_cor_no_s_lang)
00101 {
00102 assert(not ja_existe_instancia);
00103
00104 ja_existe_instancia = true;
00105
00106
00107
00108 SLtt_get_terminfo();
00109
00110 if(SLsmg_init_smg() == -1) {
00111
00112 assert(false);
00113 }
00114
00115
00116 SLsignal(SIGWINCH, manipuladorDeRedimensionamento);
00117
00118 mudaCoresDasCelulasDoFundoPara(cor_do_texto, cor_do_fundo);
00119
00120 assert(cumpreInvariante());
00121 }
00122
00123 void Slang::Ecra::moveCursorPara(Posicao const& nova_posicao)
00124 {
00125 assert(cumpreInvariante());
00126
00127 verificaRedimensionamento();
00128
00129 int linha = nova_posicao.linha();
00130 int coluna = nova_posicao.coluna();
00131
00132 if(cursor_esta_limitado_ao_ecra_real)
00133 {
00134 if(linha >= dimensao().numeroDeLinhas())
00135 linha = dimensao().numeroDeLinhas() - 1;
00136 else if(linha < 0)
00137 linha = 0;
00138
00139 if(coluna >= dimensao().numeroDeColunas())
00140 coluna = dimensao().numeroDeColunas() - 1;
00141 else if(coluna < 0)
00142 coluna = 0;
00143 }
00144
00145 SLsmg_gotorc(linha, coluna);
00146
00147 assert(cumpreInvariante());
00148 }
00149
00150 void Slang::Ecra::moveCursorDeAcordoCom(Slang::Tecla const& tecla)
00151 {
00152 assert(cumpreInvariante());
00153 assert(tecla.eDeDeslocamento());
00154
00155 switch(tecla)
00156 {
00157 case Tecla::cima:
00158 sobeCursor();
00159 break;
00160
00161 case Tecla::baixo:
00162 baixaCursor();
00163 break;
00164
00165 case Tecla::esquerda:
00166 recuaCursor();
00167 break;
00168
00169 case Tecla::direita:
00170 avancaCursor();
00171 break;
00172
00173 default:
00174 assert(false);
00175 break;
00176 }
00177
00178 assert(cumpreInvariante());
00179 }
00180
00181 Slang::Ecra::Troco const Slang::Ecra::trocoDe(Caixa const& caixa) const
00182 {
00183 assert(cumpreInvariante());
00184 assert(caixa.eCanonica());
00185
00186 verificaRedimensionamento();
00187
00188
00189 Posicao const posicao_original_do_cursor = posicaoDoCursor();
00190
00191 int const linha = caixa.origem().linha();
00192 int const coluna = caixa.origem().coluna();
00193 int const numero_de_linhas = caixa.dimensao().numeroDeLinhas();
00194 int const numero_de_colunas = caixa.dimensao().numeroDeColunas();
00195
00196 Troco troco(caixa.dimensao());
00197 int i = 0;
00198 for(int l = linha; l != linha + numero_de_linhas; ++l)
00199 for(int c = coluna; c != coluna + numero_de_colunas; ++c)
00200 {
00201 moveCursorPara(Posicao(l, c));
00202 troco.dados[i++] = SLsmg_char_at();
00203 }
00204
00205
00206 moveCursorPara(posicao_original_do_cursor);
00207
00208 return troco;
00209 }
00210
00211 void Slang::Ecra::cola(Troco const& troco, Posicao const& em)
00212 {
00213 assert(cumpreInvariante());
00214
00215 verificaRedimensionamento();
00216
00217 Posicao posicao_original_do_cursor;
00218
00219 if(cursor_imovel_na_proxima_operacao_de_escrita)
00220 posicao_original_do_cursor = posicaoDoCursor();
00221
00222 int const linha = em.linha();
00223 int const coluna = em.coluna();
00224 int const numero_de_linhas = troco.dimensao().numeroDeLinhas();
00225 int const numero_de_colunas = troco.dimensao().numeroDeColunas();
00226
00227 int i = 0;
00228 for(int l = linha; l != linha + numero_de_linhas; ++l)
00229 for(int c = coluna; c != coluna + numero_de_colunas; ++c)
00230 {
00231 moveCursorPara(Posicao(l, c));
00232 char const caractere = troco.dados[i] & 0XFF;
00233 int const objecto = troco.dados[i++] >> 8;
00234 SLsmg_set_color(objecto);
00235 SLsmg_write_char(caractere);
00236 }
00237
00238 if(cursor_imovel_na_proxima_operacao_de_escrita) {
00239 moveCursorPara(posicao_original_do_cursor);
00240
00241 cursor_imovel_na_proxima_operacao_de_escrita = false;
00242 }
00243
00244
00245 *this << fundo;
00246
00247 assert(cumpreInvariante());
00248 }
00249
00250 void Slang::Ecra::desenha(Caixa const& caixa)
00251 {
00252 assert(cumpreInvariante());
00253
00254 verificaRedimensionamento();
00255
00256 Posicao posicao_original_do_cursor;
00257
00258 if(cursor_imovel_na_proxima_operacao_de_escrita)
00259 posicao_original_do_cursor = posicaoDoCursor();
00260
00261 SLsmg_draw_box(caixa.origem().linha(), caixa.origem().coluna(),
00262 caixa.dimensao().numeroDeLinhas(),
00263 caixa.dimensao().numeroDeColunas());
00264
00265 if(cursor_imovel_na_proxima_operacao_de_escrita)
00266 {
00267 moveCursorPara(posicao_original_do_cursor);
00268
00269 cursor_imovel_na_proxima_operacao_de_escrita = false;
00270 }
00271
00272 assert(cumpreInvariante());
00273 }
00274
00275 void Slang::Ecra::desenhaSegmentoHorizontalCom(int const largura)
00276 {
00277 assert(cumpreInvariante());
00278
00279 verificaRedimensionamento();
00280
00281 Posicao posicao_original_do_cursor;
00282
00283 if(cursor_imovel_na_proxima_operacao_de_escrita)
00284 posicao_original_do_cursor = posicaoDoCursor();
00285
00286 SLsmg_draw_hline(largura);
00287
00288 if(cursor_imovel_na_proxima_operacao_de_escrita)
00289 {
00290 moveCursorPara(posicao_original_do_cursor);
00291
00292 cursor_imovel_na_proxima_operacao_de_escrita = false;
00293 }
00294
00295 assert(cumpreInvariante());
00296 }
00297
00298 void Slang::Ecra::desenhaSegmentoVerticalCom(int const altura)
00299 {
00300 assert(cumpreInvariante());
00301
00302 verificaRedimensionamento();
00303
00304 Posicao posicao_original_do_cursor;
00305
00306 if(cursor_imovel_na_proxima_operacao_de_escrita)
00307 posicao_original_do_cursor = posicaoDoCursor();
00308
00309 SLsmg_draw_vline(altura);
00310
00311 if(cursor_imovel_na_proxima_operacao_de_escrita)
00312 {
00313 moveCursorPara(posicao_original_do_cursor);
00314
00315 cursor_imovel_na_proxima_operacao_de_escrita = false;
00316 }
00317
00318 assert(cumpreInvariante());
00319 }
00320
00321 Slang::Ecra& Slang::Ecra::operator<<(string const& cadeia_a_escrever)
00322 {
00323 assert(cumpreInvariante());
00324
00325 verificaRedimensionamento();
00326
00327 string cadeia = cadeia_a_escrever;
00328
00329 Posicao posicao_original_do_cursor;
00330 if(cursor_imovel_na_proxima_operacao_de_escrita)
00331 posicao_original_do_cursor = posicaoDoCursor();
00332
00333
00334
00335
00336 if(largura_da_proxima_operacao_de_escrita == 0)
00337 SLsmg_write_string(const_cast<char *>(cadeia.c_str()));
00338 else {
00339 string::size_type espaco_a_usar =
00340 largura_da_proxima_operacao_de_escrita;
00341
00342 if(cadeia.size() < espaco_a_usar)
00343 switch(justificacao_actual) {
00344 case ao_centro:
00345 cadeia =
00346 string((espaco_a_usar - cadeia.size() + 1) / 2,
00347 ' ') + cadeia;
00348 break;
00349 case a_direita:
00350 cadeia =
00351 string(espaco_a_usar - cadeia.size(), ' ') +
00352 cadeia;
00353 break;
00354 case a_esquerda:
00355 cadeia +=
00356 string(espaco_a_usar - cadeia.size(), ' ');
00357 break;
00358 }
00359 else
00360 switch(justificacao_actual) {
00361 case ao_centro:
00362 cadeia = cadeia.substr((cadeia.size() - espaco_a_usar) / 2,
00363 espaco_a_usar);
00364 break;
00365 case a_direita:
00366 cadeia = cadeia.substr(cadeia.size() - espaco_a_usar,
00367 espaco_a_usar);
00368 break;
00369 case a_esquerda:
00370 cadeia = cadeia.substr(0, espaco_a_usar);
00371 break;
00372 }
00373
00374 SLsmg_write_nstring(const_cast<char *>(cadeia.c_str()),
00375 espaco_a_usar);
00376
00377 largura_da_proxima_operacao_de_escrita = 0;
00378 }
00379
00380 if(cursor_imovel_na_proxima_operacao_de_escrita) {
00381 moveCursorPara(posicao_original_do_cursor);
00382 cursor_imovel_na_proxima_operacao_de_escrita = false;
00383 }
00384
00385 assert(cumpreInvariante());
00386
00387 return *this;
00388 }
00389
00390 Slang::Ecra const& Slang::Ecra::operator>>(Troco& troco) const
00391 {
00392 assert(cumpreInvariante());
00393
00394 verificaRedimensionamento();
00395
00396 Posicao const posicao_original_do_cursor = posicaoDoCursor();
00397
00398 int const linha = posicao_original_do_cursor.linha();
00399 int const coluna = posicao_original_do_cursor.coluna();
00400 int const numero_de_linhas = troco.dimensao().numeroDeLinhas();
00401 int const numero_de_colunas =
00402 troco.dimensao().numeroDeColunas();
00403
00404 int i = 0;
00405 for(int l = linha; l != linha + numero_de_linhas; ++l)
00406 for(int c = coluna; c != coluna + numero_de_colunas; ++c) {
00407 moveCursorPara(Posicao(l, c));
00408 troco.dados[i++] = SLsmg_char_at();
00409 }
00410
00411 moveCursorPara(posicao_original_do_cursor);
00412
00413 return *this;
00414 }
00415
00416 void Slang::Ecra::verificaRedimensionamento() const
00417 {
00418 if(tamanho_do_ecra_real_mudou)
00419 {
00420
00421
00422 tamanho_do_ecra_real_mudou = false;
00423
00424
00425
00426
00427 redimensionado_ = true;
00428
00429
00430 Posicao const posicao_do_cursor = posicaoDoCursor();
00431
00432
00433 SLtt_get_screen_size();
00434 SLsmg_reinit_smg();
00435
00436
00437 moveCursorPara(posicao_do_cursor);
00438 }
00439 }
00440
00441 void Slang::Ecra::moveCursorPara(Posicao const& nova_posicao_do_cursor) const
00442 {
00443 verificaRedimensionamento();
00444
00445 int linha = nova_posicao_do_cursor.linha();
00446 int coluna = nova_posicao_do_cursor.coluna();
00447
00448 if(cursor_esta_limitado_ao_ecra_real)
00449 {
00450 if(dimensao().numeroDeLinhas() <= linha)
00451 linha = dimensao().numeroDeLinhas() - 1;
00452 else if(linha < 0)
00453 linha = 0;
00454
00455 if(dimensao().numeroDeColunas() <= coluna)
00456 coluna = dimensao().numeroDeColunas() - 1;
00457 else if(coluna < 0)
00458 coluna = 0;
00459 }
00460
00461 SLsmg_gotorc(linha, coluna);
00462 }
00463
00464 int Slang::Ecra::reservaObjecto()
00465 {
00466 int numero_do_objecto_reservado = 1;
00467 int ocupacao_minima = ocupacao_dos_objectos[1];
00468
00469 for(int numero_do_objecto = 2;
00470 numero_do_objecto != ObjectoCor::numero_de_objectos_cor_no_s_lang;
00471 ++numero_do_objecto)
00472 if(ocupacao_dos_objectos[numero_do_objecto] < ocupacao_minima) {
00473 ocupacao_minima = ocupacao_dos_objectos[numero_do_objecto];
00474 numero_do_objecto_reservado = numero_do_objecto;
00475 }
00476
00477 ++ocupacao_dos_objectos[numero_do_objecto_reservado];
00478
00479 return numero_do_objecto_reservado;
00480 }
00481
00482 void Slang::Ecra::libertaObjecto(int const numero_do_objecto)
00483 {
00484 assert(1 <= numero_do_objecto and
00485 numero_do_objecto < ObjectoCor::numero_de_objectos_cor_no_s_lang);
00486 assert(ocupacao_dos_objectos[numero_do_objecto] != 0);
00487
00488 --ocupacao_dos_objectos[numero_do_objecto];
00489 }
00490
00491
00492 bool Slang::Ecra::ja_existe_instancia = false;
00493
00494 bool volatile Slang::Ecra::tamanho_do_ecra_real_mudou = false;
00495
00496 char* Slang::Ecra::nome_de_cor_do_s_lang[numero_de_cores] = {
00497 "black",
00498 "gray",
00499 "red",
00500 "brightred",
00501 "green",
00502 "brightgreen",
00503 "brown",
00504 "yellow",
00505 "blue",
00506 "brightblue",
00507 "magenta",
00508 "brightmagenta",
00509 "cyan",
00510 "brightcyan",
00511 "lightgray",
00512 "white"
00513 };
00514
00515 Slang::Ecra Slang::ecra;
00516
00517 string const Slang::nomes_das_cores[numero_de_cores] = {
00518 "preto",
00519 "cinza",
00520 "vermelho",
00521 "vermelho-brilhante",
00522 "verde",
00523 "verde-brilhante",
00524 "castanho",
00525 "amarelo",
00526 "azul",
00527 "azul-brilhante",
00528 "magenta",
00529 "magenta-brilhante",
00530 "ciano",
00531 "ciano-brilhante",
00532 "cinzento-claro",
00533 "branco"
00534 };
00535
00536
00537 #ifdef TESTE
00538
00539 #include <fstream>
00540
00541 using namespace Slang;
00542
00543 int main()
00544 {
00545 Posicao p;
00546
00547 assert(p == Posicao());
00548 assert(p == Posicao(0, 0));
00549
00550 p.mudaLinhaPara(10);
00551 p.mudaColunaPara(20);
00552
00553 assert(p == Posicao(10, 20));
00554 assert(p.linha() == 10);
00555 assert(p.coluna() == 20);
00556
00557 ofstream saida("ecra.lixo");
00558
00559 p.guardaEm(saida);
00560
00561 saida.close();
00562
00563 ifstream entrada("ecra.lixo");
00564
00565 Posicao q(entrada);
00566
00567 assert(p == q);
00568
00569 entrada.seekg(0);
00570
00571 p = Posicao(0, 0);
00572
00573 assert(p == Posicao(0, 0));
00574
00575 p.carregaDe(entrada);
00576
00577 entrada.close();
00578
00579 assert(p == q);
00580
00581 p += Dimensao(-20, -10);
00582
00583 assert(p == Posicao(-10, 10));
00584
00585 p -= Dimensao(-20, -10);
00586
00587 assert(p == q);
00588
00589 assert(p + Dimensao(-20, -10) == Posicao(-10, 10));
00590
00591 assert(p - Dimensao(20, 10) == Posicao(-10, 10));
00592
00593 assert(Dimensao(-20, -10) + p == Posicao(-10, 10));
00594
00595 assert(Dimensao(20, 10) - p == Posicao(10, -10));
00596
00597 assert(p - Posicao(0, 0) == Dimensao(10, 20));
00598
00599 assert(Posicao(0, 0) - p == Dimensao(-10, -20));
00600
00601 assert(-p == Posicao(-10, -20));
00602
00603
00604 Dimensao d(p);
00605
00606 assert(d == Dimensao(10, 20));
00607
00608 assert(d.numeroDeLinhas() == 10);
00609
00610 assert(d.numeroDeColunas() == 20);
00611
00612 assert(d.eCanonica());
00613
00614 d = -d;
00615
00616 assert(d == Dimensao(-10, -20));
00617
00618 assert(not d.eCanonica());
00619
00620 d.mudaNumeroDeLinhasPara(0);
00621
00622 d.mudaNumeroDeColunasPara(0);
00623
00624 assert(d == Dimensao(0, 0));
00625
00626 d = Dimensao(p);
00627
00628 assert(d == Dimensao(10, 20));
00629
00630 saida.open("ecra.lixo");
00631
00632 d.guardaEm(saida);
00633
00634 saida.close();
00635
00636 entrada.open("ecra.lixo");
00637
00638 Dimensao e(entrada);
00639
00640 assert(d == e);
00641
00642 entrada.seekg(0);
00643
00644 d = Dimensao(0, 0);
00645
00646 assert(d == Dimensao(0, 0));
00647
00648 d.carregaDe(entrada);
00649
00650 entrada.close();
00651
00652 assert(d == e);
00653
00654 d += Dimensao(-20, -10);
00655
00656 assert(d == Dimensao(-10, 10));
00657
00658 d -= Dimensao(-20, -10);
00659
00660 assert(d == e);
00661
00662 assert(d + Dimensao(-20, -10) == Dimensao(-10, 10));
00663
00664 assert(d - Dimensao(20, 10) == Dimensao(-10, 10));
00665
00666
00667 Caixa c1(Posicao(10, 20), Dimensao(3, 6));
00668 Caixa c2(Posicao(10, 20), Posicao(12, 25));
00669
00670 assert(not c1.eVazia());
00671
00672 assert(c1.eCanonica());
00673
00674 assert(c1 == c2);
00675
00676 assert(c1.origem() == Posicao(10, 20));
00677 assert(c1.extremo() == Posicao(12, 25));
00678 assert(c1.dimensao() == Dimensao(3, 6));
00679
00680 c1.mudaDimensaoPara(Dimensao(0, 0));
00681
00682 assert(c1.eVazia());
00683
00684 assert(c1.eCanonica());
00685
00686 c1.mudaDimensaoPara(Dimensao(-6, -8));
00687
00688 assert(not c1.eVazia());
00689
00690 assert(not c1.eCanonica());
00691
00692 assert(c1.extremo() == Posicao(3, 11));
00693 assert(c1.dimensao() == Dimensao(-6, -8));
00694
00695 c1 += Dimensao(7, 9);
00696
00697 assert(c1.dimensao() == Dimensao(-6, -8));
00698 assert(c1.origem() == Posicao(17, 29));
00699
00700 assert((c1 + Dimensao(-7, -9)).origem() == Posicao(10, 20));
00701 assert((c1 - Dimensao(7, 9)).origem() == Posicao(10, 20));
00702
00703 assert(c1 + c2 == Caixa(Posicao(10, 20), Posicao(12, 25)));
00704 assert(c1 * c2 == Caixa(Posicao(17, 29), Posicao(10, 20)));
00705
00706
00707 }
00708
00709 #endif // TESTE