/* Window management: "стопка" окон
* cc -DTEST -DUSG w.c -lncurses -lx
*
*____ Файл w.h для Пример 17, Пример 19, Пример 21, Пример 23 _____ */
#include "wcur.h" /* Тот же, что в Пример 16 */
extern int botw, topw;
extern struct WindowList { /* Элемент списка окон */
WINDOW *w; /* окно */
int next; /* следующее окно в списке */
char busy; /* 0:слот свободен, 1:окно видимо, -1:окно спрятано */
} wins[]; /* значения поля busy: */
#define W_VISIBLE 1 /* окно видимо */
#define W_FREE 0 /* слот таблицы свободен */
#define W_HIDDEN (-1) /* окно спрятано */
#define EOW (-1)
#define WIN(n) wins[n].w
/* если совсем нет видимых окон... */
#define TOPW (topw != EOW ? WIN(topw) : stdscr)
#define BOTW (botw == EOW ? stdscr : WIN(botw))
#define MAXW 15
#define iswindow(n) wins[n].busy
int RaiseWin (WINDOW *w); void PopWin ();
void DestroyWin(WINDOW *w, int destroy);
int HideWin (WINDOW *w);
#define KillWin(w) DestroyWin(w, TRUE)
#define DropWin(w) DestroyWin(w, FALSE)
#define PushWin(w) RaiseWin(w)
#define BAR_HOR 01 /* окно имеет горизонтальный scroll bar */
#define BAR_VER 02 /* окно имеет вертикальный scroll bar */
#define DX 2 /* отступ от краев окна */
#define BARWIDTH 2 /* ширина scroll bar-а */
#define BARHEIGHT 1 /* высота */
/* Вычисление координат строки выбора в окне */
#define WY(title, y) ((y) + (title ? 3 : 1))
#define WX(x) ((x) + 1 + DX)
#define XEND(w,scrollok) (wcols(w)-((scrollok & BAR_VER) ? BARWIDTH+2 : 1))
void whorline (WINDOW *w, int y, int x1, int x2);
void wverline (WINDOW *w, int x, int y1, int y2);
void wbox (WINDOW *w, int x1, int y1, int x2, int y2);
void wborder (WINDOW *w);
void wboxerase (WINDOW *w, int x1, int y1, int x2, int y2);
void WinBorder (WINDOW *w, int bgattrib, int titleattrib, char *title,
int scrollok, int clear);
void WinScrollBar(WINDOW *w, int whichbar, int n, int among,
char *title, int bgattrib);
/* Спасение/восстановление позиции курсора */
typedef struct { int x, y; } Point;
#define SetPoint(p, yy, xx) { (p).x = (xx); (p).y = (yy);}
#define GetBack(p, w) wmove((w), (p).y, (p).x)
/* _______________________ файл w.c _____________________________ */
/* УПРАВЛЕНИЕ ПОРЯДКОМ ОКОН НА ЭКРАНЕ */
/* ______________________________________________________________ */
#include "w.h"
int botw = EOW, topw = EOW; /* нижнее и верхнее окна */
struct WindowList wins[MAXW]; /* список управляемых окон */
/* Прочесть символ из окна, проявив окно (если оно не спрятано) */
int WinGetch (WINDOW *win) { register n, dorefr = YES;
if(botw != EOW) for(n=botw; n != EOW; n=wins[n].next)
if(wins[n].w == win){
if(wins[n].busy == W_HIDDEN) dorefr = NO; /* спрятано */
break;
}
if( dorefr ) wrefresh (win); /* проявка */
else doupdate ();
for(;;){ n = wgetch (win); /* собственно чтение */
if( n == ctrl('A')){ RedrawScreen(); continue; }
return n;
}
}
/* Вычислить новое верхнее окно */
static void ComputeTopWin(){ register n;
if(botw == EOW) topw = EOW; /* список стал пуст */
else{ /* ищем самое верхнее видимое окно */
for(topw = EOW, n=botw; n != EOW; n=wins[n].next)
/* спрятанное окно не может быть верхним */
if( wins[n].busy == W_VISIBLE) topw = n;
/* Может совсем не оказаться видимых окон; тогда
* topw == EOW, хотя botw != EOW. Макрос TOPW предложит
* в качестве верхнего окна окно stdscr */
}
}
/* Виртуально перерисовать окна в списке в порядке снизу вверх */
static void WinRefresh(){ register nw;
/* чистый фон экрана */
touchwin(stdscr); wnoutrefresh(stdscr);
if(botw != EOW) for(nw=botw; nw != EOW; nw=wins[nw].next)
if(wins[nw].busy == W_VISIBLE){
touchwin(wins[nw].w); wnoutrefresh(wins[nw].w);
}
}
/* Исключить окно из списка не уничтожая ячейку */
static int WinDelList(WINDOW *w){ register nw, prev;
if(botw == EOW) return EOW; /* список пуст */
for(prev=EOW, nw=botw; nw != EOW; prev=nw, nw=wins[nw].next)
if(wins[nw].w == w){
if(prev == EOW) botw = wins[nw].next; /* было дно стопки */
else wins[prev].next = wins[nw].next;
return nw; /* номер ячейки в таблице окон */
}
return EOW; /* окна не было в списке */
}
/* Сделать окно верхним, если его еще не было в таблице - занести */
int RaiseWin(WINDOW *w){ int nw, n;
if((nw = WinDelList(w)) == EOW){ /* не было в списке */
for(nw=0; nw < MAXW; nw++) /* занести в таблицу */
if( !iswindow(nw)){ wins[nw].w = w; break; }
if(nw == MAXW){ beep(); return EOW; } /* слишком много окон */
}
/* поместить окно nw на вершину списка */
if(botw == EOW) botw = nw;
else{ for(n = botw; wins[n].next != EOW; n=wins[n].next);
wins[n].next = nw;
}
wins[nw].busy = W_VISIBLE; /* окно видимо, слот занят */
wins[topw = nw].next = EOW; WinRefresh(); return nw;
}
/* Удалить окно из списка и (возможно) уничтожить */
/* Окно при этом исчезнет с экрана */
void DestroyWin(WINDOW *w, int destroy){ int nw;
if((nw = WinDelList(w)) != EOW){ /* окно было в списке */
ComputeTopWin();
wins[nw].busy = W_FREE; /* ячейка свободна */
wins[nw].w = NULL;
}
if(destroy) delwin(w); /* уничтожить curses-ное окно */
WinRefresh();
}
void PopWin(){ KillWin(TOPW); }
/* Спрятать окно, и при этом сделать его самым нижним. */
int HideWin(WINDOW *w){ register nw, prev;
if(botw == EOW) return EOW; /* список пуст */
for(prev = EOW, nw = botw; nw != EOW; prev = nw, nw = wins[nw].next )
if(wins[nw].w == w){
wnoutrefresh(w); /* вместо untouchwin(w); */
wins[nw].busy = W_HIDDEN; /* спрятано */
if( nw != botw ){
wins[prev].next = wins[nw].next; /* удалить из списка */
wins[nw].next = botw; botw = nw; /* на дно стопки */
}
WinRefresh();
ComputeTopWin();
return nw;
}
return EOW; /* нет в списке */
}
/* _______________ ОФОРМИТЕЛЬСКИЕ РАБОТЫ _____________________ */
/* Нарисовать горизонтальную линию */
void whorline(WINDOW *w, int y, int x1, int x2){
for( ; x1 <= x2; x1++) mvwaddch(w, y, x1, HOR_LINE);
}
/* Нарисовать вертикальную линию */
void wverline(WINDOW *w, int x, int y1, int y2){
for( ; y1 <= y2; y1++) mvwaddch(w, y1, x, VER_LINE);
}
/* Нарисовать прямоугольную рамку */
void wbox(WINDOW *w, int x1, int y1, int x2, int y2){
whorline(w, y1, x1+1, x2-1);
whorline(w, y2, x1+1, x2-1);
wverline(w, x1, y1+1, y2-1);
wverline(w, x2, y1+1, y2-1);
/* Углы */
mvwaddch (w, y1, x1, UPPER_LEFT);
mvwaddch (w, y1, x2, UPPER_RIGHT);
mvwaddch (w, y2, x1, LOWER_LEFT);
/* Нижний правый угол нельзя занимать ! */
if(! (wbegx(w) + x2 == COLS-1 && wbegy(w) + y2 == LINES-1))
mvwaddch (w, y2, x2, LOWER_RIGHT);
}
/* Нарисовать рамку вокруг окна */
void wborder(WINDOW *w){ wbox(w, 0, 0, wcols(w)-1, wlines(w)-1); }
/* Очистить прямоугольную область в окне */
void wboxerase(WINDOW *w, int x1, int y1, int x2, int y2){
int x, y; register i, j; getyx(w, y, x);
for(i=y1; i <= y2; ++i) for(j=x1; j <= x2; j++)
mvwaddch(w, i, j, ' ');
wmove(w, y, x);
}
/* Нарисовать рамку и заголовок у окна */
void WinBorder (WINDOW *w, int bgattrib, int titleattrib, char *title,
int scrollok, int clear){
register x, y;
wattrset (w, bgattrib); /* задать цвет окна */
if(clear) werase(w); /* заполнить окно цветными пробелами */
wborder (w); /* нарисовать рамку вокруг окна */
if (title) { /* если есть заголовок ... */
for (x = 1; x < wcols (w) - 1; x++){
wattrset(w, bgattrib); mvwaddch (w, 2, x, HOR_LINE);
/* очистка поля заголовка */
wattrset(w, titleattrib); mvwaddch (w, 1, x, ' ');
}
wattrset(w, bgattrib);
mvwaddch (w, 2, 0, LEFT_JOIN);
mvwaddch (w, 2, wcols (w) - 1, RIGHT_JOIN);
wattrset (w, A_BOLD | titleattrib);
mvwaddstr(w, 1, (wcols(w)-strlen(title))/2, title);
wattrset (w, bgattrib);
}
if (scrollok & BAR_VER) { /* выделить столбец под scroll bar. */
int ystart = WY(title, 0), xend = XEND(w, scrollok);
for (y = ystart; y < wlines (w) - 1; y++)
mvwaddch (w, y, xend, VER_LINE);
mvwaddch (w, wlines (w)-1, xend, BOTTOM_JOIN);
mvwaddch (w, ystart-1, xend, TOP_JOIN);
}
/* затычка */
if(wcols(w)==COLS && wlines(w)==LINES){ wattrset(w, A_NORMAL);
mvwaddch(w, LINES-1, COLS-1, ' ');
}
wattrset (w, bgattrib);
}
/* Нарисовать вертикальный scroll bar (горизонтальный не сделан) */
/* Написано не очень аккуратно */
void WinScrollBar(WINDOW *w, int whichbar, int n, int among,
char *title, int bgattrib){
register y, i;
int starty = WY(title, 0);
int endy = wlines (w) - 1;
int x = XEND(w, whichbar) + 1;
int height = endy - starty ;
if(whichbar & BAR_VER){ /* вертикальный */
wattrset (w, A_NORMAL);
for (y = starty; y < endy; y++)
for (i = 0; i < BARWIDTH; i++)
mvwaddch (w, y, x + i, ' ');
y = starty;
if(among > 1) y += ((long) (height - BARHEIGHT) * n / (among - 1));
wattron(w, A_BOLD);
for (i = 0; i < BARWIDTH; i++)
mvwaddch (w, y, x + i, BOX);
wattrset(w, bgattrib | A_BOLD );
if( wcols(w) >= 10 )
mvwprintw(w, 0, wcols(w)-9, "%03d/%03d", n+1, among);
}
wattrset (w, bgattrib);
}
#ifdef TEST
main(){ WINDOW *w[5]; register i, y;
initscr(); /* запустить curses */
w[0] = newwin(16, 20, 4, 43); /* создать 5 окон */
w[1] = newwin(12, 20, 7, 34);
w[2] = newwin(6, 30, 3, 40);
w[3] = newwin(7, 35, 12, 38);
w[4] = newwin(6, 20, 11, 54);
for(i=0; i < 5; i++){
keypad (w[i], TRUE);
wattrset(w[i], A_REVERSE); werase(w[i]);
wborder (w[i]); mvwprintw(w[i], 1, 2, "Window %d", i);
RaiseWin(w[i]); /* сделать верхним окном */
}
noecho(); cbreak(); /* прозрачный ввод */
for(;botw != EOW;){ int c;
/* нарисовать порядок окон */
for(i=botw, y=0; y < 5; y++, i=(i==EOW ? EOW : wins[i].next))
mvprintw(8 - y, 5, i==EOW ? "~": "%d%c", i,
wins[i].busy == W_HIDDEN ? 'h':' ');
mvprintw(9, 5, "topw=%3d botw=%3d", topw, botw);
wnoutrefresh(stdscr); /* вирт. проявка этих цифр */
c = WinGetch(TOPW);
/* здесь происходит doupdate();
* и только в этот момент картинка проявляется */
switch(c){
case KEY_DC: PopWin(); break;
case KEY_IC: KillWin(BOTW); break;
case '0': case '1': case '2': case '3': case '4': case '5':
c -= '0'; if( !iswindow(c)){ beep(); break; }
RaiseWin(WIN(c)); break;
case 'D': KillWin(w[2]); break;
case 'h': HideWin(BOTW); break;
case 'H': HideWin(TOPW); break;
case ESC: goto out;
default: waddch(TOPW, c & 0377); break;
}
}
mvaddstr(LINES-2, 0, "Больше нет окон"); refresh();
out: echo(); nocbreak(); endwin();
}
#endif
© Copyright А. Богатырев, 1992-95
Си в UNIX
Назад | Содержание | Вперед