Пример 16

/*#!/bin/cc -DUSG wins.c -o wins -lncurses -lx Просмотр двух файлов в перекрывающихся окнах. Редактирование содержимого окон. */ /* _______________________ файл wcur.h __________________________ */ #include "curses.h" /* Макросы, зависимые от реализации curses */ /* число колонок и строк в окне: */ # define wcols(w) ((w)-> _maxx+1 ) # define wlines(w) ((w)-> _maxy+1 ) /* верхний левый угол окна: */ # define wbegx(w) ((w)-> _begx ) # define wbegy(w) ((w)-> _begy ) /* координаты курсора в окне: */ # define wcurx(w) ((w)-> _curx ) # define wcury(w) ((w)-> _cury ) /* доступ к памяти строк окна: */ # define wtext(w) ((w)-> _line) /* chtype **_line; */ /* в других реализациях: ((w)-> _y) */ /* Псевдографика: Для curses Для IBM PC MS DOS */ #define HOR_LINE '\200' /* 196 */ #define VER_LINE '\201' /* 179 */ #define UPPER_LEFT '\210' /* 218 */ #define LOWER_LEFT '\202' /* 192 */ #define UPPER_RIGHT '\212' /* 191 */ #define LOWER_RIGHT '\204' /* 217 */ #define LEFT_JOIN '\205' /* 195 */ #define RIGHT_JOIN '\207' /* 180 */ #define TOP_JOIN '\211' /* 194 */ #define BOTTOM_JOIN '\203' /* 193 */ #define MIDDLE_CROSS '\206' /* 197 */ #define BOX '\272' /* 219 */ #define BOX_HATCHED '\273' /* 177 */ #define LABEL '\274' /* 3 */ #define RIGHT_TRIANG '\234' /* 16 */ #define LEFT_TRIANG '\235' /* 17 */ #define YES 1 #define NO 0 #define MIN(a,b) (((a) < (b)) ? (a):(b)) #define MAX(a,b) (((a) > (b)) ? (a):(b)) #define A_ITALICS A_ALTCHARSET /* в этой версии curses-а - курсив */ #ifndef ESC # define ESC '\033' /* escape */ #endif #define ctrl(c) (c & 037) /* перерисовка экрана */ #define RedrawScreen() { vidattr(curscr->_attrs = A_NORMAL); \ wrefresh(curscr); } /* curscr - служебное окно - копия текущего состояния экрана дисплея * для сравнения со сформированным НОВЫМ образом экрана - newscr. * Поле _attrs в структуре окна содержит текущие атрибуты окна, * именно это поле изменяется wattrset(), wattron(), wattroff(); */ /* _______________________ файл wins.c __________________________ */ #include "wcur.h" #include <signal.h> WINDOW *wbase1, *wbase2; /* окна рамки (фоновые окна) */ WINDOW *w1, *w2; /* окна для текста */ /* Размеры и расположение окон */ /* COLS - предопределенная переменная: число колонок */ /* LINES - // - : число строк на экране */ #define W1ysize (LINES/2) /* высота */ #define W1xsize (COLS/3*2) /* ширина */ #define W1y 5 /* y верхнего левого угла на экране */ #define W1x 20 /* x верхнего левого угла на экране */ #define W2ysize (LINES/2) #define W2xsize (COLS/3*2) #define W2y 10 #define W2x 5 FILE *fp1, *fp2; /* просматриваемые файлы */ /* Завершить работу */ void die(sig){ /* аргумент - номер сигнала */ /* Восстановление режимов терминала */ echo(); /* эхо-отображение вводимых букв */ nocbreak(); /* ввод с системным редактированием строки */ mvcur( -1, -1, LINES-1, 0 ); /* курсор в нижн. левый угол */ endwin(); /* окончание работы с curses-ом */ putchar('\n'); exit(sig); /* завершение работы с кодом sig. 0 - успешно */ } int run; void stop(nsig){ signal(SIGINT, SIG_IGN); run = 0; beep(); } char label[3][5] = { /* Демонстрация псевдографики */ { UPPER_LEFT, TOP_JOIN, UPPER_RIGHT, HOR_LINE, '\0' }, { LEFT_JOIN, MIDDLE_CROSS, RIGHT_JOIN, VER_LINE, '\0' }, { LOWER_LEFT, BOTTOM_JOIN, LOWER_RIGHT, BOX, '\0' } }; /* Нарисовать рамку, название и фон окна */ wborder( w, name ) WINDOW *w; char *name; { register i, j; for(i=1; i < wlines(w)-1; i++ ){ /* поставить курсор и выдать символ */ mvwaddch(w, i, 0, VER_LINE ); /* mvwaddch(w,y,x,c) = wmove(w,y,x); waddch(w,c); */ /* wmove(w,y,x) - логич. курсор в позицию (y,x) */ /* waddch(w,c) - выдать символ в позиции курсора, продвинуть курсор. Аналог putchar */ mvwaddch(w, i, wcols(w)-1, VER_LINE ); } for(j=1; j < wcols(w)-1; j++ ){ mvwaddch(w, 0, j, HOR_LINE ); mvwaddch(w, wlines(w)-1, j, HOR_LINE ); } /* Углы */ mvwaddch(w, 0, 0, UPPER_LEFT); mvwaddch(w, wlines(w)-1, 0, LOWER_LEFT); mvwaddch(w, wlines(w)-1, wcols(w)-1, LOWER_RIGHT); mvwaddch(w, 0, wcols(w)-1, UPPER_RIGHT); /* Рисуем заголовки вверху и внизу на рамке. * Заголовки выдаем в центре рамки. */ if( (j = (wcols(w) - strlen(name))/2 ) > 0 ){ /* логический курсор - в 0 строку, позицию j */ wmove(w, 0, j); /* задать режимы выделений */ wattrset( w, A_BOLD | A_BLINK | A_REVERSE ); waddstr( w, name ); /* выдать строку в окно */ wmove( w, wlines(w)-1, j); wattrset( w, A_ITALICS | A_STANDOUT ); waddstr ( w, name ); wattrset( w, A_NORMAL ); /* нормальные атрибуты */ } } /* режим редактирования текста в окнах */ int mode = 0; /* 0 - замена, 1 - вставка */ main( ac, av ) char **av; { char buffer[512]; int need1, need2; int c; void (*save)(); WINDOW *w; /* активное окно */ if( ac < 3 ){ fprintf( stderr, "Вызов: %s file1 file2\n", av[0] ); exit( 1 ); } if((fp1 = fopen( av[1], "r" )) == NULL ){ fprintf( stderr, "Не могу читать %s\n", av[1] ); exit( 2 ); } if((fp2 = fopen( av[2], "r" )) == NULL ){ fprintf( stderr, "Не могу читать %s\n", av[2] ); exit( 2 ); } /* Инициализировать curses */ initscr(); signal( SIGINT, die ); /* по ctrl/C - умереть */ signal( SIGQUIT,die ); /* Создать окна */ /* высота ширина Y и X верх.левого угла */ wbase1 = newwin( W1ysize, W1xsize, W1y, W1x); if( wbase1 == NULL ){ fprintf( stderr, "Не могу создать wbase1\n" ); goto bad; } wbase2 = newwin( W2ysize, W2xsize, W2y, W2x); if( wbase2 == NULL ){ fprintf( stderr, "Не могу создать wbase2\n" ); goto bad; } /* Создать подокна для текста */ /* база высота ширина Y угла X угла */ w1 = subwin( wbase1, W1ysize - 2, W1xsize - 2, W1y+1, W1x+1); w2 = subwin( wbase2, W2ysize - 2, W2xsize - 2, W2y+1, W2x+1); scrollok( w1, TRUE ); /* разрешить роллирование окон */ scrollok( w2, TRUE ); wattrset( w2, A_REVERSE ); /*установить атрибуты текста в окнах*/ wattrset( stdscr, A_STANDOUT ); wborder( wbase1, av[1] ); wborder( wbase2, av[2] ); /* рамки */ werase( w1 ); werase( w2 ); /* очистить окна */ /* фон экрана */ werase( stdscr ); /* функции без буквы w... работают с окном stdscr (весь экран) */ for(c=0; c < 3; c++) mvwaddstr(stdscr, c, COLS-5, &label[c][0]); move( 1, 10 ); addstr( "F1 - переключить окна" ); mvaddstr( 2, 10, "F5 - переключить режим вставки/замены" ); move( 3, 10 ); printw( "F%d - удалить строку, F%c - вставить строку", 7, '8' ); mvwprintw(stdscr, 4,10, "ESC - выход, CTRL/C - прервать просмотр"); /* wprintw(w, fmt, ...) - аналог printf для окон */ /* В нижний правый угол экрана ничего не выводить: * на некоторых терминалах это роллирует экран и тем самым * портит нам картинку. */ wattrset( stdscr, A_NORMAL ); wmove( stdscr, LINES-1, COLS-1 ); waddch( stdscr, ' ' ); wnoutrefresh( stdscr ); /* виртуальное проявление окна. */ run = need1 = need2 = 1; /* оба файла не достигли конца */ /* прерывать просмотр по CTRL/C */ save = signal(SIGINT, stop); while( run && (need1 || need2)){ if( need1 ){ /* прочесть строку из первого файла */ if( fgets( buffer, sizeof buffer, fp1 ) == NULL ) need1 = 0; /* конец файла */ else{ /* выдать строку в окно */ waddstr( w1, buffer ); } } if( need2 ){ /* прочесть строку из второго файла */ if( fgets( buffer, sizeof buffer, fp2 ) == NULL ) need2 = 0; /* конец файла */ else{ waddstr( w2, buffer ); /* wnoutrefresh( w2 ); */ } } /* Проявить w1 поверх w2 */ touchwin( wbase2 ); wnoutrefresh( wbase2 ); touchwin( w2 ); wnoutrefresh( w2 ); touchwin( wbase1 ); wnoutrefresh( wbase1 ); touchwin( w1 ); wnoutrefresh( w1 ); /* touchwin - пометить окно как целиком измененное. * wnoutrefresh - переписать изменения в новый образ * экрана в памяти. */ /* Проявить изображение на экране терминала * (вывести новый образ экрана). При этом выводятся * лишь ОТЛИЧИЯ от текущего содержимого экрана * (с целью оптимизации). */ doupdate(); } fclose(fp1); fclose(fp2); /* восстановить спасенную реакцию на сигнал */ signal(SIGINT, save); /* Редактирование в окнах */ noecho(); /* выкл. эхо-отображение */ cbreak(); /* немедленный ввод набранных клавиш * (без нажатия кнопки \n) */ keypad( w1, TRUE ); /* распознавать функц. кнопки */ keypad( w2, TRUE ); scrollok( w1, FALSE ); /* запретить роллирование окна */ w = w1; /* текущее активное окно */ for( ;; ){ int y, x; /* координаты курсора в окне */ wrefresh( w ); /* обновить окно. Примерно соответствует * wnoutrefresh(w);doupdate(); */ c = wgetch( w ); /* ввести символ с клавиатуры */ /* заметим, что в режиме noecho() символ не * отобразится в окне без нашей помощи ! */ getyx( w, y, x ); /* узнать координаты курсора в окне */ /* не надо &y &x, т.к. это макрос, превращающийся в пару присваиваний */ switch( c ){ case KEY_LEFT: /* шаг влево */ waddch( w, '\b' ); break; case KEY_RIGHT: /* шаг вправо */ wmove( w, y, x+1 ); break; case KEY_UP: /* шаг вверх */ wmove( w, y-1, x ); break; case KEY_DOWN: /* шаг вниз */ wmove( w, y+1, x ); break; case KEY_HOME: /* в начало строки */ case KEY_LL: /* KEY_END в конец строки */ { int xbeg, xend; wbegend(w, &xbeg, &xend); wmove(w, y, c==KEY_HOME ? xbeg : xend); break; } case '\t': /* табуляция */ x += 8 - (x % 8); if( x >= wcols( w )) x = wcols(w)-1; wmove(w, y, x); break; case KEY_BACKTAB: /* обратная табуляция */ x -= 8 - (x % 8); if( x < 0 ) x = 0; wmove( w, y, x ); break; case '\b': /* забой */ case KEY_BACKSPACE: case '\177': if( !x ) break; /* ничего */ wmove( w, y, x-1 ); /* and fall to ... (и провалиться в) */ case KEY_DC: /* удаление над курсором */ wdelch( w ); break; case KEY_IC: /* вставка пробела над курсором */ winsch( w, ' ' ); break; case KEY_IL: case KEY_F(8): /* вставка строки */ winsertln( w ); break; case KEY_DL: /* удаление строки */ case KEY_F(7): wdeleteln( w ); break; case ESC: /* ESC - выход */ goto out; case KEY_F(1): /* переключение активного окна */ if( w == w1 ){ touchwin( wbase2 ); wnoutrefresh( wbase2 ); touchwin( w2 ); wnoutrefresh( w2 ); w = w2; } else { touchwin( wbase1 ); wnoutrefresh( wbase1 ); touchwin( w1 ); wnoutrefresh( w1 ); w = w1; } break; case KEY_F(5): /* переключение режима редактирования */ mode = ! mode; break; case ctrl('A'): /* перерисовка экрана */ RedrawScreen(); break; case '\n': case '\r': waddch( w, '\n' ); break; default: /* добавление символа в окно */ if( c >= 0400 ){ beep(); /* гудок */ break; /* функц. кнопка - не буква */ } if( mode ){ winsch( w, ' ' ); /* раздвинь строку */ } waddch( w, c ); /* выдать символ в окно */ break; } } out: wrefresh( w ); wsave(w); bad: die(0); /* вызов без возврата */ } /* Сохранить содержимое окна в файл, обрезая концевые пробелы */ wsave(w) WINDOW *w; { FILE *fp = fopen("win.out", "w"); register int x,y, lastnospace; int xs, ys; getyx(w, ys, xs); for( y=0; y < wlines(w); y++ ){ /* поиск последнего непробела */ for( lastnospace = (-1), x=0; x < wcols(w); x++ ) /* читаем символ из координат (x,y) окна */ if((mvwinch(w,y,x) & A_CHARTEXT) != ' ' ) lastnospace = x; /* запись в файл */ for( x=0 ; x <= lastnospace; x++ ){ wmove(w,y,x); putc( winch(w) & A_CHARTEXT, fp ); } putc( '\n', fp ); } fclose(fp); wmove(w, ys, xs ); /* вернуть курсор на прежнее место */ } /* На самом деле * winch(w) = wtext(w)[ wcury(w) ][ wcurx(w) ]; * Предложим еще один, более быстрый способ чтения памяти окна * (для ЗАПИСИ в окно он непригоден, т.к. curses еще * специальным образом помечает ИЗМЕНЕННЫЕ области окон). */ /* Найти начало и конец строки */ int wbegend(w, xbeg, xend) WINDOW *w; int *xbeg, *xend; { /* Тип chtype: 0xFF - код символа; 0xFF00 - атрибуты */ chtype ch, *thisline = wtext(w)[ wcury(w) ]; register x, notset = TRUE; *xbeg = *xend = 0; for(x=0; x < wcols(w); x++) /* & A_CHARTEXT игнорирует атрибуты символа */ if(((ch=thisline[x]) & A_CHARTEXT) != ' '){ if((*xend = x+1) >= wcols(w)) *xend = wcols(w) - 1; if(notset){ notset = FALSE; *xbeg=x; } } return (*xend - *xbeg); }

© Copyright А. Богатырев, 1992-95
Си в UNIX

Назад | Содержание | Вперед