Пример 17



/* 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

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

Используются технологии uCoz