Introdu��o �s Ncurses

ArticleCategory: [Choose a category, translators: do not translate this, see list below for available categories]

Software Development

AuthorImage:[Here we need a little image from you]

[RehaGerceker]

TranslationInfo:[Author + translation history. mailto: or http://homepage]

original in tr Reha K. Gerçeker

tr to en Reha K. Gerçeker

en to pt Bruno Sousa

AboutTheAuthor:[A small biography about the author]

O Reha � um estudante de engenharia inform�tica em Istanbul, na Turquia. Ela adora a liberdade que o Linux fornece como plataforma de desenvolvimento de software. Ele passa muito do seu tempo � frente do seu computador, escrevendo programas. Ele deseja tornar-se um programador inteligente. num destes dias.

Abstract:[Here you write a little summary]

As Ncurses s�o uma biblioteca que fornecem o mapeamento para teclas de fun��o, fun��es de desenho de ecr�s e a possibilidade de utilizar m�ltiplas janelas n�o sobrepostas em terminais � base de texto.

ArticleIllustration:[One image that will end up at the top of the article]

[ncurses]

ArticleBody:[The main part of the article]

O que � que s�o as Ncurses?

Quer que o seu programa tenha uma interface colorida nos terminais de texto? As Ncurses s�o uma biblioteca que lhe fornecem funcionalidades de janelas em terminais � base de texto. Coisas de que as ncurses s�o capazes:



� poss�vel utilizar as ncurses em qualquer sistema UNIX que obedecem � norma ANSI/POSIX. � parte disto, a biblioteca � capaz de detectar propriedades do terminal a partir da base de dados do sistema e agir em conformidade, fornecendo uma interface independente do terminal. Assim as ncurses podem ser utilizadas, fiavelmente, para trabalhos que s�o supostos trabalhar em plataformas diferentes e em v�rios terminais.

O Midnight Commander � um dos exemplos escritos com as ncurses. A interface utilizada para a configura��o do Kernel � escrita com as ncurses. Pode ver as suas fotografias instant�neas abaixo.


[Midnight Commander]

[kernel config]

Onde fazer Download?

As Ncurses s�o desenvolvidas sob a GNU/Linux. Para obter a �ltima vers�o, obtenha informa��o detalhada e outras liga��es relativas �s ncurses, visite www.gnu.org/software/ncurses/.

Elementos B�sicos

No sentido de utilizar a biblioteca, deve incluir no seu c�digo fonte a curses.h, e tenha a certeza de ligar o seu c�digo � biblioteca das curses. Isto pode ser feito atrav�s do par�metro -lcurses dado ao gcc.

� necess�rio conhecer a estrutura de dados fundamental, enquanto trabalha com as ncurses. Ou seja a estrutura WINDOW, como se depreende facilmente pelo nome, � usada para representar as janelas que cria. Praticamente todas as fun��es da biblioteca recebem como par�metro um ponteiro do tipo WINDOW.

Os componentes comuns mais utilizados s�o janelas. Mesmo que n�o crie as suas pr�prias janelas o ecr� � considerado como uma s� janela. Como o descritor do tipo FILE, stdout da biblioteca de entrada/sa�da padr�o representa o ecr� (quando n�o h� redirec��es), as ncurses t�m um ponteiro do tipo WINDOW, stdscr que faz o mesmo trabalho. Adicionalmente ao stdsrc, outro ponteiro do tipo WINDOW, com o nome de curscr � definido na biblioteca. O stdsrc representa o ecr�, o cursrc representa o ecr� corrente para a biblioteca. Pode perguntar "Qual � a diferen�a?" Continue a leitura.

No sentido de utilizar as fun��es ncurses e vari�veis nos seus programas, tem de chamar a fun��o initscr. Esta fun��o aloca mem�ria para as vari�veis como stdscr, curscr e torna a biblioteca pronta para ser utilizada. Por outras palavras, todas as fun��es das ncurses devem ser precedidas de initscr. Do mesmo modo deve chamar a fun��o endwin quando termina todo o trabalho com as ncurses. Isto liberta a mem�ria utilizada pelas ncurses. Depois de chamar a fun��o endwin n�o pode utilizar as fun��es das ncurses a n�o ser que chame novamente a fun��o initscr.

Entre as chamadas � fun��o initscr e a endwin, certifique-se de n�o enviar dados de sa�da para o ecr� utilizando as fun��es da biblioteca padr�o. Caso contr�rio, pode obter um ecr� n�o pretendido e normalmente corrompido. Quando as ncurses est�o activas, utilize as suas pr�prias fun��es para enviar os dados de sa�da para o ecr�. Antes de chamar a fun��o initsrc e depois de chamar a endwin, pode fazer o que quiser.

Actualizando o ecr�: refrescamento

A estrutura WINDOW n�o somente mant�m a altura, o comprimento e a posi��o da janela mas tamb�m assegura os conte�dos da janela. Quando escreve para uma janela os conte�dos da janela alteram-se, mas isto n�o quer dizer que apare�am logo no ecr� imediatamente. No sentido de ter o ecr� actualizado, quer o refresh ou o wrefresh t�m de ser invocados.

Aqui est� a diferen�a entre o initscr e o curscr. Enquanto que o curscr guarda os conte�dos do ecr� corrente, o stdscr pode ter informa��o diferente ap�s as chamadas de output das ncurses. Se quiser que as �ltimas altera��es no stdscr se reflictam no curscr, precisa de chamar o refresh. Por outras palavras a fun��o refresh � a �nica que lida com o curscr. � recomend�vel que n�o mexa no curscr e o deixe para ser actualizado pela fun��o refresh.

A fun��o refresh tem um mecanismo de actualizar o ecr� o mais r�pido poss�vel. Quando a fun��o � chamada, s� actualiza as linhas que foram alteradas da janela. Isto salvaguarda tempo de CPU, bem como previne o programa de escrever a mesma informa��o novamente no ecr�. Este mecanismo � a raz�o pela qual as fun��es das ncurses e as fun��es da biblioteca de entrada/sa�da padr�o podem produzir maus resultados quando utilizadas em conjunto; quando as fun��es das ncurses s�o chamadas elas alteram o valor de uma flag que diz � fun��o refresh que a linha se alterou, enquanto que com as fun��es da biblioteca de entrada/sa�da padr�o nada disto se passa.

As fun��es refresh e wrefresh, basicamente, fazem o mesmo. A fun��o wrefresh recebe por par�metro um ponteiro do tipo WINDOW e refresca somente os conte�dos dessa janela. refresh() � equivalente a wrefresh(stdscr). Como mencionarei mais tarde, assim como a fun��o wrefresh a maioria das fun��es das ncurses t�m macros que aplicam estas modifica��es ao stdscr.

Criando Novas Janelas

Falemos agora acerca da subwin e da newwin, as fun��es que criam novas janelas. Ambas recebem por par�metro a altura, o comprimento, as coordenadas do canto esquerdo superior da nova janela. Retornam um ponteiro do tipo WINDOW que representa a nova janela. Pode utilizar este novo ponteiro com a fun��o wrefresh e outras que falarei mais tarde.

"Se fazem o mesmo, porqu� duplicar as fun��es?" poder� estar a questionar-se. Voc� tem raz�o, elas s�o um pouco diferentes. A fun��o subwin cria uma nova janela como sendo uma sub-janela de outra. Uma janela criada deste modo, herda propriedades da janela m�e. Estas propriedades podem ser mais tarde alteradas sem afectar a janela m�e.

Apesar disto, h� uma coisa que une a janela m�e � janela filha. A tabela de caracteres que mant�m os conte�dos de uma janela � partilhado entre as janelas m�e e filha. Por outras palavras, os caracteres na intersec��o das duas janelas, pode ser alterado por qualquer uma delas. Se a janela m�e escreve para tal espa�o, o conte�do da janela filha � tamb�m alterado. O inverso tamb�m se aplica.

Ao contr�rio da fun��o subwin, a fun��o newwin cria verdadeiramente uma nova janela. Tal janela, a n�o ser que possua as suas pr�prias sub-janelas, n�o partilha a sua tabela de caracteres com outra janela. A vantagem de utilizar a fun��o subwin � que a utiliza��o de uma tabela de caracteres partilhada usa menos mem�ria. Contudo, quando janelas escrevem umas por cima das outras, a utiliza��o da fun��o newwin traz as suas pr�prias vantagens.

Pode criar as suas pr�prias janelas em qualquer profundidade. Qualquer sub-janela pode ter as suas pr�prias sub-janelas, mas tenha em mente que a mesma tabela de caracteres � partilhada por mais do que duas janelas.

Quando n�o precisar mais da janela que criou, pode apag�-la utilizando a fun��o delwin. Sugiro que consulte as p�ginas man para a lista de par�metros destas fun��es.

Escreva para as Janelas, leia das Janelas

Fal�mos acerca do stdscr, do curscr, refrescar o ecr� e criar novas janelas. Mas ent�o, como � que escrevemos para uma janela? Ou como � que lemos dados de uma janela?

As fun��es utilizadas para este prop�sitos assemelham-se �s fun��es correspondentes da biblioteca de entrada/sa�da padr�o. Entre estas fun��es est�o a printw em vez da printf, a scanw em vez da scanf, a addch em vez da putc ou a putchar, getch em vez da getc ou getchar. S�o utilizadas como normalmente, s� os seus nomes s�o diferentes. Semelhantemente, a fun��o addstr podia ser utilizada para escrever uma string para uma janela e a fun��o getstr para ler uma string de uma janela. Todas estas fun��es com uma letra 'w' adicionada � frente do seu nome e que recebem como primeiro par�metro um ponteiro do tipo WINDOW, fazem o seu trabalho numa janela diferente da stdscr. Por exemplo, printw e wprintw(stdsrc, ...) s�o equivalentes, tal e qual como refresh e wrefresh(stdscr).

Seria uma hist�ria muito comprida, entrar nos detalhes destas fun��es. As p�ginas mans�o a melhor fonte para aprender as suas descri��es, prot�tipos, valores de retorno e outras notas. Sugiro que verifique as p�ginas man para cada fun��o que usar. Elas oferecem informa��o detalhada e valiosa. A �ltima sec��o deste artigo, onde apresento um programa de exemplo pode tamb�m servir de tutorial em como utilizar estas fun��es.

Cursores F�sicos e L�gicos.

� preciso explicar os cursores f�sicos e l�gicos depois de falar em como escrever e ler das janelas. O cursor f�sico � o cursor habitual que pisca no ecr� e, s� existe um cursor f�sico. Por outro lado, os cursores l�gicos pertencem �s ncurses e cada janela tem um deles. Assim podem existir v�rios cursores l�gicos.

O cursor l�gico est� na posi��o da janela onde se iniciar� o processo de leitura ou escrita. Assim, sendo capaz de mover o cursor l�gico significa que pode escrever em qualquer s�tio do ecr� e em qualquer altura. Isto � uma vantagem das ncurses sob a biblioteca de entrada e sa�da padr�o.

A fun��o que move o cursor l�gico � a move ou como pode advinhar a wmove. A fun��o move � uma macro da wmove, escrita para o stdscr.

Outra mat�ria � a coordena��o dos cursores l�gicos e f�sicos. A posi��o do cursor f�sico terminar� ap�s um processo de escrita e � determinada pela flag _leave que existe na estrutura WINDOW. Se a flag _leave est� activada o cursor l�gico � movido para a posi��o do cursor f�sico (onde o �ltimo caracter � escrito) ap�s o t�rmio da escrita. Se a flag _leave n�o est� definida, o cursor f�sico regressa � posi��o do cursor l�gico (onde o primeiro caracter � escrito) ap�s o t�rmio da escrita. A flag _leave � controlada pela fun��o leaveok.

A fun��o que move o cursor f�sico � a mvcur. Ao contr�rio de outras, a fun��o mvcur tem efeito imediato e n�o ap�s o pr�ximo refrescamento. Se quiser que o cursor f�sico seja invis�vel, ent�o use a fun��o curs_set. Verifique as p�ginas man para os detalhes.

Existem, tamb�m macros, que combinam as fun��es de escrita e movimento, descritas acima numa s� chamada. S�o explicadas, de um modo simp�tico, nas mesmas p�ginas man que as fun��es addch, addstr, printw, getch, getstr, scanw, etc.

Limpando as Janelas

A escrita para janelas est� feita. Mas como � que limpamos as janelas, as linhas, ou os caracteres?

Limpar nas ncurses significa preencher o quadrado, a linha ou os conte�dos da janela com espa�os brancos. As fun��es que eu explicarei abaixo, preenchem os espa�os necess�rios com espa�os brancos e limpam, assim o ecr�.

Primeiro, falemos de fun��es que limpam um caracter ou uma linha. As fun��es delch e wdelch apagam o caracter que est� sobre o cursor l�gico da janela e reposicionam os caracteres que se seguem na mesma linha. A fun��o deleten e wdeleteln apagam a linha onde est� posicionada o cursor l�gico e move para cima todas as linhas seguintes.

As fun��es clrtoeol e wclrtoeol apagam todos os caracteres na mesma linha � direita do cursor l�gico. As fun��es clrtobot e wclrtobot primeiro chamam a fun��o wclrtoeol para apagar todos os caracteres � direita da cursor l�gico e depois apagam todas as linhas seguintes.

Outras, al�m destas, limpam todo o ecr� ou toda uma janela. Existem dois m�todos para limpara todo um ecr�. O primeiro � preencher todo um espa�o com espa�os brancos e chamar a fun��o refresh e o outro � utilizar um c�digo de controle, incorporado de terminal. O primeiro m�todo � mais lento que o segundo pois requer que todos espa�os no ecr� sejam rescritos, enquanto que o segundo limpa o ecr� imediatamente.

A fun��o erase e werase preenchem o vector de caracteres de uma janela com espa�os brancos. No pr�ximo refrescamento, a janela � limpa. Contudo, se a janela a ser limpa preenche todo o ecr�, n�o � l� muito inteligente utilizar estas fun��es. Elas utilizam o primeiro m�todo descrito acima. Quando a janela a ser limpa � do tamanho do ecr�, tem vantagem utilizar as fun��es abaixo.

Antes de passar a outras fun��es, � tempo de mencionar a flag _clear. Existe na estrutura WINDOW e se estiver activada, pede � fun��o refresh para enviar um c�digo de controle ao terminal quando � chamada. Quando chamada, a fun��o refresh verifica se a janela � do tamanho do ecr� (utilizando a flag _FULLWIN) e se for limpa o ecr� com um m�todo incorporado de terminal. S� escreve caracteres em vez dos espa�os brancos no ecr�. Isto torna a limpeza de todo o ecr� mais r�pida. A raz�o porque o m�todo de terminal � s� utilizada para janelas que preenchem todo o ecr� � que o c�digo de controle de terminal limpa todo o ecr� e n�o somente e janela. A flag _clear � controlada pela fun��o clearok.

As fun��es clear e wclear s�o utilizadas para limpar janelas do tamanho do ecr�. De facto, estas fun��es s�o equivalentes a chamar a fun��o werase e clearok. Primeiro preenchem o vector de caracteres da janela com espa�os brancos. Depois, definindo flag _clear, elas limpam o ecr� utilizando o m�todo incorporado de terminal se a janela � do tamanho do ecr� ou refrescam todos os espa�os da janela preenchendo-a com espa�os brancos.

Como resultado, se souber que a janela a ser limpa ocupa todo o ecr� ent�o utilize a fun��o clear ou wclear. Produz o resultado mais r�pido. Contudo, n�o existe diferen�a em utilizar a fun��o wclear ou werase quando a janela n�o � do tamanho do ecr�.

Utilizando Cores

As cores que v� no ecr� devem ser pensadas como pares de cores. Isto porque cada quadrado tem uma cor de fundo e de frente. Escrever cores com as ncurses significa criar os seus pr�prios pares de cores e utiliz�-los para escrever para uma janela.

Assim como o initscr precisa de ser chamado para iniciar as ncurses, a fun��o start_color precisa de ser chamada para inicializar as cores. A fun��o que precisa para criar o seu par de cores � a init_pair. Quando cria um par de cores com a fun��o init_pair, este par fica associado ao n�mero que deu � fun��o como primeiro par�metro. Assim, sempre que se quiser utilizar este par, refere-se a ele chamando o COLOR_PAIR com o respectivo n�mero associado.

Para al�m de criar os pares de cores, precisa de ter fun��es que escrevam com um par de cor diferente. Isto faz-se atrav�s das fun��es attron e wattron. Estas fun��es, at� que a fun��o attroff ou a wattroff sejam chamadas, fazem com que tudo seja escrito na janela correspondente com a cor do par que escolheu.

Existem, tamb�m as fun��es bkgd e wbkgd que alteram o par da cor que est� associado a uma janela inteira. Quando chamadas, alteram as cores de fundo e frente de todos os espa�os da janela. Ou seja, no pr�ximo refrescamento, todos os espa�os da janela s�o rescritos com o novo par de cores.

Veja as p�ginas man acerca das cores disponiveis e dos detalhes das fun��es mencionadas aqui.

Caixas, � volta das Janelas

Voc� cria caixas � volta das suas janelas para criar um bom visual aso seu programa. Existe uma macro na biblioteca chamada box que o faz por si. Ao contr�rio de outras a fun��o/macro wbox n�o existe; a box recebe como par�metro um ponteiro do tipo WINDOW.

Pode encontrar facilmente os detalhes da fun��o box nas p�ginas man. H� algo mais que deve ser mencionado. P�r uma janela dentro de uma caixa significa, simplesmente, escrever os caracteres necess�rios para o vector de caracteres da janela e que corresponde aos limites de fronteiras. Se, mais tarde escrever para tais fronteiras, a caixa pode ficar corrompida. Para se prevenir disto, voc� cria uma janela interna, dentro da janela original com a fun��o subwin, ponha a janela original numa caixa e utiliza a janela interna para escrever para a janela quando for necess�rio.

Teclas de Fun��o

No sentido de poder utilizar as teclas de fun��o, a flag _use_keypad deve ser activada na janela de onde est� a obter os dados. keypad � a fun��o que define o valor de _use_keypad. Quando define o valor de _use_keypad, pode obter dados do teclado com as fun��es de entrada de dados, normalmente.

Neste caso, se por exemplo, utilizar a fun��o getch para obter dos dados deve ter cuidado para guardar os dados numa vari�vel do tipo int em vez de uma vari�vel do tipo char. Isto � assim porque os valores num�ricos das teclas de fun��o s�o superiores aqueles que uma vari�vel do tipo char pode suportar. N�o precisa de saber estes valores num�ricos das teclas de fun��o, utilize em vez dos n�meros os nomes definidos na biblioteca. Estes nomes est�o listados na p�gina man da fun��o getch.

Um exemplo

Vamos agora analisar um programa simples e simp�tico. Neste programa, criam-se menus utilizando as ncurses e a selec��o de uma op��o do menu � demonstrada. Um aspecto interessante deste programa � a utiliza��o das janelas ncurses para gerar o efeito de menu. Pode ver a sua fotografia abaixo.

[programa de exemplo]

O programa come�a com ficheiro header inclu�dos, como � habitual. Depois definimos as constantes que s�o os valores ASCII das teclas enter e escape.

#include <curses.h>
#include <stdlib.h>

#define ENTER 10
#define ESCAPE 27

A fun��o abaixo � a primeira a ser chamada quando o programa corre. Primeiro chama a fun��o initscr para inicializar as ncurses e a fun��o start_color para tornar o uso das cores poss�veis. Os pares de cores que ser�o utilizados no programa s�o definidos logo de seguida. A fun��o curs_set(0) torna o cursor f�sico invis�vel. A fun��o noecho impede que os dados introduzidos atrav�s do teclado sejam apresentados no ecr�. Pode tamb�m utilizar a fun��o noecho para controlar a entrada de dados atrav�s do teclado e apresentar somente as partes que deseja apresentar. A fun��o echo deve ser chamada quando � necess�rio eliminar o efeito de noecho. A fun��o abaixo chama por fim a fun��o keypad para activar as teclas de fun��o quando obtendo dados de entrada a partir do stdscr. Isto � necess�rio visto utilizarmos as teclas F1, F2 e os cursores mais tarde no programa.

void init_curses()
{
    initscr();
    start_color();
    init_pair(1,COLOR_WHITE,COLOR_BLUE);
    init_pair(2,COLOR_BLUE,COLOR_WHITE);
    init_pair(3,COLOR_RED,COLOR_WHITE);
    curs_set(0);
    noecho();
    keypad(stdscr,TRUE);
}

A pr�xima fun��o cria a barra de menu que aparece no topo do ecr�. Pode verificar a fun��o main abaixo e verificar que a barra de menu que aparece como uma s� linha no topo do ecr� � de facto definido como uma s� linha de uma sub-janela do stdscr. A fun��o abaixo recebe como par�metro o ponteiro para essa janela, altera em primeiro lugar a cor de fundo e depois escreve o nome dos menus. Utilizamos a fun��o waddstr para escrever os nomes dos menus, outra fun��o poderia ter sido utilizada. Preste aten��o �s chamadas da fun��o wattron que s�o usadas para escrever com um par de cor diferente (n�mero 3) em vez de utilizar o par com a cor por omiss�o (n�mero 2). Lembre-se que o par n�mero 2 foi definido como sendo o par por omiss�o na primeira linha atrav�s da fun��o wbkgd. A fun��o wattroff � chamada quando queremos alterar o par com a cor por omiss�o.

void draw_menubar(WINDOW *menubar)
{
    wbkgd(menubar,COLOR_PAIR(2));
    waddstr(menubar,"Menu1");
    wattron(menubar,COLOR_PAIR(3));
    waddstr(menubar,"(F1)");
    wattroff(menubar,COLOR_PAIR(3));
    wmove(menubar,0,20);
    waddstr(menubar,"Menu2");
    wattron(menubar,COLOR_PAIR(3));
    waddstr(menubar,"(F2)");
    wattroff(menubar,COLOR_PAIR(3));
}

A pr�xima fun��o desenha os menus quando as teclas F1 e F2 s�o premidas. Para criar o efeito de menu uma nova janela com a mesma cor branca que a barra de menu � criada por cima da janela azul que faz de fundo. N�o queremos que esta nova janela sobreponha os caracteres escritos na parte de fundo. Devem permanecer l� at� que o menu seja fechado. Esta � a raz�o pela qual a janela de menu n�o pode ser criada como uma sub-janela do stdscr. Como ver� abaixo, os itens[0] da janela s�o criados com a fun��o newwin e os outros 8 itens s�o criados como sub-janelas dos itens[0]. Aqui os itens[0] s�o utilizados para desenhar uma caixa � volta do menu e os outros itens de janelas s�o utilizados para mostrar o item seleccionado no menu, bem como para n�o sobrepor os caracteres � volta da caixa do menu. Para fazer com que um item de menu pare�a seleccionado , basta tornar a sua cor de fundo diferente do resto dos itens. � o que � feito ma terceira linha a contar do topo; a cor de fundo do primeiro item � tornada diferente das outras, assim quando o menu de pop up aparece � o primeiro item que � seleccionado.

WINDOW **draw_menu(int start_col)
{
    int i;
    WINDOW **items;
    items=(WINDOW **)malloc(9*sizeof(WINDOW *));

    items[0]=newwin(10,19,1,start_col);
    wbkgd(items[0],COLOR_PAIR(2));
    box(items[0],ACS_VLINE,ACS_HLINE);
    items[1]=subwin(items[0],1,17,2,start_col+1);
    items[2]=subwin(items[0],1,17,3,start_col+1);
    items[3]=subwin(items[0],1,17,4,start_col+1);
    items[4]=subwin(items[0],1,17,5,start_col+1);
    items[5]=subwin(items[0],1,17,6,start_col+1);
    items[6]=subwin(items[0],1,17,7,start_col+1);
    items[7]=subwin(items[0],1,17,8,start_col+1);
    items[8]=subwin(items[0],1,17,9,start_col+1);
    for (i=1;i<9;i++)
        wprintw(items[i],"Item%d",i);
    wbkgd(items[1],COLOR_PAIR(1));
    wrefresh(items[0]);
    return items;
}

A pr�xima fun��o apaga, simplesmente, a janela de menu criada pela fun��o acima. Apaga primeiro os itens da janela com a fun��o delwin e depois liberta a mem�ria dos ponteiros do tipo item.

void delete_menu(WINDOW **items,int count)
{
    int i;
    for (i=0;i<count;i++)
        delwin(items[i]);
    free(items);
}

A fun��o scroll_menu permite-nos fazer scroll entre e dentro dos menus. L� as teclas primidas no teclado com a fun��o getch. Se os cursores baixo, cima s�o premidos ent�o os itens abaixo ou em cima s�o seleccionados. Isto � feito, como se recorda, tornando a cor de fundo do item seleccionado diferente do resto. Se os cursores direita, esquerda s�o premidos ent�o o menu aberto � fechado e aberto outro. Se a tecla enter for pressionada, ent�o o item seleccionado � retornado. Se a tecla ESC � premida, os menus s�o fechados sem que seja seleccionado algum item. A fun��o ignora outras teclas de entrada. Nesta fun��o o getch � capaz de ler as teclas de cursor a partir do teclado. Permita-me que o lembre que isto � poss�vel visto que a primeira fun��o init_curses chama keypad(stdsrc, TRUE) e os valor de retorno da fun��o getch � mantido numa vari�vel inteira, em vez de numa vari�vel do tipo char, pois os seus valores s�o para al�m dos valores suportados por uma vari�vel do tipo char.

int scroll_menu(WINDOW **items,int count,int menu_start_col)
{
    int key;
    int selected=0;
    while (1) {
        key=getch();
        if (key==KEY_DOWN || key==KEY_UP) {
            wbkgd(items[selected+1],COLOR_PAIR(2));
            wnoutrefresh(items[selected+1]);
            if (key==KEY_DOWN) {
                selected=(selected+1) % count;
            } else {
                selected=(selected+count-1) % count;
            }
            wbkgd(items[selected+1],COLOR_PAIR(1));
            wnoutrefresh(items[selected+1]);
            doupdate();
        } else if (key==KEY_LEFT || key==KEY_RIGHT) {
            delete_menu(items,count+1);
            touchwin(stdscr);
            refresh();
            items=draw_menu(20-menu_start_col);
            return scroll_menu(items,8,20-menu_start_col);
        } else if (key==ESCAPE) {
            return -1;
        } else if (key==ENTER) {
            return selected;
        }
    }
}

Por �ltimo h� a fun��o main. Utiliza todas as fun��es que descrevi em cima e que fazem com que o programa trabalhe devidamente. L� tamb�m as teclas premidas com a fun��o getch e se a tecla F1 ou a F2 � premida, desenha o janela de menu correspondente com a fun��o draw_menu. Ap�s isto chama a fun��o scroll_menu e deixa o utilizador fazer uma selec��o a partir dos menus. Ap�s o retorno da fun��o scroll_menu apaga as janelas de menu e imprime o item seleccionado na barra de mensagem.

Devia mencionar a fun��o touchwin. Se a fun��o refresh fosse chamada sem a touchwin ap�s os menus serem fechados, o �ltimo menu aberto teria ficado no ecr�. Isto � assim porque as fun��es de menu n�o alteram a stdsrc de nenhum modo, quando a fun��o refresh � chamada. N�o escreve por cima de nenhum caracter da stdsrc pois assume que a janela n�o se alterou. A fun��o touchwin define todas as flags na estrutura da WINDOW o que diz para refrescar todas as linhas da janela que se alteraram e assim, at� ao pr�ximo refrescamento toda a janela tem de ser rescrita mesmo que os conte�dos da janela n�o se tenham alterado. A informa��o escrita na stdsrc permanece l� ap�s o fecho dos menus visto que estes n�o escrevem por cima do stdsrc mas por cima de novas janelas.

int main()
{
    int key;
    WINDOW *menubar,*messagebar;
    
    init_curses();
    
    bkgd(COLOR_PAIR(1));
    menubar=subwin(stdscr,1,80,0,0);
    messagebar=subwin(stdscr,1,79,23,1);
    draw_menubar(menubar);
    move(2,1);
    printw("Press F1 or F2 to open the menus. ");
    printw("ESC quits.");
    refresh();

    do {
        int selected_item;
        WINDOW **menu_items;
        key=getch();
        werase(messagebar);
        wrefresh(messagebar);
        if (key==KEY_F(1)) {
            menu_items=draw_menu(0);
            selected_item=scroll_menu(menu_items,8,0);
            delete_menu(menu_items,9);
            if (selected_item<0)
                wprintw(messagebar,"You haven't selected any item.");
            else
                wprintw(messagebar,
                  "You have selected menu item %d.",selected_item+1);
            touchwin(stdscr);
            refresh();
        } else if (key==KEY_F(2)) {
            menu_items=draw_menu(20);
            selected_item=scroll_menu(menu_items,8,20);
            delete_menu(menu_items,9);
            if (selected_item<0)
                wprintw(messagebar,"You haven't selected any item.");
            else
                wprintw(messagebar,
                  "You have selected menu item %d.",selected_item+1);
            touchwin(stdscr);
            refresh();
        }
    } while (key!=ESCAPE);
    
    delwin(menubar);
    delwin(messagebar);
    endwin();
    return 0;
}

Se copiar o c�digo para um ficheiro chamado example.c e remover todas as minhas explica��es, pode compilar o c�digo com

gcc -Wall example.c -o example -lcurses

e teste o programa. Pode tamb�m fazer download do c�digo abaixo na sec��o das refer�ncias.

Conclus�o

Falei acerca das bases das ncurses que s�o suficientes para criar uma boa interface para o seu programa. Contudo, as capacidades da biblioteca n�o est�o limitadas ao que aqui expliquei. Descobrir� imensas outras coisas nas p�ginas man, que tantas vezes lhe pedi para ler e, compreender� que a informa��o apresentada aqui � s� uma introdu��o.

Refer�ncias