Пример 20

/* ______________________________________________________________ */ /* PULL_DOWN меню (меню-строка) */ /* _______________________ файл pull.h __________________________ */ typedef struct { Info info; /* строка в меню */ Menu *menu; /* связанное с ней вертикальное меню */ char *note; /* подсказка */ } PullInfo; typedef struct _Pull { /* Паспорт меню */ int nitems; /* количество элементов в меню */ PullInfo *items;/* элементы меню */ int *hotkeys; /* горячие ключи */ int key; /* клавиша, завершившая выбор */ int current; /* выбранный элемент */ int space; /* интервал между элементами меню */ int bg_attrib; /* цвет фона строки */ int sel_attrib; /* цвет выбранного элемента */ Point savep; void (*scrollBar) (struct _Pull *m, int n, int among); } PullMenu; #define PYBEG 0 /* строка, в которой размещается меню */ #define PM_BOLD I_DIR #define PM_NOSEL I_NOSEL #define PM_LFT M_LFT #define PM_RGT M_RGT #define PM_SET(m, i, flg) (m)->items[i].info.fl |= (flg) #define PM_CLR(m, i, flg) (m)->items[i].info.fl &= ~(flg) #define PM_TST(m, i, flg) ((m)->items[i].info.fl & (flg)) #define PM_ITEM(m, i) ((m)->items[i].info.s) #define PM_MENU(m, i) ((m)->items[i].menu) #define PM_NOTE(m, i) ((m)->items[i].note) #define COORD(m, i) ((m)->space * (i+1) + PullSum(m, i)) int PullInit(PullMenu *m); int PullSum(PullMenu *m, int n); void PullDraw(PullMenu *m); int PullShow(PullMenu *m); void PullHide(PullMenu *m); void PullDrawItem(PullMenu *m, int i, int reverse, int selection); void PullPointAt(PullMenu *m, int y); int PullHot(PullMenu *m, unsigned c); int PullPrev(PullMenu *m); int PullNext(PullMenu *m); int PullFirst(PullMenu *m); int PullThis(PullMenu *m); int PullUsualSelect(PullMenu *m); #define PullWin stdscr #define PM_REFUSED(m) ((m)->key < 0 || (m)->key == ESC ) /* _______________________ файл pull.c __________________________ */ #include "glob.h" #include "w.h" #include "menu.h" #include "pull.h" int PullSum(PullMenu *m, int n){ register i, total; int pos; for(i=0, total = 0; i < n; i++ ) total += strlen( MnuConvert(PM_ITEM(m, i), &pos )); return total; } /* Разметка меню. На входе: p->items массив элементов с M_HOT-метками и связанных меню. p->bg_attrib цвет фона строки. p->sel_attrib цвет выбранного элемента. Меню всегда размещается в окне stdscr (PullWin). */ int PullInit(PullMenu *m){ /* подменю не должны быть инициализированы, * т.к. все равно будут сдвинуты в другое место */ int total, pos; char *s; register i; m->key = m->current = 0; if(m->hotkeys){ free((char *) m->hotkeys); m->hotkeys = (int *) NULL; } /* подсчитать элементы меню */ m->nitems = 0; for( i=0, total = 0; PM_ITEM(m, i) != NULL; i++ ){ total += strlen(s = MnuConvert(PM_ITEM(m, i), &pos)); m->nitems++; } if( total > wcols(PullWin)){ /* меню слишком широкое */ err: beep(); return 0; } m->space = (wcols(PullWin) - total - 2) / (m->nitems + 1); if( m->space <= 0 ) goto err; /* разметить горячие клавиши */ if( m-> hotkeys = (int *) malloc( sizeof(int) * m->nitems )){ for(i=0; i < m->nitems; i++ ) m->hotkeys[i] = NOKEY; } for( i=0; i < m->nitems; i++ ){ if( PM_MENU(m,i)){ PM_MENU(m,i)->left = COORD(m, i) - 1; PM_MENU(m,i)->top = PYBEG + 1; PM_MENU(m,i)->bg_attrib = m-> bg_attrib; PM_MENU(m,i)->sel_attrib = m-> sel_attrib; if( PM_MENU(m,i)->win ) MnuDeinit( PM_MENU(m,i)); MnuInit( PM_MENU(m,i)); } if( m->hotkeys ){ s = MnuConvert(PM_ITEM(m, i), &pos); if( pos >= 0 ) m->hotkeys[i] = isupper(s[pos]) ? tolower(s[pos]) : s[pos]; } } keypad(PullWin, TRUE); return 1; } /* Проявить pull-down меню */ int PullShow(PullMenu *m){ register i; int first, last; first = last = (-1); for(i=0; i < m->nitems; i++ ){ PM_SET(m, i, PM_LFT | PM_RGT ); if( !PM_TST(m, i, PM_NOSEL)){ if( first < 0 ) first = i; last = i; } } if( first < 0 ) return (TOTAL_NOSEL); if(first == last ){ PM_CLR(m, first, PM_LFT | PM_RGT ); }else{ PM_CLR(m, first, PM_LFT); PM_CLR(m, last, PM_RGT); } wmove(PullWin, PYBEG, 0); wattrset(PullWin, m->bg_attrib); wclrtoeol(PullWin); PullDraw(m); return 1; } void PullDraw(PullMenu *m){ register i; for(i=0; i < m->nitems; i++ ) PullDrawItem(m, i, NO, NO); } /* Спрятать pull-down меню. Сама строка остается, подменю исчезают */ void PullHide(PullMenu *m){ register i; for(i=0; i < m->nitems; i++ ) if( PM_MENU(m, i)) MnuHide( PM_MENU(m, i)); PullDraw(m); } /* Нарисовать элемент меню */ void PullDrawItem(PullMenu *m, int i, int reverse, int selection){ int x, pos, hatch = PM_TST(m, i, PM_NOSEL ); char *s; x = COORD(m, i); s = MnuConvert( PM_ITEM(m, i), &pos ); wattrset(PullWin, (reverse ? m->sel_attrib : m->bg_attrib) | (hatch ? A_ITALICS : 0 )); /*mvwaddch(PullWin, PYBEG, x-1, reverse ? LEFT_TRIANG : ' ');*/ mvwaddstr(PullWin, PYBEG, x, s); /*waddch(PullWin, reverse ? RIGHT_TRIANG : ' ');*/ if( pos >= 0 ){ /* Hot key letter */ wattron(PullWin, A_BOLD); mvwaddch(PullWin, PYBEG, x + pos, s[pos]); } wmove (PullWin, PYBEG, x-1); SetPoint(m->savep, PYBEG, x-1); wattrset(PullWin, m->bg_attrib); } int PullPrev(PullMenu *m){ register y; for( y = m->current - 1; y >= 0; y-- ) if( !PM_TST(m, y, PM_NOSEL )) return y; return (-1); } int PullNext(PullMenu *m){ register y; for( y = m->current+1; y < m->nitems; y++ ) if( !PM_TST(m, y, PM_NOSEL)) return y; return (-1); } int PullFirst(PullMenu *m){ register y; for( y = 0; y < m->nitems; y++ ) if( !PM_TST(m, y, PM_NOSEL)) return y; return (-1); } int PullThis(PullMenu *m){ register y; if( m->current < 0 || m->current >= m->nitems ) return (-1); if( PM_TST(m, m->current, PM_NOSEL)) return (-1); return m->current; } int PullHot(PullMenu *m, unsigned c){ register y; if( m-> hotkeys == (int *) NULL ) return (-1); if( c < 0400 && isupper(c)) c = tolower(c); for( y=0; y < m->nitems; y++ ) if( c == m->hotkeys[y] && !PM_TST(m, y, PM_NOSEL)) return y; return (-1); } /* Указать на элемент n */ void PullPointAt( PullMenu *m, int n){ if( n < 0 || n >= m->nitems ) return ; /* error */ if( n != m->current ){ if( PM_MENU(m, m->current)) MnuHide( PM_MENU(m, m->current)); PullDrawItem( m, m->current, NO, YES ); } m -> current = n; PullDrawItem( m, n, YES, YES ); if( m->scrollBar ){ m->scrollBar( m, n, m->nitems ); GetBack(m->savep, PullWin); } } /* Выбор в меню */ int PullUsualSelect(PullMenu *m){ int autogo = NO, c, code, done = 0, snew, sel, reply = (-1); m->key = (-1); if((sel = PullThis(m)) < 0 ) if((sel = PullFirst(m)) < 0 ) return TOTAL_NOSEL; if( PullShow(m) < 0 ) return TOTAL_NOSEL; PullPointAt(m, sel); /* начальная позиция */ for(;;){ if( autogo ){ /* Автоматическая проявка подменю */ if( PM_MENU(m, m->current) == NULL) goto ask; code = MnuUsualSelect(PM_MENU(m, m->current), PM_TST(m, m->current, PM_LFT) | PM_TST(m, m->current, PM_RGT)); MnuHide(PM_MENU(m, m->current)); c = PM_MENU(m, m->current)->key; if(code == (-1)){ reply = (-1); goto out; } /* в подменю ничего нельзя выбрать */ if( code == TOTAL_NOSEL) goto ask; /* MnuUsualSelect выдает специальные коды для * сдвигов влево и вправо */ if( code == M_LEFT ) goto left; if( code == M_RIGHT ) goto right; reply = code; goto out; } else ask: c = WinGetch(PullWin); switch(c){ case KEY_LEFT: left: if((snew = PullPrev(m)) < 0 ) goto ask; goto mv; case KEY_RIGHT: right: if((snew = PullNext(m)) < 0 ) goto ask; goto mv; case ESC: reply = (-1); goto out; case '\r': case '\n': if( PM_MENU(m, m->current) == NULL){ reply = 0; goto out; } autogo = YES; break; default: if((snew = PullHot(m, c)) < 0 ) break; if( PM_MENU(m, snew) == NULL){ reply=0; done++; } autogo = YES; goto mv; } continue; mv: PullPointAt(m, sel = snew); if( done ) break; } out: wnoutrefresh(PullWin); PullHide(m); m->key = c; wattrset(PullWin, A_NORMAL); /* NOT bg_attrib */ return reply; /* номер элемента, выбранного в меню PM_MENU(m, m->current) */ }

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

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