<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2//EN">
<HTML>
  <HEAD>
    <!-- this stylesheet will later on be added by lfparser automatically: -->
<STYLE type="text/css">
<!--
  pre { font-familiy:monospace,Courier }
  p.code { width:80%; alignment:center; background-color:#aedbe8; border-style:no ne; border-width:medium; border-color:#aedbe8; padding:0.1cm ; text-align:left }
-->
</STYLE>

  </HEAD>

  <BODY>
    <H1>Introduzione a Ncurses</H1>

    <H4>ArticleCategory: [Choose a category, translators: do not
    translate this, see list below for available categories]</H4>
    Software Development 

    <H4>AuthorImage:[Here we need a little image from you]</H4>
    <IMG src="../../common/images/RehaGerceker.jpg" width="178" height="243" alt=
    "[RehaGerceker]"> 

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

    <P>original in tr <A href="mailto:gerceker@itu.edu.tr">Reha K.
    Ger&ccedil;eker</A></P>

    <P>tr to en <A href="mailto:gerceker@itu.edu.tr">Reha K.
    Ger&ccedil;eker</A></P>

	<p>en to it <a href="mailto:alex@neko.it">Alessandro Pellizzari</a></p>

    <H4>AboutTheAuthor:[A small biography about the author]</H4>

	<p>Reha � uno studente di ingegneria informatica a Istanbul, in Turchia.
	Ama la libert� che Linux d� come piattaforma di sviluppo software.
	Passa la maggior parte del suo tempo davanti al computer, scrivendo
	programmi. Vorrebbe diventare un programmatore intelligente, un giorno.</p>

    <H4>Abstract:[Here you write a little summary]</H4>
	Ncurses � una libreria che fornisce funzioni di mappatura dei
	tasti funzione, di disegno dello schermo e di gestione di finestre
	multiple non sovrapposte su testimali a caratteri.
	
    <H4>ArticleIllustration:[One image that will end up at the top of
    the article]</H4>
    <IMG src="../../common/images/article233/ncurses.gif" width="153" height="160" alt="[ncurses]"> 

    <H4>ArticleBody:[The main part of the article]</H4>

    <H2>Cos'� ncurses?</H2>

	<p>Volete che il vostro programma abbia un'interfaccia in modo
	testo colorata? Ncurses � la libreria che permette di avere finestre
	sui terminali a caratteri.
	Le cose che consente di fare sono:</P>

    <UL>
      <LI>Usare l'intero schermo come si preferisce.</LI>

      <LI>Creare e gestire finestre.</LI>

      <LI>Usare 8 colori diversi.</LI>

      <LI>Aggiungere il supporto per il mouse ai programmi.</LI>

      <LI>Usare i tasti funzione della tastiera.</LI>
    </UL>
    <BR>
    <BR>
     

	<p>� possibile usare ncurses su qualsiasi sistema UNIX conforme allo
	standard ANSI/POSIX. Oltre a questo, la libreria � in grado di
	conoscere le capacit� del terminale e di adeguarsi di conseguenza,
	fornendo un'interfaccia indipendente dal terminale. Per questo ci si pu�
	affidare a ncurses per progetti che dovrenno funzionare su diverse
	piattaforme e diversi terminali.</p>

	<p>Midnight Commander � uno degli esempi scritti con ncurses. Anche
	l'interfaccia usata per la configurazione del kernel sulla console
	� scritta con ncurses. Potete vedere degli snapshot sotto.</p>
    <IMG src="../../common/images/article233/mc.jpg" width="526" height="423" alt=
    "[Midnight Commander]"><BR>
    <BR>
    <IMG src="../../common/images/article233/menuconfig.jpg" width="526" height="423" alt=
    "[kernel config]"> 

    <H2>Dove si scarica?</H2>

	<p>Ncurses viene sviluppata sotto GNU/Linux. Per scaricare l'ultima
	versione, avere informazioni dettagliate e trovare altri riferimenti,
	visitate <a
href="http://www.gnu.org/software/ncurses/">www.gnu.org/software/ncurses/</a>.</P>

    <H2>Le basi</H2>

	<p>Per usare la libreria dovete includere curses.h nel vostro codice
	sorgente e assicurarvi di fare un link alla libreria curses in compilazione.
	Per farlo dovete passare il parametro -lcurses a gcc.</P>

	<p>Lavorando con ncurses � necessatio conoscere una struttura dati
	fondamentale. Si tratta della struttura WINDOW e, come si capisce
	facilmente dal nome, viene usata per rappresentare le finestre
	che create. Praticamente tutte le funzioni della libreria richiedono
	un puntatore a WINDOW tra i parametri.</p>

	<p>I componenti pi� usati di ncurses sono le finestre. Anche se non
	create le vostre finestre, lo schermo � considerato una finestra.
	Cos� come il descrittore di FILE stdout della libreria di I/O standard
	rappresenta lo schermo (quando non ci sono redirezioni), ncurses ha un
	puntatore a WINDOW stdscr che copre lo stesso ruolo. Oltre a stdscr
	nelal libreria viene definito un altro puntatore a WINDOW chiamato
	curscr.Come stdscr rappresenta lo schermo, curscr rappresenta
	lo schermo attuale alla libreria. Potreste chiedere "Quale � la differenza?"
	Continuate a leggere.</p>

	<p>Per usare le funzioni di ncurses nei vostri programmi dovrete
	richiamare la funzione initscr. Questa funzione alloca memoria
	per le variabili come stdscr, curscr e prepara la libreria
	all'uso. In altre parole tutte le funzioni di ncurses devono
	essere richiamate dopo initscr. Allo stesso modo dovrete richiamare
	endwin una volta terminato di usare ncurses. Questa funzione libera
	la memoria utilizzata da ncurses. Dopo aver usato endwin non potrete
	usare le funzioni di ncurses finch� non richiamerete initscr.</P>

	<p>Tra l'uso di initscr e quello di endwin assicuratevi di non mandare
	otput allo schermo con le funzioni della libreria di I/O standard.
	In caso contrario potreste ottenere un output su schermo confuso o
	corrotto. Quando ncurses � attiva usate le sue funzioni per mandare
	output verso lo schermo. Prima di chiamare initscr o dopo endwin
	potete fare quello che volete.</p>

    <H2>Ridisegno dello schermo: refresh</H2>

	<p>La struttura WINDOW non contiene solo l'altezza, la larghezza e la
	posizione della finestra, ma anche il contenuto della finestra.
	Quando scrivete su una finestra il suo contenuto cambia, ma questo non
	significa che il cambiamento appaia sullo schermo immediatamente.
	Per ottenere un ridisegno dello schermo dovete richiamare refresh o
	wrefresh</P>

	<p>Questa � la differenza tra stdscr e curscr. Mentre curscr mantiene
	il contenuto dello schermo corrente, stdscr potrebbe contenere
	informazioni diverse dopo le chiamate alle funzioni di output di
	ncurses. Se volete trasferire su curscr i cambiamenti che avete
	fatto a stdscr dovete richiamare refresh. In altre parole, refresh �
	l'unica funzione che interagisce con curscr. � raccomandato di non
	trafficare con curscr e di lasciare che sia la funzione refresh ad
	aggiornarne il contenuto.</p>
	
	<p>refresh ha un meccanismo per aggiornare lo schermo il pi�
	velocemente possibile. Quando la funzione viene chiamata cambia solo
	le linee modificate della finestra. Questo permette di risparmiare
	tempo CPU perch� evita di ristampare le stesse informazioni che sono
	gi� sullo schermo. Questo meccanismo � la ragione per cui le funzioni
	ncurses e quelle standard di I/O possono produrre pessimi risultati
	se usate insieme; quando le funzioni ncurses vengono chiamate, esse
	impostano un flag che informa refresh che la linea � cambiata, mentre
	questo non accade quando si chiama una funzione di I/O standard.</p>
	
	<p>refresh e wrefresh fanno praticamente la stessa cosa. wrefresh
	prende come parametro un puntatore a WINDOW e aggiorna il contenuto
	di quella sola finestra. refresh() � equivalente a wrefresh(stdscr).
	Come dir� pi� avanti gran parte delle funzioni di ncurses hanno delle
	macro che applicano le stesse funzioni a stdscr.</p>
	
	<H2>Creare nuove finestre</H2>

	<p>Parliamo ora di subwin e newwin, le funzioni che permettono di
	creare nuove finestre. Entrambe queste funzioni prendono come parametri
	l'altezza, la larghezza e le coordinate dell'angolo in alto a sinistra
	della nuova finestra. Ritornano un puntatore a WINDOW che rappresenta
	la nuova finestra. Potete usare questo nuovo puntatore con wrefresh
	e altre funzioni di cui parler� pi� avanti.</p>

	<p>"Se fanno la stessa cosa, perch� duplicare le funzioni?" potreste
	chiedere. Avete ragione, sono un po' diverse. subwin crea la nuova
	finestra come sottofinestra di un'altra. Una finestra creata in questo
	modo eredita alcune propriet� della finestra genitore. Queste
	propriet� potrebbero essere cambiate in seguito senza influire sulla
	finestra genitore.</p>
	
	<p>A parte questo c'� una cosa che lega le finestre genitore e figlie.
	L'array di caratteri che definisce il contenuto di una finestra viene
	condiviso tra la finestra genitore e la figlia. In altre parole i 
	caratteri nell'intersezione tra le due finestre potrebbero essere
	cambiati da una qualsiasi delle due. Se il genitore scrive su tale
	rettangolo allora anche il contenuto della figlia cambia. � vero
	anche il contrario.</p> 
	
	<p>A differenza di subwin, newwin crea una finestra nuova di zecca.
	Questa finestra, a meno che non abbia figlie, non condivide il suo
	array di caratteri con nessun'altra. Il vantaggio di usare subwin
	� che la condivisione dell'array riduce l'uso di memoria. D'altra
	parte, quando le finestre iniziano a sovrapporsi a vicenda, l'uso
	di newwin ha i suoi vantaggi.</p>
	
	<p>Potete creare le vostre sotto-finestre a qualsiasi profondit�.
	Ogni sotto-finestra pu� avere proprie sotto-finestre, ma in
	questo caso ricordate che lo stesso array verr� condiviso da pi�
	di due finestre.</p>
	
	<p>Quando avete finito con una finestra che avete creato potete
	cancellarla con la funziona delwin. Vi suggerisco di consultare la
	manpage per la lista di parametri di queste funzioni.</p>


    <H2>Scrivere sulle Finestre, Leggere dalle Finestre</H2>

	<p>Abbiamo parlato di stdscr, curscr, dell'aggiornamento dello schermo
	e della creazione di nuove finestre. Ma allora come scriviamo su
	una finestra? O come leggiamo dati da una finestra?</p>

	<p>Le funzioni usate a questo scopo richiamano le loro controparti
	della libreria standard di I/O. Tra di esse ci sono printw al posto
	di printf, scanw al posto di scanf, addch al posto di putc o putchar,
	getch al posto di getc o getchar. Vengono usate come al solito, solo
	i nomi sono diversi. Allo stesso modo, addstr pu� essere usata per
	scrivere una stringa sulla finestra e getstr per leggere una stringa
	da una finestra. Tutte queste funzioni con una 'w' aggiunta all'inizio
	del nome e un puntatore a WINDOW come primo parametro eseguono il
	loro lavoro su una finestra diversa da stdscr. Per esempio printw(...)
	e wprintw(stdscr, ...) sono equivalenti, come refresh() e wrefresh(stdscr).</p>

	<p>Sarebbe una lunga storia addentrarci nei dettagli di queste funzioni.
	Le pagine man sono il posto migliore dove imparare le loro descrizioni,
	i prototipi, i valori di ritorno e altre informazioni. Vi suggerisco di
	controllare le pagine man per ogni funzione che usate. Riportano
	informazioni dettagliate e preziose. L'ultima sezione di questo articolo,
	dove presento un programma di esempio, pu� servire anche come tutorial
	sull'uso delle funzioni.</p>

    <H2>Cursori Fisici e Logici</H2>

	<p>� necessario spiegare i cursori logici e fisici dopo aver parlato
	di leggere e scrivere sulle finestre. Quello che si intende per
	cursore fisico � il classico cursore lampeggiante sullo schermo e
	ce n'� solo uno. D'altra parte il cursore logico appartiene alle
	finestre ncurses e ogni finestra ne ha uno. Perci� ci possono essere pi�
	cursori logici.</p>

	<p>Il cursore logico � il quadratino della finestra dove il processo
	di scrittura o lettura avr� inizio. Per questo, essere in grado di
	muovere il cursore logico significa poter scrivere in ogni posizione
	dello schermo o della finestra in qualsiasi momento. Questo � il
	vantaggio di ncurses rispetto alla libreria I/O standard.</p>

	<p>La funzione che sposta il cursore logico � move o, come potete
	facilmente intuire, wmove. move � una macro per wmove, scritta
	per stdscr.</p>

	<p>Un altro punto riguarda la coordinazione tra cursore fisico e
	logico. La posizione finale del cursore fisico sar� determinata dal
	flag _leave nella struttura WINDOW. Se _leave � impostato, il cursore
	logico viene spostato nella posizione del cursore fisico (nel punto
	in cui viene scritto l'ultimo carattere) dopo la fine della scrittura.
	Se _leave non � settato il cursore fisico viene riportato alla posizione
	del cursore logico (dove viene scritto il primo carattere) dopo la
	scrittura. Il flag _leave � controllato dalla funzione leaveok.</p>
	
	<p>La funzione che muove il cursore fisico � mvcur. A differenza delle
	altre, mvcur ha un effetto immediato e non attende il ridisegno. Se
	olete rendere invisibile il cursore fisico, potete usare la funzione
	curs_set. Controllate la pagina man per i dettagli.</p>
	
	<p>Ci sono anche macro che raggruppano le funzioni di movimento e
	scrittura descritte sopra in un unico comando. Vengono descritte
	bene nelle stesse pagine man riguardanti addch, addstr, printw, getch,
	getstr, scanw, ecc.</p>	

    <H2>Cancellare le Finestre</H2>

	<p>Abbiamo visto come scrivere sulle finestre. Ma come cancelliamo
	finestre, linee o caratteri></p>

	<p>Cancellare in ncurses significa riempire il carattere, la linea
	o il contenuto della finestra con spazi bianchi. Le funzioni che
	ho descritto sotto riempiono  i caratteri necessari con spazi bianchi
	e quindi cancellano lo schermo.</p>
	
	<p>Prima di tutto parliamo delle funzioni che cancellano un carattere
	o una linea. Le funzioni delch e wdelch cancellano il carattere che
	si trova sotto il cursore logico della finestra e spostano i caratteri
	che lo seguono sulla riga verso sinistra. deleteln e wdeleteln
	cancellano la riga su cui si trova il cursore logico e spostano in
	alto le linee seguenti.</p>

	<p>Le funzioni clrtoeol e wclrtoeol cancellano tutti i caratteri
	sulla stessa linea alla destra del cursore logico. clrtobot e wclrtobot
	prima richiamano wclrtoeol per cancellare tutti i caratteri a destra
	del cursore logico, e quindi cancellano tutte le linee seguenti.</p>
	
	<p>Oltre a queste esistono funzioni che cancellano l'intero schermo
	o la finestra. Ci sono due modi per cancellare tutto lo schermo. Il
	primo � di riempire tutti i caratteri con spazi bianchi e poi chiamare
	refresh, mentre il secondo � di usare il codice di controllo dello
	specifico terminale. Il primo metodo � pi� lento del secondo perch�
	richiede la riscrittura di tutti i caratteri sullo schermo mentre il
	secondo cancella tutto lo schermo immediatamente.</p>
	
	<p>erase e werase riempiono l'array di caratteri di una finestro
	con spazi bianchi. Al prossimo refresh la finestra verr� cancellata.
	Se per� la finestra occupa tutto lo schermo non � una buona idea
	usare queste funzioni, in quanto usano il primo metodo descritto
	sopra. Quando la finestra da cancellare ha le dimensioni dello schermo
	� meglio usare le funzioni descritte sotto.</p>
	
	<p>Prima di addentrarci in altre funzioni � meglio menzionare il
	flag _clear. Esso � contenuto nella struttura WINDOW e se � settato
	chiede a refresh di mandare il codice di controllo al terminale
	quando viene richiamato. Al momento della chiamata refresh controlla
	se la finestra ha le dimensioni dello schermo (controllando il flag
	_FULLWIN) e in questo caso cancella lo schermo con l'apposito codice
	di controllo. Quindi scrive solo caratteri che non siano spazi bianchi
	sullo schermo. Questo rende la cancellazione dello schermo pi� veloce.
	Il motivo per cui il codice di controllo viene usato solo per finestre
	che riempiono tutto lo schermo � che esso cancella tutto lo schermo e
	non solo la finestra. Il flag _clear viene controllato dalla funzione
	clearok.</p>

	<p>Le funzioni clear e wclear vengono usate per cancellare finestre
	delle dimensioni dello schermo. In effetti queste funzioni sono
	equivalenti a chiamare werase e clearok. Prima di tutto riempiono
	l'array di caratteri della finestra con spazi bianchi. Quindi, impostando
	il flag _clear, cancellano lo schermo con il codice del terminale se
	la finestra � a tutto schermo oppure ridisegnano tutti i caratteri
	della finestra riempiendoli con spazi bianchi.</p>

	<p>In definitiva, se sapete che la finestra � a tutto schermo usate
	clear o wclear. D'altra parte non c'� differenza tra l'uso di wclear
	o werase quando la finestra non � a tutto schermo.</p>

    <H2>Usare i Colori</H2>

	<p>I colori che vedete sullo schermo dovrebbero essere considerati
	come coppia di colori. Questo perch� ogni carattere ha un colore
	di sfondo e uno di primo piano. Scrivere a colori con ncurses
	significa creare le proprie coppie di colori e usare queste coppie
	per scrivere su una finestra.</p>

	<p>Proprio come initscr deve essere chiamata per inizializzare
	ncurses, start_color deve essere chiamata per inizializzare i
	colori. La funzione di cui avrete bisogno per creare le vostre coppie
	di colori � init_pair. Quando create una coppia con init_pair essa
	viene associata al numero che passate come primo parametro della
	funzione. A questo punto, quando vorrete usare questa coppia, vi
	riferirete ad essa chiamando COLOR_PAIR con il numero associato.</p>

	<p>Oltre a creare le coppie di colori avrete bisogno delle funzioni
	necessarie a scrivere con diverse coppie. Questo viene fatto tramite
	le funzioni attron e wattron. Queste funzioni, fino alla chiamata di
	attroff o wattroff, fanno in modo che tutto quello che viene scritto
	sulla finestra corrispondente sia della coppia di colori che avete
	selezionato.</p>
	
	<p>Ci sono anche le funzioni bkgd e wbkgd che cambiano la coppia di
	solori associata all'intera finestra. Quando vengono richiamate
	cambiano il colore di sfondo e di primo piano di tutti i caratteri
	della finestra. In questo modo, al prossimo refresh ogni carattere della
	finestra verr� riscritto con la nuova coppia di colori.</p>

	<p>Nelle pagine man troverete i colori disponibili e i dettagli
	delle funzioni summenzionate.</p>

    <H2>Bordi attorno alle Finestre</H2>

	<p>Potete creare dei bordi attorno alle vostre finestre per dare
	un aspetto migliore al vostro programma. C'� una macro nella libreria
	chiamata box che lo fa per voi. A differenze di altre funzioni, non
	esiste una wbox; box accetta come argomento un puntatore a WINDOW.</p>

	<p>Troverete i dettagli di box nella sua pagina man. C'� un'altra cosa
	che va menzionata. Mettere una finestra dentro un bordo significa
	semplicemente scrivere i caratteri necessari nell'array di caratteri
	della finestra che corrispondono ai suoi bordi. Se in futuro scriverete
	su tali caratteri il bordo ne sar� corrotto. Per prevenire questa
	situazione potete creare una finestra interna a quella originaria con
	subwin, applicate la box alla finestra originaria e usate la finestra
	interna per scrivere quando serve.</p>

    <H2>Tasti Funzione</H2>

	<p>Per poter usare i tasti funzione � necessario impostare il flag
	_use_keypad nella finestra da cui state cercando di leggere l'input.
	La funzione che imposta questo valore � keypad. Quando lo impostate
	potete ricevere input dalla tastiera normalmente con le funzioni 
	di input.</p>

	<p>In questo caso, se usate getch per ricevere i dati per esempio,
	dovete fare attenzione a salvare tali dati in un int piuttosto che
	in un char. Questo perch� i valori numerici dei tasti funzione sono
	maggiori dei valori che una variabile di tipo char pu� contenere.
	Non avete bisogno di conoscere tali valori ma potete usare i nomi
	per loro definiti nella libreria. Tali valori sono elencati nella
	pagina man di getch.</p>


    <H2>Un Esempio</H2>

	<p>Analizzeremo ora un picolo programmino. In questo programma i menu
	vengono creati con ncurses e viene mostrato come selezionarne una voce.
	Un aspetto interessante di questo programma � l'uso delle finestre
	di ncurses per creare un effetto menu. Potete vedere uno snapshot qui sotto:</p>

    <IMG src="../../common/images/article233/example.jpg" width="588" height="399" alt=
    "[example program]"> 

	<p>Il programma inizia con i soliti file di include. Quindi definiamo
	le costanti per i valori ASCII dei tasti enter ed esc.</p>

<PRE>
#include &lt;curses.h&gt;
#include &lt;stdlib.h&gt;

#define ENTER 10
#define ESCAPE 27
</PRE>

	<p>La funzione qui sotto viene richiamata per prima alla partenza
	del programma. Chiama subito initscr per inizializzare ncurses e
	subito dopo chiama start_color per rendere possibile l'uso dei colori.
	Le coppier di colori usate durante il programma verranno definite dopo.
	La funzione curs_set(0) rende invisibile il cursore fisico. noecho
	fa in modo che quello che si scrive da tastiera non venga riportato
	a schermo. Potete usarla anche per controllare cosa viene scritto e
	stampare a schermo solo le parti che volete visualizzare. La funzione
	echo dovr� essere richiamata quando necessario per disattivare questo
	effetto. La funzione qui sotto alla fine chiama keypad per abilitare i
	tasti funzione nell'input da stdscr. Questo si rende necessario in quanto
	useremo F1, F2 e i tasti cursore nel programma che segue.</p>

<PRE>
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);
}
</PRE>

	<p>La funzione seguente crea una barra di menu che appare in alto
	sullo schermo. Controllando la funzione main sotto potete vedere che
	la barra di menu che appare come una singola linea in alto sullo schermo
	non � altro che una sottofinestra di una sola linea di stdscr. La funzione
	qui sotto riceve un puntatore a quella finestra come parametro, quindi
	prima ne cambia il colore di sfondo e poi scrive le voci di menu. Usiamo
	wstdadd per scrivere le voci di menu, ma potrebbe essere stata usata
	un'altra funzione. Fate attenzione alle chiamate a wattron, usate per
	scrivere con una diversa coppia di colori (numero 3) al posto della
	coppia di default (numero 2). Ricordate che la coppia numero 2 � stata
	impostata sulla prima linea da wbkgd. wattroff viene chiamata quando
	vogliamo tornare alla coppia di colori di default.</p>

