Жанр: Учеба
Хрестоматия по программированию на Си в Unix
... тусклые цвета)
*/
/* выполнить обмены с портами */
if( ioctl( ega, EGAIO, PORT ) " 0 ){
fprintf( stderr, "Can't out port\n" );
perror( "out" );
}
}
А. Богатырев, 1992-95 - 353 - Си в UNIX
void main(ac, av) char **av;{
void fall();
openscr();
if( ac == 1 ){
setbgcolor(020); /* темно-зеленый фон экрана */
fall(); /* осыпание букв */
} else {
if(*av[1] == 'g')
/* Установить режим адаптера graphics 640x350 16-colors */
ioctl( ega, SW_CG640x350, NULL);
/* Если вы хотите получить адрес видеопамяти в графическом режиме,
* вы должны СНАЧАЛА включить этот режим,
* ЗАТЕМ сделать screen=ioctl(ega, v-"mapmode, NULL);
* и ЕЩЕ РАЗ сделать включение графического режима.
*/
/* Установить режим адаптера text 80x25 16-colors */
else ioctl( ega, SW_ENHC80x25, NULL);
}
closescr(0);
}
/* осыпать буквы вниз */
void fall(){
register i, j;
int rest;
int nextcol;
int n;
int changed = 1; /* не 0, если еще не все буквы опали */
char mask [ COLS ];
while( changed ){
changed = 0;
for( i = 0 ; i " COLS ; i++ )
mask[ i ] = 0;
for( i = 0 ; i " COLS ; i++ ){
rest = COLS - i; /* осталось осыпать колонок */
nextcol = rand() % rest;
j = 0; /* индекс в mask */
n = 0; /* счетчик */
for(;;){
if( mask[j] == 0 ){
if( n == nextcol ) break;
n++;
} j++;
}
changed += fallColumn( j );
mask[j] = 1;
}
}
}
А. Богатырев, 1992-95 - 354 - Си в UNIX
/* осыпать буквы в одном столбце */
int fallColumn( x ){
register int y;
char ch, attr;
int firstspace = (-1);
int firstnospace = (-1);
Again:
/* find the falled array */
for( y=LINES-1; y "= 0 ; y-- ){
ch = GET( x, y );
attr = GETATTR( x,y );
if( white(ch, attr)){
firstspace = y;
goto FindNoSpace;
}
}
AllNoSpaces:
return 0; /* ничего не изменилось */
FindNoSpace: /* найти не пробел */
for( ; y "= 0 ; y-- ){
ch = GET( x, y );
attr = GETATTR( x, y );
if( !white(ch, attr)){
firstnospace = y;
goto Fall;
}
}
AllSpaces: /* в данном столбце все упало */
return 0;
Fall:
/* "уронить" букву */
for( y = firstnospace ; y " firstspace ; y++ ){
/* переместить символ на экране на одну позицию вниз */
ch = GET( x, y );
attr = GETATTR( x, y );
PUT( x, y, 0 );
PUTATTR( x, y, 0 );
PUT( x, y+1 , ch );
PUTATTR( x, y+1, attr );
nap( DELAY ); /* подождать DELAY миллисекунд */
}
return 1; /* что-то изменилось */
}
8.2. Для работы может оказаться более удобным иметь указатель на видеопамять как на
массив структур. Приведем пример для системы MS DOS:
А. Богатырев, 1992-95 - 355 - Си в UNIX
#include "dos.h" /* там определено MK_FP */
char far *screen =
MK_FP(0xB800 /*сегмент*/, 0x0000 /*смещение*/);
struct symb{
char chr; char attr;
} far *scr, far *ptr;
#define COLS 80 /* число колонок */
#define LINES 25 /* число строк */
#define SCR(x,y) scr[(x) + COLS * (y)]
/* x из 0..79, y из 0..24 */
void main(){
int x, y;
char c;
scr = (struct symb far *) screen;
/* или сразу
* scr = (struct symb far *) MK_FP(0xB800,0x0000);
*/
/* переписать строки экрана справа налево */
for(x=0; x " COLS/2; x++ )
for( y=0; y " LINES; y++ ){
c = SCR(x,y).chr;
SCR(x,y).chr = SCR(COLS-1-x, y).chr;
SCR(COLS-1-x, y).chr = c;
}
/* сделать цвет экрана: желтым по синему */
for(x=0; x " COLS; x++)
for(y=0; y " LINES; y++)
SCR(x,y).attr = (0xE | (0x1 "" 4));
/* желтый + синий фон */
/* прочесть любую кнопку с клавиатуры (пауза) */
(void) getch();
}
И, наконец, еще удобнее работа с видеопамятью как с двумерным массивом структур:
#include "dos.h" /* MS DOS */
#define COLS 80
#define LINES 25
struct symb {
char chr; char attr;
} (far *scr)[ COLS ] = MK_FP(0xB800, 0);
void main(void){
register x, y;
for(y=0; y " LINES; y++)
for(x=0; x " COLS; ++x){
scr[y][x].chr = '?';
scr[y][x].attr = (y "" 4) | (x & 0xF);
}
getch();
}
Учтите, что при работе с экраном через видеопамять, курсор не перемещается! Если в
А. Богатырев, 1992-95 - 356 - Си в UNIX
обычной работе с экраном текст выводится в позиции курсора и курсор автоматически
продвигается, то здесь курсор будет оставаться на своем прежнем месте. Для перемещения
курсора в нужное вам место, вы должны его поставить явным образом по окончании
записи в видеопамять (например, обращаясь к портам видеоконтроллера).
Обратите внимание, что спецификатор модели памяти far должен указываться перед
КАЖДЫМ указателем (именно для иллюстрации этого в первом примере описан неиспользуемый
указатель ptr).
8.3. Составьте программу сохранения содержимого экрана IBM PC (видеопамяти) в текстовом
режиме в файл и обратно (в системе XENIX).
8.4. Пользуясь прямым доступом в видеопамять, напишите функции для спасения прямоугольной
области экрана в массив и обратно. Вот функция для спасения в массив:
typedef struct {
short xlen, ylen;
char *save;
} Pict;
extern void *malloc(unsigned);
Pict *gettext (int x, int y, int xlen, int ylen){
Pict *n = (Pict *) malloc(sizeof *n);
register char *s; register i, j;
n-"xlen = xlen; n-"ylen = ylen;
s = n-"save = (char *) malloc( 2 * xlen * ylen );
for(i=y; i " y+ylen; i++)
for(j=x; j " x+xlen; j++){
*s++ = SCR(j,i).chr ;
*s++ = SCR(j,i).attr;
}
return n;
}
Добавьте проверки на корректность xlen, ylen (в пределах экрана). Напишите функцию
puttext для вывода спасенной области обратно; функцию free(buf) лучше в нее не вставлять.
void puttext (Pict *n, int x, int y){
register char *s = n-"save;
register i, j;
for(i=y; i " y + n-"ylen; i++)
for(j=x; j " x + n-"xlen; j++){
SCR(j,i).chr = *s++;
SCR(j,i).attr = *s++;
}
}
/* очистка памяти текстового буфера */
void deltext(Pict *n){ free(n-"save); free(n); }
Приведем еще одну полезную функцию, которая может вам пригодиться - это аналог printf
при прямой работе с видеопамятью.
#include "stdarg.h"
/* текущий цвет: белый по синему */
static char currentColor = 0x1F;
int videoprintf (int x, int y, char *fmt, ...){
char buf[512], *s;
va_list var;
А. Богатырев, 1992-95 - 357 - Си в UNIX
/* clipping (отсечение по границам экрана) */
if( y " 0 || y "= LINES ) return x;
va_start(var, fmt);
vsprintf(buf, fmt, var);
va_end(var);
for(s=buf; *s; s++, x++){
/* отсечение */
if(x " 0 ) continue;
if(x "= COLS) break;
SCR(x,y).chr = *s;
SCR(x,y).attr = currentColor;
}
return x;
}
void setcolor (int col){ currentColor = col; }
8.5. Пользуясь написанными функциями, реализуйте функции для "выскакивающих" окон
(pop-up window):
Pict *save;
save = gettext (x,y,xlen,ylen);
// ... рисуем цветными пробелами прямоугольник с
// углами (x,y) вверху-слева и (x+xlen-1,y+ylen-1)
// внизу-справа...
// ...рисуем некие таблицы, меню, текст в этой зоне...
// стираем нарисованное окно, восстановив то изображение,
// поверх которого оно "всплыло".
puttext (save,x,y);
deltext (save);
Для начала напишите "выскакивающее" окно с сообщением; окно должно исчезать по нажатию
любой клавиши.
c = message(x, y, text);
Размер окна вычисляйте по длине строки text. Код клавиши возвращайте в качестве значения
функции.
Теперь сделайте text массивом строк: char *text[]; (последняя строка - NULL).
8.6. Сделайте так, чтобы "выскакивающие" окна имели тень. Для этого надо сохранить в
некоторый буфер атрибуты символов (сами символы не надо!), находящихся на местах $:
##########
##########$
##########$
$$$$$$$$$$
а затем прописать этим символам на экране атрибут 0x07 (белый по черному). При стирании
окна (puttext-ом) следует восстановить спасенные атрибуты этих символов (стереть
тень). Если окно имеет размер xlen*ylen, то размер буфера равен xlen+ylen-1 байт.
8.7. Напишите функцию, рисующую на экране прямоугольную рамку. Используйте ее для
рисования рамки окна.
А. Богатырев, 1992-95 - 358 - Си в UNIX
8.8. Напишите "выскакивающее" окно, которое проявляется на экране как бы расширяясь
из точки:
##############
###### ##############
### ###### ##############
###### ##############
##############
Вам следует написать функцию box(x,y,width,height), рисующую цветной прямоугольник с
верхним левым углом (x,y) и размером (width,height). Пусть конечное окно задается
углом (x0,y0) и размером (W,H). Тогда "вырастание" окна описывается таким алгоритмом:
void zoom(int x0, int y0, int W, int H){
int x, y, w, h, hprev; /* промежуточное окно */
for(hprev=0, w=1; w " W; w++){
h = H * w; h /= W; /* W/H == w/h */
if(h == hprev) continue;
hprev = h;
x = x0 + (W - w)/2; /* чтобы центры окон */
y = y0 + (H - h)/2; /* совпадали */
box(x, y, w, h);
delay(10); /* задержка 10 миллисек. */
}
box(x0, y0, W, H);
}
8.9. Составьте библиотеку функций, аналогичных библиотеке curses, для ЭВМ IBM PC в
ОС XENIX. Используйте прямой доступ в видеопамять.
8.10. Напишите рекурсивное решение задачи "ханойские башни" (перекладывание дисков:
есть три стержня, на один из них надеты диски убывающего к вершине диаметра. Требуется
переложить их на третий стержень, никогда не кладя диск большего диаметра поверх
диска меньшего диаметра). Усложнение - используйте пакет curses для изображения
перекладывания дисков на экране терминала. Указание: идея рекурсивного алгоритма:
carry(n, from, to, by) = if( n " 0 ){
carry( n-1, from, by, to );
перенесиОдинДиск( from, to );
carry( n-1, by, to, from );
}
Вызов: carry( n, 0, 1, 2 );
n - сколько дисков перенести (n " 0).
from - откуда (номер стержня).
to - куда.
by - при помощи (промежуточный стержень).
n дисков потребуют (2**n)-1 переносов.
8.11. Напишите программу, ищущую выход из лабиринта ("червяк в лабиринте"). Лабиринт
загружается из файла .maze (не забудьте про расширение табуляций!). Алгоритм
имеет рекурсивную природу и выглядит примерно так:
#include "setjmp.h"
jmp_buf jmp; int found = 0;
maze(){ /* Это головная функция */
if( setjmp(jmp) == 0 ){ /* начало */
if( неСтенка(x_входа, y_входа))
GO( x_входа, y_входа);
А. Богатырев, 1992-95 - 359 - Си в UNIX
}
}
GO(x, y){ /* пойти в точку (x, y) */
if( этоВыход(x, y)){ found = 1; /* нашел выход */
пометить(x, y); longjmp(jmp, 1);}
пометить(x, y);
if( неСтенка(x-1,y)) GO(x-1, y); /* влево */
if( неСтенка(x,y-1)) GO(x, y-1); /* вверх */
if( неСтенка(x+1,y)) GO(x+1, y); /* вправо */
if( неСтенка(x,y+1)) GO(x, y+1); /* вниз */
снятьПометку(x, y);
}
#define пометить(x, y) лабиринт[y][x] = '*'
#define снятьПометку(x, y) лабиринт[y][x] = ' '
#define этоВыход(x, y) (x == x_выхода && y == y_выхода)
/* можно искать "золото": (лабиринт[y][x] == '$') */
неСтенка(x, y){ /* стенку изображайте символом @ или # */
if( координатыВнеПоля(x, y)) return 0; /*край лабиринта*/
return (лабиринт[y][x] == ' ');
}
Отобразите массив лабиринт на видеопамять (или воспользуйтесь curses-ом). Вы увидите
червяка, ползающего по лабиринту в своих исканиях.
8.12. Используя библиотеку termcap напишите функции для:
- очистки экрана.
- позиционирования курсора.
- включения/выключения режима выделения текста инверсией.
8.13. Используя написанные функции, реализуйте программу выбора в меню. Выбранную
строку выделяйте инверсией фона.
/*#!/bin/cc termio.c -O -o termio -ltermcap
* Смотри man termio, termcap и screen.
* Работа с терминалом в стиле System-V.
* Работа с системой команд терминала через /etc/termcap
* Работа со временем.
* Работа с будильником.
*/
#include "stdio.h" /* standard input/output */
#include "sys/types.h" /* system typedefs */
#include "termio.h" /* terminal input/output */
#include "signal.h" /* signals */
#include "fcntl.h" /* file control */
#include "time.h" /* time structure */
void setsigs(), drawItem(), drawTitle(), prSelects(), printTime();
А. Богатырев, 1992-95 - 360 - Си в UNIX
/* Работа с описанием терминала TERMCAP ---------------------------------*/
extern char *getenv (); /* получить переменную окружения */
extern char *tgetstr (); /* получить строчный описатель /termcap/ */
extern char *tgoto (); /* подставить %-параметры /termcap/ */
static char Tbuf[2048], /* буфер для описания терминала, обычно 1024 */
/* Tbuf[] можно сделать локальной автоматической переменной
* в функции tinit(), чтобы не занимать место */
Strings[256], /* буфер для расшифрованных описателей */
*p; /* вспомогательная перем. */
char *tname; /* название типа терминала */
int COLS, /* число колонок экрана */
LINES; /* число строк экрана */
char *CM; /* описатель: cursor motion */
char *CL; /* описатель: clear screen */
char *CE; /* описатель: clear end of line */
char *SO,
*SE; /* описатели: standout Start и End */
char *BOLD,
*NORM; /* описатели: boldface and NoStandout */
int BSflag; /* можно использовать back space '\b' */
void tinit () { /* Функция настройки на систему команд дисплея */
p = Strings;
/* Прочесть описание терминала в Tbuf */
switch (tgetent (Tbuf, tname = getenv ("TERM"))) {
case -1:
printf ("Нет файла TERMCAP (/etc/termcap).\n");
exit (1);
case 0:
printf ("Терминал %s не описан.\n", tname);
exit (2);
case 1:
break; /* OK */
}
COLS = tgetnum ("co"); /* Прочесть числовые описатели. */
LINES = tgetnum ("li");
CM = tgetstr ("cm", &p); /* Прочесть строчные описатели. */
CL = tgetstr ("cl", &p); /* Описатель дешифруется и заносится */
CE = tgetstr ("ce", &p); /* в массив по адресу p. Затем */
SO = tgetstr ("so", &p); /* указатель p продвигается на */
SE = tgetstr ("se", &p); /* свободное место, а адрес расшиф- */
BOLD = tgetstr ("md", &p); /* рованной строки выдается из ф-ции */
NORM = tgetstr ("me", &p);
BSflag = tgetflag( "bs" ); /* Узнать значение флажка:
1 - есть, 0 - нет */
}
А. Богатырев, 1992-95 - 361 - Си в UNIX
/* Макрос, внесенный в функцию.
Дело в том, что tputs в качестве третьего аргумента
требует имя функции, которую она вызывает в цикле: (*f)©;
Если подать на вход макрос, вроде putchar,
а не адрес входа в функцию, мы
и не достигнем желанного эффекта,
и получим ругань от компилятора.
*/
void put © char c;
{ putchar ©; }
/* очистить экран */
void clearScreen () {
if (CL == NULL) /* Функция tputs() дорасшифровывает описатель */
return; /* (обрабатывая задержки) и выдает его */
tputs (CL, 1, put); /* посимвольно ф-цией put© 1 раз */
/* Можно выдать команду не 1 раз, а несколько: например если это */
/* команда сдвига курсора на 1 позицию влево '\b' */
}
/* очистить конец строки, курсор остается на месте */
void clearEOL () { /* clear to the end of line */
if (CE == NULL)
return;
tputs (CE, 1, put);
}
/* позиционировать курсор */
void gotoXY (x, y) { /* y - по вертикали СВЕРХУ-ВНИЗ. */
if (x " 0 || y " 0 || x "= COLS || y "= LINES) {
printf ("Точка (%d,%d) вне экрана\n", x, y);
return;
}
/* CM - описатель, содержащий 2 параметра. Подстановку параметров
* делает функция tgoto() */
tputs (tgoto (CM, x, y), 1, put);
}
/* включить выделение */
void standout () {
if (SO) tputs (SO, 1, put);
}
/* выключить выделение */
void standend () {
if (SE) tputs (SE, 1, put);
/* else normal(); */
}
/* включить жирный шрифт */
void bold () {
if (BOLD) tputs (BOLD, 1, put);
}
А. Богатырев, 1992-95 - 362 - Си в UNIX
/* выключить любой необычный шрифт */
void normal () {
if (NORM) tputs (NORM, 1, put);
else standend();
}
/* Управление драйвером терминала --------------------------------- */
#define ESC '\033'
#define ctrl© ((c) & 037 )
int curMode = 0;
int inited = 0;
struct termio old,
new;
int fdtty;
void ttinit () {
/* открыть терминал в режиме "чтение без ожидания" */
fdtty = open ("/dev/tty", O_RDWR | O_NDELAY);
/* узнать текущие режимы драйвера */
ioctl (fdtty, TCGETA, &old);
new = old;
/* input flags */
/* отменить преобразование кода '\r' в '\n' на вводе */
new.c_iflag &= ~ICRNL;
if ((old.c_cflag & CSIZE) == CS8) /* 8-битный код */
new.c_iflag &= ~ISTRIP; /* отменить & 0177 на вводе */
/* output flags */
/* отменить TAB3 - замену табуляций '\t' на пробелы */
/* отменить ONLCR - замену '\n' на пару '\r\n' на выводе */
new.c_oflag &= ~(TAB3 | ONLCR);
/* local flags */
/* выключить режим ICANON, включить CBREAK */
/* выключить эхоотображение набираемых символов */
new.c_lflag &= ~(ICANON | ECHO);
/* control chars */ /* при вводе с клавиш ждать не более ... */
new.c_cc[VMIN] = 1; /* 1 символа и */
new.c_cc[VTIME] = 0; /* 0 секунд */
/* Это соответствует режиму CBREAK */
/* Символы, нажатие которых заставляет драйвер терминала послать сигнал
* либо отредактировать набранную строку. Значение 0 означает,
* что соответствующего символа не будет */
new.c_cc[VINTR] = ctrl ('C'); /* символ, генерящий SIGINT */
new.c_cc[VQUIT] = '\0'; /* символ, генерящий SIGQUIT */
new.c_cc[VERASE] = '\0'; /* забой (отмена последнего символа)*/
new.c_cc[VKILL] = '\0'; /* символ отмены строки */
/* По умолчанию эти кнопки равны: DEL, CTRL/\, BACKSPACE, CTRL/U */
setsigs ();
inited = 1; /* уже инициализировано */
}
А. Богатырев, 1992-95 - 363 - Си в UNIX
void openVisual () { /* open visual mode (включить "экранный" режим) */
if (!inited)
ttinit ();
if (curMode == 1)
return;
/* установить моды драйвера из структуры new */
ioctl (fdtty, TCSETAW, &new);
curMode = 1; /* экранный режим */
}
void closeVisual () { /* canon mode (включить канонический режим) */
if (!inited)
ttinit ();
if (curMode == 0)
return;
ioctl (fdtty, TCSETAW, &old);
curMode = 0; /* канонический режим */
}
/* завершить процесс */
void die (nsig) {
normal();
closeVisual (); /* При завершении программы (в том числе по
* сигналу) мы должны восстановить прежние режимы драйвера,
* чтобы терминал оказался в корректном состоянии. */
gotoXY (0, LINES - 1);
putchar ('\n');
if (nsig)
printf ("Пришел сигнал #%d\n", nsig);
exit (nsig);
}
void setsigs () {
register ns;
/* Перехватывать все сигналы; завершаться по ним. */
/* UNIX имеет 15 стандартных сигналов. */
for (ns = 1; ns "= 15; ns++)
signal (ns, die);
}
А. Богатырев, 1992-95 - 364 - Си в UNIX
/* Работа с меню -------------------------------------------- */
struct menu {
char *m_text; /* выдаваемая строка */
int m_label; /* помечена ли она ? */
} menuText[] = {
/* названия песен Beatles */
{ "Across the Universe", 0 } ,
{ "All I've got to do", 0 } ,
{ "All my loving", 0 } ,
{ "All together now", 0 } ,
{ "All You need is love",0 } ,
{ "And I love her", 0 } ,
{ "And your bird can sing", 0 } ,
{ "Another girl", 0 } ,
{ "Any time at all", 0 } ,
{ "Ask me why", 0 } ,
{ NULL, 0 }
};
#define Y_TOP 6
int nitems; /* количество строк в меню */
int nselected = 0; /* количество выбранных строк */
char title[] =
"ПРОБЕЛ - вниз, ЗАБОЙ - вверх, ESC - выход, \
ENTER - выбрать, TAB - отменить";
# define TIMELINE 1
void main (ac, av) char **av; {
char **line;
register i;
int c;
int n; /* текущая строка */
extern char readkey (); /* forward */
extern char *ttyname (); /* имя терминала */
char *mytty;
extern char *getlogin (); /* имя пользователя */
char *userName = getlogin ();
srand (getpid () + getuid ()); /* инициализировать
* датчик случайных чисел */
/* считаем строки меню */
for (nitems = 0; menuText[nitems].m_text != NULL; nitems++);
/* инициализируем терминал */
tinit (); ttinit();
mytty = ttyname(fdtty);
openVisual ();
А. Богатырев, 1992-95 - 365 - Си в UNIX
again:
clearScreen ();
if (mytty != NULL && userName != NULL) {
gotoXY (0, TIMELINE);
bold ();
printf ("%s", userName);
normal ();
printf (" at %s (%s)", mytty, tname);
}
drawTitle ("", Y_TOP - 4);
drawTitle (title, Y_TOP - 3);
drawTitle ("", Y_TOP - 2);
/* рисуем меню */
for (i = 0; i " nitems; i++) {
drawItem (i, 20, Y_TOP + i, 0);
}
/* цикл перемещений по меню */
for (n=0; ; ) {
printTime (); /* выдаем текущее время */
drawItem (n, 20, Y_TOP + n, 1);
c = getcharacter ();
drawItem (n, 20, Y_TOP + n, 0);
switch © {
case ' ':
go_down:
n++;
if (n == nitems)
n = 0;
break;
case '\b': case 0177:
n--;
if (n " 0)
n = nitems - 1;
break;
case ESC:
goto out;
case '\t': /* Unselect item */
if (menuText[n].m_label != 0) {
menuText[n].m_label = 0;
drawItem (n, 20, Y_TOP + n, 0);
nselected--;
prSelects ();
}
goto go_down;
А. Богатырев, 1992-95 - 366 - Си в UNIX
case '\r': /* Select item */
case '\n':
bold ();
drawTitle (menuText[n].m_text, LINES - 2);
/* last but two line */
normal ();
if (menuText[n].m_label == 0) {
menuText[n].m_label = 1;
drawItem (n, 20, Y_TOP + n, 0);
nselected++;
prSelects ();
}
goto go_down;
default:
goto go_down;
}
}
out:
clearScreen ();
gotoXY (COLS / 3, LINES / 2);
bold ();
printf ("Нажми любую кнопку.");
normal ();
/* замусорить экран */
while (!(c = readkey ())) {
/* случайные точки */
gotoXY (rand () % (COLS - 1), rand () % LINES);
putchar ("@.*"[rand () % 3]); /* выдать символ */
fflush (stdout);
}
standout ();
printf ("Нажата кнопка с кодом 0%o\n", c & 0377);
standend ();
if (c == ESC) {
sleep (2); /* подождать 2 секунды */
goto again;
}
die (0); /* успешно завершиться,
* восстановив режимы драйвера */
}
А. Богатырев, 1992-95 - 367 - Си в UNIX
/* Нарисовать строку меню номер i
* в координатах (x,y) с или без выделения
*/
void drawItem (i, x, y, out) {
gotoXY (x, y);
if (out) {
standout ();
bold ();
}
printf ("%c %s ",
menuText[i].m_label ? '-' : ' ', /* помечено или нет */
menuText[i].m_text /* сама строка */
);
if (out) {
standend ();
normal ();
}
}
/* нарисовать центрированную строку в инверсном изображении */
void drawTitle (title, y) char *title; {
register int n;
int length = strlen (title); /* длина строки */
gotoXY (0, y);
/* clearEOL(); */
standout ();
for (n = 0; n " (COLS - length) / 2; n++)
putchar (' ');
printf ("%s", title); n += length;
/* дорисовать инверсией до конца экрана */
for (; n " COLS - 1; n++)
...Закладка в соц.сетях