// ui.cc - Classe User Interface // robert - Programme du robot APBteam // Copyright (C) 2005 Olivier Gaillard /// @file ui.cc Interface ncurses permettant de piloter adjust #include #include #include #include #include #include #include #include #include "ui.hh" #include "mainui.hh" /// Nombre d'items du menu #define NBITEMS 13 /// Items du menu principal char *itemsName[NBITEMS][2] = {{"Move color", "Permet d'ajuster les niveaux d'une couleur"}, {"Del color", "Enleve une couleur du reseau"}, {"Merge colors", "Groupe plusieurs couleurs ensembles"}, {"Object to display", "Selectionne l'object à afficher"}, {"Change object color", "Selectionne l'index de la couleur d'un objet"}, {"Change color format", "Selectionne l'index le mode de couleur"}, {"Show objets found", "Affiche les balles et poteaux trouvés"}, {"Training", "Entraine le reseau de neurones"}, {"New network", "Regenere de nouveaux poids pour le reseau"}, {"Cancel changes", "Recharge le fichier de oconfig"}, {"Save changes", "Sauvegarde les changements dans le fichier"}, {"Quit", "Quitte le programme"}, {NULL, NULL}}; /// Constructor UI::UI(const char *filename) { oconfig = new OConfig; // TODO verifier que le terminal est assez grand sinon écran noir // Suppression de l'ancien fifo system("rm -f uicmds"); // Creation du fifo if (mknod("uicmds", S_IFIFO | 0666, 0) != 0) { std::cerr << "UI::UI : Error during fifo creation\n"; return; } // Ouverture du fifo fifo = open("uicmds", O_RDWR); if (fifo < 0) { std::cerr << "UI::UI : Error during fifo opening\n"; return; } // On choppe le pid du prog adjust situé dans le fichier adjust.PID FILE *file; file = fopen("adjust.PID", "r"); if (!file) { std::cerr << "UI:UI : PID file not found" << std::endl; exit(1); } char buf[10]; fgets(buf, 10, file); pid = atol(buf); fclose(file); curImage = 0; parseFileList(); oconfig->loadNNFile(); savedNNColorNumber = oconfig->nnNbColor; // Ecriture du PID dans un fichier long uiPid = getpid(); file = fopen("ui.PID", "w+"); if (!file) { std::cerr << "UI::UI : Error during file opening" << std::endl; return; } fprintf(file, "%li\n", uiPid); fclose(file); // Ouverture du fifo kill(pid, SIGUSR2); // Init ncurses initscr(); start_color(); keypad(stdscr, TRUE); cbreak(); noecho(); curs_set(0); // Init couleurs init_pair(1, COLOR_BLUE, COLOR_BLACK); init_pair(2, COLOR_RED, COLOR_BLACK); init_pair(3, COLOR_GREEN, COLOR_BLACK); init_pair(4, COLOR_CYAN, COLOR_BLACK); if (filename) { sprintf(buf, "n %s\n", filename); sendSignal(buf); } } /// Destructeur UI::~UI() { // Libere memoire unpost_menu(mainMenu); free_menu(mainMenu); for(int i = 0; i < NBITEMS; ++i) free_item(item[i]); endwin(); close(fifo); // Ferme adjust SIGQUIT kill(pid, SIGQUIT); system("rm -f adjust.PID ui.PID"); if (fileList) delete fileList; } /// Synchronisation des poids locaux avec ceux du programme adjust void UI::updateNodes () { char buf[10]; // On parcours toutes les couleurs for (int i=0; i < oconfig->nnNbColor*3; i++) { // On lis le fifo et on le copie dans le tableau node read(fifo, buf, 10); oconfig->node[i] = atoi(buf); } } /// Cree la liste d'images a ouvrir void UI::parseFileList () { // On enleve l'ancienne liste et on en cree une nouvelle char buf[100]; sprintf(buf, "rm -Rf imagelist ; ls %s | grep -e .jpg -e .JPG -e .png -e .PNG > imagelist", oconfig->imgPath); system(buf); FILE *file; file = fopen("imagelist", "r"); if (!file) { std::cerr << "UI:ParseFileList : file not found" << std::endl; std::cerr << "UI:ParseFileList : use 'ls pictures_dir > imagelist" << std::endl; exit(1); } lengthFileList = 0; while(fgets(buf, 30, file)) lengthFileList++; rewind(file); fileList = new char*[lengthFileList]; int fileCount = 0; char *p; while (fgets(buf, 30, file)) { fileList[fileCount] = new char[30]; p = strtok(buf, "\t\n"); if (p) { strcpy(fileList[fileCount], p); fileCount++; } else lengthFileList--; } } /// Envoie une donnee au prog adjust /// @param *cmd commande a envoyer void UI::sendSignal (const char *cmd) { // Ecrit dans le fifo write(fifo, cmd, 50); // Envoie un signal USR1 au prog adjust kill(pid, SIGUSR1); // Attente de la reponse de adjust SetReady(0); while (!GetReady()) { usleep(1); } } /// Affiche un msg dans la barre d'etat /// @param *str message a afficher dans la barre d'etat void UI::printStatus (const char *str) { // Creation de la fenetre WINDOW *statusWindow = newwin(3, 60, 20, 5); wattron(statusWindow, A_BOLD | COLOR_PAIR(4)); // Affichage du texte wprintw(statusWindow, "%s\n", str); wrefresh(statusWindow); // Liberation de la memoire delwin(statusWindow); } /// menu de selection de couleur /// @param type choix du texte des items /// @param current item selectionne au depart int UI::chooseColor (const int type, const int current) { // Choix de la couleur char **colorName; // Nombre d'item a afficher if (type == NB_COULEUR) oconfig->nnNbColor = 15; // Creation des items ITEM **colorItem = new ITEM*[oconfig->nnNbColor+2]; colorName = new char*[oconfig->nnNbColor+1]; for (int i=0; innNbColor; i++) { colorName[i] = new char[20]; if (type == NUM_COULEUR) sprintf(colorName[i], "Couleur %i", i); else if (type == NB_COULEUR) sprintf(colorName[i], "%i", i); colorItem[i] = new_item(colorName[i] , NULL); } colorName[oconfig->nnNbColor] = new char[20]; sprintf(colorName[oconfig->nnNbColor], "Annuler"); colorItem[oconfig->nnNbColor] = new_item(colorName[oconfig->nnNbColor] , NULL); colorItem[oconfig->nnNbColor+1] = NULL; // Creation de la fenetre WINDOW *colorWindow = newwin(16, 15, 3, 35); keypad(colorWindow, TRUE); // Creation du menu MENU *colormenu = new_menu(colorItem); set_menu_win(colormenu, colorWindow); set_menu_mark(colormenu, " -> "); post_menu(colormenu); wrefresh(colorWindow); // Affichage d'info printStatus("Utiliser ENTREE pour selectionner la couleur\n"); char buf[50]; int car; int col=0; if (type == NUM_COULEUR) { // Cree une image de la couleur selectionnee sprintf(buf, "s %i\n", current); sendSignal(buf); } set_current_item(colormenu, colorItem[current]); col = current; wrefresh(colorWindow); while((car = wgetch(colorWindow)) != 10) { switch (car) { case KEY_DOWN: // Touche BAS // Deplacement dans le menu if (col < (int)oconfig->nnNbColor) { menu_driver(colormenu, REQ_DOWN_ITEM); col++; } break; case KEY_UP: // Touche HAUT // Deplacement dans le menu if (col > 0) { menu_driver(colormenu, REQ_UP_ITEM); col--; } break; } if ( (type == NUM_COULEUR) && (col < oconfig->nnNbColor)) { // Cree une image de la couleur selectionnee sprintf(buf, "s %i\n", col); sendSignal(buf); } wrefresh(colorWindow); } // Cas d'annulation if (col == oconfig->nnNbColor) { col = -1; // On reaffiche l'image normale sendSignal("r -1\n"); } // Liberation memoire for(int i=0; innNbColor; i++) free_item(colorItem[i]); free_menu(colormenu); delwin(colorWindow); colorWindow = newwin(16, 15, 3, 35); wrefresh(colorWindow); delwin(colorWindow); delete [] colorName; // Retourne la valeur choisie par l'utilisateur return col; } /// menu de selection d'objet int UI::chooseObject (const int current) { const int nbObjects = 5; // Creation des items const char *objectName[15] = {"greenSkittle", "redSkittle", "border", "base", "gap", "undefined", "annuler"}; ITEM **objectItem = new ITEM*[nbObjects+2]; for (int i = 0; i < nbObjects+1; ++i) objectItem[i] = new_item(objectName[i], NULL); objectItem[nbObjects+1] = NULL; // Creation de la fenetre WINDOW *objectWindow = newwin(7, 18, 10, 45); keypad(objectWindow, TRUE); // Creation du menu MENU *objectmenu = new_menu(objectItem); set_menu_win(objectmenu, objectWindow); set_menu_mark(objectmenu, " -> "); post_menu(objectmenu); wrefresh(objectWindow); // Affichage d'info printStatus("Utiliser ENTREE pour selectionner l'objet\n"); int car; int obj=0; set_current_item(objectmenu, objectItem[current]); obj = current; wrefresh(objectWindow); while((car = wgetch(objectWindow)) != 10) { switch (car) { case KEY_DOWN: // Touche BAS // Deplacement dans le menu if (obj < nbObjects) { menu_driver(objectmenu, REQ_DOWN_ITEM); obj++; } break; case KEY_UP: // Touche HAUT // Deplacement dans le menu if (obj > 0) { menu_driver(objectmenu, REQ_UP_ITEM); obj--; } break; } // if ( (type == NUM_COULEUR) && (obj < oconfig->nnNbColor)) // { // // Cree une image de la couleur selectionnee // sprintf(buf, "s %i\n", obj); // sendSignal(buf); // } wrefresh(objectWindow); } // Cas d'annulation if (obj == nbObjects) obj = -1; // Liberation memoire for(int i=0; i "); post_menu(objectmenu); wrefresh(objectWindow); // Affichage d'info printStatus("Utiliser ENTREE pour selectionner le format de couleur\n"); int car; int obj=0; set_current_item(objectmenu, objectItem[current]); obj = current; wrefresh(objectWindow); while((car = wgetch(objectWindow)) != 10) { switch (car) { case KEY_DOWN: // Touche BAS // Deplacement dans le menu if (obj < nbObjects) { menu_driver(objectmenu, REQ_DOWN_ITEM); obj++; } break; case KEY_UP: // Touche HAUT // Deplacement dans le menu if (obj > 0) { menu_driver(objectmenu, REQ_UP_ITEM); obj--; } break; } // if ( (type == NUM_COULEUR) && (obj < oconfig->nnNbColor)) // { // // Cree une image de la couleur selectionnee // sprintf(buf, "s %i\n", obj); // sendSignal(buf); // } wrefresh(objectWindow); } // Cas d'annulation if (obj == nbObjects) obj = -1; // Liberation memoire for(int i=0; innNbColor+2]; mergeName = new char*[oconfig->nnNbColor+1]; for (int i=0; innNbColor; i++) { mergeName[i] = new char[20]; sprintf(mergeName[i], "Couleur %i (%i)", i, oconfig->index[i]); mergeItem[i] = new_item(mergeName[i] , NULL); } // Ajout du choix unmerge a la fin du menu mergeName[oconfig->nnNbColor] = new char[20]; strcpy(mergeName[oconfig->nnNbColor], "Unmerge all"); mergeItem[oconfig->nnNbColor] = new_item(mergeName[oconfig->nnNbColor], NULL); mergeItem[oconfig->nnNbColor+1] = NULL; // Creation de la fenetre WINDOW *mergeWindow = newwin(10, 20, 9, 35); keypad(mergeWindow, TRUE); // Creation du menu MENU *mergemenu = new_menu(mergeItem); set_menu_win(mergemenu, mergeWindow); set_menu_mark(mergemenu, " -> "); menu_opts_off(mergemenu, O_ONEVALUE); post_menu(mergemenu); wrefresh(mergeWindow); // Initialisation de variables int c; int end = 0; int col = 0; char buf[40]; char cmd[50]; char tmp[3]; int nbColorToMerge = 0; // Cree une image de la couleur selectionnee sendSignal("s 0\n"); // Affichage d'info printStatus("ESPACE pour choisir les valeurs, ENTREE pour valider\n"); // Boucle du menu de selection des couleurs int indexColor = -1; while(!end) { c = wgetch(mergeWindow); switch (c) { case ' ': // Touche ESPACE // Selection d'un element menu_driver(mergemenu, REQ_TOGGLE_ITEM); break; case KEY_DOWN: // Touche BAS // Deplacement dans le menu if (col < oconfig->nnNbColor) { menu_driver(mergemenu, REQ_DOWN_ITEM); col++; } break; case KEY_UP: // Touche HAUT // Deplacement dans le menu if (col > 0) { menu_driver(mergemenu, REQ_UP_ITEM); col--; } break; case 10: // Touche ENTREE // Validation des elements items = menu_items(mergemenu); // Si l'option unmerge est choisie if ( item_index(current_item(mergemenu)) == item_count(mergemenu)-1) { // On remet a zero la table d'index for (int i=0; innNbColor; i++) oconfig->index[i] = i; // Fin de la boucle end = 1; nbColorToMerge++; } else { // Parcours des items du menu for (int i=0; i< item_count(mergemenu)-1; i++) // Si il on ete valide on les ajoute a la string if (item_value(items[i]) == TRUE) { // Memorisation du premier index trouve pour // le copier dans les autres couleurs choisies if (indexColor == -1) indexColor = oconfig->index[i]; sprintf(tmp, " %i", i); strcat(buf, tmp); nbColorToMerge++; oconfig->index[i]= indexColor; } // Flag de fin de boucle end = 1; } break; } if (col != oconfig->nnNbColor) { // Cree une image de la couleur selectionnee sprintf(cmd, "s %i\n", col); sendSignal(cmd); } } if (nbColorToMerge) { // Cas ou unmerge a ete selectionne if (indexColor == -1) { // Envoie un signal sprintf(cmd, "m %i\n", -1); sendSignal(cmd); // Affichage d'info sprintf(cmd, "Les index des couleurs ont ete remises a zero"); printStatus(cmd); } else { // Finition de la chaine a envoye strcat(buf, "\n"); sprintf(cmd, "m %i", nbColorToMerge); strcat(cmd, buf); // Envoie du signal sendSignal(cmd); // Affichage d'info sprintf(cmd, "Les couleurs melangees sont %s", buf+1); printStatus(cmd); } } else printStatus("Pas de couleur selectionnee\n"); wrefresh(mergeWindow); // Liberation memoire for(int i=0; innNbColor; i++) free_item(mergeItem[i]); free_menu(mergemenu); delwin(mergeWindow); mergeWindow = newwin(10, 20, 9, 35); wrefresh(mergeWindow); delwin(mergeWindow); delete [] mergeName; } /// menu de suppression de couleur void UI::goDelColor() { // menu de sélection de couleur int numColor = chooseColor(NUM_COULEUR); // Annulation if (numColor < 0) return; // Envoie du signal char buf[50]; sprintf(buf, "d %i\n", numColor); sendSignal(buf); // On supprime la couleur en local unsigned char *pCur; pCur = &oconfig->node[numColor*3]; for(int i=numColor*3; innNbColor*3; i++) { *(pCur) = *(pCur+3); pCur++; } oconfig->nnNbColor--; // Affichage d'info sprintf(buf, "Couleur %i supprimee\n", numColor); printStatus(buf); } /// menu de selection du group a former void UI::goSelectGroup(const int type) { // menu de selection de couleur /* int tmp; if (type == BALL) tmp = chooseColor(NUM_COULEUR, oconfig->groupColor); else if (type == GOAL) tmp = chooseColor(NUM_COULEUR, oconfig->goalColor); if (tmp != -1) { if (type == BALL) { oconfig->groupColor = tmp; // Envoie d'un signal avec la valeur choisie char buf[50]; sprintf(buf, "g %i\n", tmp); sendSignal(buf); } else if (type == GOAL) { oconfig->goalColor = tmp; } } */ } /// menu de suppression de couleur void UI::goChangeColor () { unsigned char c[3]; int ligne=0; char cmd[50]; // menu de sélection de couleur int col = chooseColor(NUM_COULEUR); // Annulation if (col < 0) return; // Affectation des composantes actuelles for (int i=0; i<3; i++) c[i] = oconfig->node[col*3+i]; // Création de la fenetre WINDOW *colorWindow = newwin(4, 60, 12, 25); keypad(colorWindow, TRUE); // Initialisation de l'affichage wprintw(colorWindow, "Couleur %i:\n", col); wprintw(colorWindow, "<---------------------------------------------------->\n"); wprintw(colorWindow, "<---------------------------------------------------->\n"); wprintw(colorWindow, "<---------------------------------------------------->\n"); // Affichage du curseur sur les lignes // ainsi que des valeurs des composantes de la couleur wattron(colorWindow, A_BOLD | COLOR_PAIR(1)); mvwprintw(colorWindow, 1, 56, "%3u", c[0]); mvwprintw(colorWindow, 1, c[0]/5+1, "*"); wattroff(colorWindow, A_BOLD | COLOR_PAIR(1)); mvwprintw(colorWindow, 2, 56, "%3u", c[1]); mvwprintw(colorWindow, 3, 56, "%3u", c[2]); mvwprintw(colorWindow, 2, c[1]/5+1, "*"); mvwprintw(colorWindow, 3, c[2]/5+1, "*"); wrefresh(colorWindow); // Boucle pour la selection des valeurs int car; while ((car = wgetch(colorWindow)) != 10) { switch(car) { case KEY_UP: // Touche HAUT if (ligne != 0) { // Mise a jour affichage mvwprintw(colorWindow, ligne+1, 56, "%3u", c[ligne]); mvwprintw(colorWindow, ligne+1, c[ligne]/5+1, "*"); ligne--; } break; case KEY_DOWN: // Touche BAS if (ligne != 2) { // Mise a jour affichage mvwprintw(colorWindow, ligne+1, 56, "%3u", c[ligne]); mvwprintw(colorWindow, ligne+1, c[ligne]/5+1, "*"); ligne++; } break; case KEY_LEFT: // Touche gauche if (c[ligne] > 0) { // Mise a jour affichage mvwprintw(colorWindow, ligne+1, c[ligne]/5+1, "-"); c[ligne]--; } break; case KEY_RIGHT: // Touche droite if (c[ligne] < 255) { // Mise a jour affichage mvwprintw(colorWindow, ligne+1, c[ligne]/5+1, "-"); c[ligne]++; } break; case KEY_NPAGE : // Touche gauche if (c[ligne] > 9) { // Mise a jour affichage mvwprintw(colorWindow, ligne+1, c[ligne]/5+1, "-"); c[ligne]-=10; } break; case KEY_PPAGE: // Touche droite if (c[ligne] < 246) { // Mise a jour affichage mvwprintw(colorWindow, ligne+1, c[ligne]/5+1, "-"); c[ligne]+=10; } break; } // Mise a jour de l'affichage des valeurs wattron(colorWindow, A_BOLD | COLOR_PAIR(1)); mvwprintw(colorWindow, ligne+1, 56, "%3u", c[ligne]); mvwprintw(colorWindow, ligne+1, c[ligne]/5+1, "*"); wattroff(colorWindow, A_BOLD | COLOR_PAIR(1)); wrefresh(colorWindow); // Communication avec adjust sprintf(cmd, "c %i %u %u %u\n", col, c[0], c[1], c[2]); sendSignal(cmd); // Affichage d'info sprintf(cmd, "Couleur %i change en %u %u %u\n", col, c[0], c[1], c[2]); printStatus(cmd); } // Affectation des nouvelles valeurs for (int i=0; i<3; i++) oconfig->node[col*3+i] = c[i]; // Communication avec adjust sprintf(cmd, "c %i %u %u %u\n", col, c[0], c[1], c[2]); sendSignal(cmd); // Suppression de la fenetre ecran et affichage delwin(colorWindow); colorWindow = newwin(4, 60, 12, 25); wrefresh(colorWindow); delwin(colorWindow); } // Affiche les objets et poteaux trouvés void UI::showObjectsFound () { // Creation de la fenetre WINDOW *winInfo = newwin(15, 60, 5, 4); // Affichage du texte sendSignal ("f\n"); char buf[20] = "start"; bool end = 1; while ( end != 0 ) { read (fifo, buf, 20); end = strcmp ("end\n", buf); if (end != 0) wprintw (winInfo, "%s", buf); } wrefresh(winInfo); // Liberation de la memoire delwin(winInfo); } void UI::newNN (const int nbColor) { char buf[20]; if (nbColor != -1) { sprintf(buf, "p %i\n", nbColor); sendSignal(buf); if (oconfig->node) delete [] oconfig->node; oconfig->node = new unsigned char[nbColor*3]; oconfig->nnNbColor = nbColor; // Synchronisation des poids avec adjust updateNodes (); printStatus("Nouveau reseau de neurones charge\n"); } } /// Affiche le menu principale void UI::menu () { // Init items item = new ITEM*[NBITEMS]; for (int i=0; i "); set_menu_win(mainMenu, mainWindow); set_menu_sub(mainMenu, derwin(mainWindow, 13, 65, 3, 1)); set_menu_format(mainMenu, NBITEMS, 1); post_menu(mainMenu); // Actualisation de la fenetre wrefresh(mainWindow); int c; int select=0; int end=0; // Affichage de l'aide de l'item wattron(mainWindow,COLOR_PAIR(3)); mvwprintw(mainWindow, 3+select, 25, itemsName[select][1]); char buf[50]; // Boucle du menu principal while(!end) { c = wgetch(mainWindow); switch(c) { case KEY_DOWN: // Touche flèche BAS // On se déplace vers le bas menu_driver(mainMenu, REQ_DOWN_ITEM); if (select!=NBITEMS-2) { // Efface la ligne d'aide de l'item courant mvwprintw(mainWindow,3+select, 25, "\t\t\t\t\t\t\t"); select++; } break; case KEY_UP: // Touche flèche HAUT // On se déplace vers le haut menu_driver(mainMenu, REQ_UP_ITEM); if (select!=0) { // Efface la ligne d'aide de l'item courant mvwprintw(mainWindow,3+select, 25, "\t\t\t\t\t\t\t"); select--; } break; case 10: // Touche ENTER switch(select) { case NBITEMS-2: // Quitte le programme end=1; break; case 0: // Change les valeurs des poids du NN pour une couleur goChangeColor(); break; case 1: // Supprime une couleur goDelColor(); break; case 2: // Melange 2 couleurs goMergeWindow(); break; case 3: // Selectionne la couleur des objets à afficher { int obj; obj = chooseObject(0); if (obj >= 0) { sprintf(buf, "a %i\n", obj); sendSignal(buf); } } break; case 4: // Selectionne la couleur des objets { int obj, col; obj = chooseObject(0); if (obj >= 0) { col = chooseColor (NUM_COULEUR, 0); if (col >= 0) { std::string name = Group::translateToColorName (obj); for (std::vector::iterator iter = oconfig->groupColor.begin (); iter != oconfig->groupColor.end (); ++iter) { if (name == iter->label) { iter->color = col; break; } } sprintf(buf, "b %s %i\n", name.c_str (), col); sendSignal(buf); } } } break; case 5: // Selectionne le mode de couleur { int fc; fc = chooseColorFormat(0); if (fc >= 0) { sprintf(buf, "b %i\n", fc); sendSignal(buf); } } break; case 6: // Affiche les objets trouvés showObjectsFound (); wrefresh (mainWindow); break; case 7: // Entraine le NN sprintf(buf, "t\n"); sendSignal(buf); // Synchronisation des poids avec adjust updateNodes (); printStatus ("Réseau de neurones entrainé\n"); break; case 8: // Regeneration de poids int nbColor; nbColor = chooseColor (NB_COULEUR, oconfig->nnNbColor); oconfig->nnNbColor = nbColor; newNN (nbColor); break; case 9:// Annuler les changements // Reload du fichier de poids initial oconfig->loadNNFile(); // Envoie du nombre de couleur initial du NN et reload de l'image sprintf(buf, "r %i", savedNNColorNumber); sendSignal(buf); oconfig->nnNbColor = savedNNColorNumber; printStatus("Les changements ont été annulés\n"); break; case 10: // Sauver les changements // Sauvegarde des poids dans le fichier poids oconfig->createNNFile("rc/poids", oconfig->nnNbColor); // Reload du NN et de l'image a partir des nouveaux poids sprintf(buf, "r -1"); sendSignal(buf); printStatus ("Les changements ont été sauvés\n"); break; } // END switch touche ENTER break; // Sortie du programme case 27: // ECHAP end=true; break; // Changement d'image case ' ': // Image suivante curImage++; if (curImage >= lengthFileList) curImage = 0; // Envoie de la commande pour le chargement de la nouvelle image sprintf (buf, "n %s%s\n", oconfig->imgPath, fileList[curImage]); sendSignal (buf); break; case 'g': showObjectsFound (); wgetch (mainWindow); break; case 'n': newNN (oconfig->nnNbColor); break; } // On affiche le texte d'aide de l'item correspondant mvwprintw (mainWindow, 3+select, 25, itemsName[select][1]); wrefresh (mainWindow); } delwin (mainWindow); }