<PRE>
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));
}
</PRE>

	<p>La prossima funzione disegna i menu quando si preme F1 o F2. Per
	creare l'effetto dei menu viene creata una nuova finestra con lo stesso
	colore bianco della barra di menu, sopra la finestra blu che definisce
	lo sfondo. Non vogliamo che questa nuova finestra sovrascriva caratteri
	gi� scritti sullo sfondo. Essi dovrebbero tornare visibili dopo che il
	menu verr� chiuso. Per questo motivo la finestra di menu non pu� essere
	creata come sottofinestra di stdscr. Come potete vedere sotto la finestra
	items[0] viene creata con la funzione newwin e le altre 8 finestre per
	le sotto-voci vengono create come sottofinestre di items[0]. Qui items[0]
	viene usata per disegnare un bordo attorno al menu e le altre finestre
	di sotto-voci vengono usate per mostrare la sotto-voce selezionata nel menu
	e per non sovrascrivere i caratteri del bordo del menu attorno a loro. Per
	dare l'effetto della selezione di una sotto-voce � sufficiente cambiare
	il suo colore di sfondo rispetto alle altre.Questo viene fatto nella
	terzultima riga; lo sfondo della prima sotto-voce viene reso diverso dalle
	altre, in modo che quando il menu si apre, la prima sia selezionata.</p>

<PRE>
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&lt;9;i++)
        wprintw(items[i],"Item%d",i);
    wbkgd(items[1],COLOR_PAIR(1));
    wrefresh(items[0]);
    return items;
}
</PRE>

	<p>La prossima funzione si limita a cancellare la finestra di menu
	creata dalla funzione appena vista. Prima di tutto cancella le
	finestre delle sotto-voci con delwin, quindi libera la memoria allocata
	per i puntatori alle sotto-voci.</p>

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

	<p>La funzione scroll_menu ci permette di spostarci tra e dentro i menu.
	Legge i tasti premuti sulla tastiera con getch. Se vengono premuti i tasti
	cursore-su o cursore-gi� viene selezionata la voce precedente o seguente.
	Questo viene fatto cambiando il colore di sfondo della sotto-voce selezionata.
	Se vengono premuti i tasti cursore-sinistra o cursore-destra il menu
	aperto viene chiuso e viene aperto l'altro. Se viene premuto il tasto enter
	la sotto-voce selezionata viene ritornata. Se viene premuto ESC vengono
	chiusi i menu senza selezionare nulla. La funzione ignora altri tipi di
	input. In questa funzione getch � in grado di leggere i tasti funzione dalla
	tastiera. Ricordo che questo � possibile perch� la prima funziona,
	init_curses, richiamava keypad(stdscr, TRUE) e il valore di ritorno di
	getch viene memorizzato in un int invece che in un char, visto che il
	valore dei tasti funzione � maggiore di quello che pu� essere contenuto in
	un char.</p>

<PRE>
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;
        }
    }
}
</PRE>

	<p>Per finire, c'� la funzione main. Essa usa tutte le funzioni scritte
	in precedenza e descritte sopra per far funzionare il programma.
	Legge anche i caratteri con getch e se viene premuto F1 o F2 disegna
	il menu corrispondente con draw_menu. Dopodiche chiama scroll_menu e
	lascia la possibilit� all'utente di selezionare dal menu. Dopo il
	ritorno da scroll_menu cancella le finestre dei menu e scrive sulla
	barra messaggi la voce selezionata.</p>

	<p>Dovrei menzionare la funzione touchwin. Se refresh fosse stato
	chiamato senza touchwin dopo che i menu sono stati chiusi, l'ultimo
	menu aperto sarebbe rimasti sullo schermo. Questo perch� le funzioni
	per i menu non modificano stdscr e alla chiamata di refresh, esso non
	ridisegnerebbe stdscr poich� assumerebbe che la finestra non fosse sia
	cambiata. touchwin imposta tutti i flag della struttura WINDOW per
	informare refresh del cambiamento della finestra, cosicche al prossimo
	refresh la finestra venga completamente ridisegnata anche se il suo
	contenuto non � stato alterato. Le informazioni scritte su stdscr rimangono
	dopo che i menu sono stati chiusi poich� i menu non scrivono su stdscr ma
	piuttosto creano delle loro finestre.</p>

<PRE>
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("Premi F1 o F2 per aprire i menu. ");
    printw("ESC esce.");
    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&lt;0)
                wprintw(messagebar,"Non hai selezionato alcuna voce.");
            else
                wprintw(messagebar,
                  "Hai selezionato la voce %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&lt;0)
                wprintw(messagebar,"Non hai selezionato alcuna voce.");
            else
                wprintw(messagebar,
                  "Hai selezionato la voce %d.",selected_item+1);
            touchwin(stdscr);
            refresh();
        }
    } while (key!=ESCAPE);
    
    delwin(menubar);
    delwin(messagebar);
    endwin();
    return 0;
}
</PRE>

	<p>Se copiate il codice in un file chiamato example.c e togliete
	le spiegazioni, potete compilare il codice con</p>
	
<PRE>
gcc -Wall example.c -o example -lcurses
</PRE>

	<p>e provarlo. Potete anche scaricare il codice seguendo i link nel
	capitolo dei riferimenti.</p>
	
    <H2>Conclusioni</H2>

	<p>Ho parlato dei fondamenti di ncurses che possono essere sufficienti
	per creare una buona interfaccia per i vostri programmi. Le capacit�
	della libreria per� non sono limitate a quelle descritte qui.
	Scoprirete molte altre cose dalle pagine man che vi ho spesso chiesto di
	leggere e realizzerete che le informazioni che vi ho presentato qui
	sono solo una introduzione.</p>


    <H2>Riferimenti</H2>
<ul>
<li>Il programma di esempio: <a href="../../common/src/article233/example_c.txt">example.c</a>
<li>Il sito di ncurses:<a 
href="http://www.gnu.org/software/ncurses/">www.gnu.org/software/ncurses/</a>
</ul>
  </BODY>
</HTML>
    <!-- vim: set sw=2 ts=2 et tw=74: -->