return; /* incorrect */ if( x < 0 || x > width ) return; /* incorrect */ AID_LFT = MIN(LDX, maxlen); AID_RGT = MAX(0, MIN(maxlen, width-1 - LDX)); if( aid < *cur && x <= AID_LFT && oldshift > 0 ) goto Scroll; else if( aid > *cur && x >= AID_RGT && oldshift + width < maxlen ) goto Scroll; if( oldshift <= aid && aid < oldshift + width ) /* prokrutka ne nuzhna - simvol uzhe vidim */ goto Position; Scroll: if( aid >= *cur ) newshift = aid - AID_RGT; else newshift = aid - AID_LFT; if( newshift + width > maxlen || (len == maxlen && aid == len)) newshift = maxlen - width; if( newshift < 0 ) newshift = 0; if( newshift != oldshift ){ *shift = newshift; (*draw)(ptr); drawn = YES; } Position: if((x = aid - newshift) >= width && len != maxlen ) beep(); /* ERROR */ (*go)(ptr, x, !drawn ); *cur = aid; } /* Postavit' kursor na at-tyj simvol stroki */ void LePointAt( LineEdit *le, int at ){ /* at == len dopustimo */ if( at < 0 || at > le->len ) return; if( le->pos == at ) return; /* uzhe na meste */ LeCursorHide( le ); LeRoll( le, at, & le->pos, & le->shift, le->width, le->len, le->maxlen, LePoint, LeDraw, LINE_DX); le->pos = at; LeCursorShow( le ); } /* Narisovat' podhodyashchij scroll bar */ void LePoint( LineEdit *le, int x, int eraseOld ){ if(le->scrollBar) (*le->scrollBar)(le, BAR_HOR, x + le->shift, le->maxlen+1 ); GetBack( le->savep, le->win); } /* Narisovat' podhodyashchij scroll bar */ /* Vyzyvaj eto kazhdyj raz, kogda len izmenitsya */ void LeReport( LineEdit *le ){ if(le->scrollBar) le->scrollBar (le, BAR_VER, le->len, le->maxlen+1 ); GetBack( le->savep, le->win); } /* Narisovat' vidimuyu chast' stroki */ void LeDraw( LineEdit *le ){ LeDrawLine( le, 0); } /* Udalenie bukvy iz stroki */ void LeDelCh( LineEdit *le ){ if( le->len <= 0 || le->pos < 0 || le->pos >= le->len ) return; LeCursorHide( le ); (void) cdelete( le->line, le->pos ); le->len --; LeDrawLine( le, le->pos - le->shift ); LeReport( le ); } /* Vstavka bukvy v stroku */ void LeInsCh( LineEdit *le, int c ){ if( le->len < 0 || le->pos < 0 || le->pos > le->len ) return; LeCursorHide( le ); insert( le->line, le->pos, c ); le->len++; LeDrawLine( le, le->pos - le->shift ); LeReport( le ); } /* Zamena bukvy v stroke */ void LeRepCh( LineEdit *le, int c ){ if( le->len <= 0 || le->pos < 0 || le->pos >= le->len ) return; LeCursorHide( le ); le->line[ le->pos ] = c; LePutChar( le, le->pos - le-> shift ); } /* Vstavka podstroki v stroku redaktirovaniya */ int LeInsStr( LineEdit *le, char *s){ int len = le->len, slen = strlen(s); register i; if( len + slen > le->maxlen ) slen = le->maxlen - len; if( ! slen ) return 0; for( i=0; i < slen ; i ++ ) insert( le->line, le->pos+i, s[i] ); le->len += slen; LeCursorHide( le ); LeDrawLine( le, le->pos - le->shift ); LePointAt( le, le->pos + slen ); LeReport( le ); return slen ; } /* Stiranie slova */ int LeWerase( LineEdit *le, char *to ){ register i; register char *s = le->line; char c; if( to ) *to = '\0'; i = le->pos; if( s[i] == ' ' || s[i] == '\0' ){ /* najti konec slova */ for( --i; i >= 0 ; i-- ) if( s[i] != ' ' ) break; if( i < 0 || le->len == 0 ){ beep(); return NO; } } /* najti nachalo slova */ for( ; i >= 0 && s[i] != ' ' ; i-- ); i++; /* i < 0 || s[i] == ' ' */ LeCursorHide( le ); LePointAt( le, i ); while( s[i] != ' ' && s[i] != '\0' ){ c = cdelete( s, i ); if( to ) *to++ = c; le->len --; } /* udalit' probely posle slova */ while( s[i] == ' ' ){ c = cdelete( s, i ); le->len --; } if( to ) *to = '\0'; LeDrawLine( le, i - le->shift ); LeReport( le ); return YES; } /* Redaktor stroki le->line chto redaktirovat'. le->maxlen maks. dlina stroki. le->win okno, soderzhashchee pole redaktirovaniya. le->width shirina polya redaktirovaniya. le->top koord-ty polya redaktirovaniya le->left v okne win. le->insert = YES rezhim vstavki. le->nc = YES stirat' stroku pri pervom nazhatii. le->histIn vhodnaya istoriya ili NULL. le->histOut vyhodnaya istoriya ili NULL. le->showMe funkciya proyavki okna ili NULL. le->hideMe funkciya spryatyvaniya okna ili NULL. le->hitkeys special'nye klavishi ili NULL. le->handler obrabotchik special'nyh klavish ili NULL. le->scrollBar risovalka scroll bar-ov ili NULL. le->posMe ustanovka pozicii v stroke pri vhode. le->bg_attrib cvet polya. le->fr_attrib cvet nezapolnennoj chasti polya. le->wl_attrib cvet kraev polya pri prodolzhenii. le->sel_attrib cvet simvola pod kursorom. */ int LeEdit( LineEdit *le ){ int c; int nchar = 0; /* schetchik nazhatyh klavish */ Info *inf; /* proyavit' okno */ if( le->showMe ) if( (*le->showMe) (le) <= 0 ) return (-1); if( !le->win ) return (le->key = -1); Again: le -> pos = 0; le -> len = strlen( le->line ); le -> shift = 0; le -> cursorOn = NO; le->key = (-1); LeDraw( le ); if(le->posMe) (*le->posMe)(le); LePointAt(le, le->pos ); LePoint( le, le->pos - le->shift, NO ); LeReport( le ); for (;;) { LeCursorShow( le ); c = WinGetch(le->win); /* prochest' simvol s klaviatury */ nchar++; /* chislo nazhatyh klavish */ INP: if( le->hitkeys && le->handler ){ HandlerReply reply; if( is_in(c, le->hitkeys)){ /* specsimvol ? */ c = (*le->handler)(le, c, &reply); /* Vosstanovit' scroll bars */ LePoint( le, le->pos - le->shift, NO ); LeReport( le ); switch( reply ){ case HANDLER_CONTINUE: continue; case HANDLER_NEWCHAR: goto INP; case HANDLER_OUT: goto out; case HANDLER_AGAIN: /* reset */ LeCursorHide(le); goto Again; case HANDLER_SWITCH: default: break; /* goto switch(c) */ } } } sw: switch (c) { case KEY_RIGHT: /* kursor vpravo */ if (le->pos != le->len && le->len > 0) LePointAt( le, le->pos + 1); break; case KEY_LEFT: /* kursor vlevo */ if (le->pos > 0) LePointAt(le, le->pos - 1); break; case '\t': /* tabulyaciya vpravo */ if (le->pos + 8 > le->len) LePointAt(le, le->len); else LePointAt(le, le->pos + 8); break; case KEY_BACKTAB: /* tabulyaciya vlevo */ case ctrl('X'): if( le->pos - 8 < 0 ) LePointAt(le, 0); else LePointAt(le, le->pos - 8 ); break; case KEY_HOME: /* v nachalo stroki */ LePointAt(le, 0); break; case KEY_END: /* v konec stroki KEY_LL */ if( le->len > 0 ) LePointAt(le, le->len); break; case 0177: /* steret' simvol pered kursorom */ case KEY_BACKSPACE: case '\b': if (le->pos == 0) break; LePointAt(le, le->pos - 1); /* nalevo */ /* i provalit'sya v DC ... */ case KEY_F (6): /* steret' simvol nad kursorom */ case KEY_DC: if (! le->len || le->pos == le->len) break; LeDelCh(le); break; case KEY_UP: /* vyzvat' istoriyu */ case KEY_DOWN: case KEY_NPAGE: case KEY_PPAGE: case KEY_F(4): if( ! le->histIn ) break; /* inache pozvat' istoriyu */ inf = HistSelect( le->histIn, wbegx(le->win) + le->pos - le->shift + 2, le->top + 1); if( inf == (Info *) NULL ) break; LeCursorHide( le ); strncpy( le->line, inf->s, le->maxlen ); goto Again; out: case '\r': case '\n': case ESC: /* vvod zavershen - vyjti */ LeCursorHide( le ); if( c != ESC && le->histOut && *le->line ) /* zapomnit' stroku v istoriyu */ HistAdd( le->histOut, le->line, 0); if( le->hideMe ) /* spryatat' okno */ (*le->hideMe)(le); return (le->key = c); case KEY_F (8): /* steret' vsyu stroku */ case ctrl('U'): le->line[0] = '\0'; le->len = le->pos = le->shift = 0; LeCursorHide( le ); LeReport( le ); goto REWRITE; case KEY_F(0): /* F10: steret' do konca stroki */ if( le->pos == le->len ) break; le->line[ le->pos ] = '\0'; le->len = strlen( le->line ); LeCursorHide( le ); LeDrawLine( le, le->pos - le->shift ); LeReport( le ); break; case ctrl('W'): /* steret' slovo */ LeWerase( le, NULL ); break; case ctrl('A'): /* pererisovka */ LeCursorHide(le); /* RedrawScreen(); */ REWRITE: LeDraw(le); break; case KEY_F(7): /* pereklyuchit' rezhim vstavki/zameny */ le->insert = ! le->insert; LeCursorHide( le ); break; #ifndef M_UNIX case ctrl('V'): /* vvod zaekranirovannogo simvola */ nchar--; c = WinGetch(le->win); nchar++; if( c >= 0400 ) goto sw; goto Input; #endif case 0: break; default: /* vvod obychnogo simvola */ if (c >= 0400 || ! isprint(c)) break; Input: if( le->nc && nchar == 1 && le->insert && /*le->pos == 0 &&*/ le->len != 0 ){ /* esli eto pervaya nazhataya knopka, to /* udalit' vse soderzhimoe stroki /* i zamenit' ee nazhatoj bukvoj */ le->shift = 0; le->len = le->pos = 1; le->line[0] = c; le->line[1] = '\0'; LeCursorHide( le ); LeReport( le ); goto REWRITE; } if (!le->insert) { /* REPLACE - rezhim zameny */ if (le->pos == le->len) goto AddChar; /* vremennyj INSERT */ LeRepCh( le, c ); LePointAt( le, le->pos + 1 ); } else { /* INSERT - rezhim vstavki */ AddChar: if( le->len >= le->maxlen ){ beep(); /* stroka perepolnena */ break; } LeInsCh( le, c ); LePointAt( le, le->pos + 1 ); } /* endif */ } /* endswitch */ } /* endfor */ } /* endfunc */ /* Primer 22 */ /* ______________________________________________________________ */ /* PRYAMOUGOLXNAYA TABLICA-MENYU */ /* _______________________ fajl table.h _________________________ */ typedef struct _Table { /* Pasport tablicy */ int nitems; /* kolichestvo elementov v tablice */ Info *items; /* massiv elementov */ char *fmt; /* format vyvoda */ int key; /* knopka, zavershivshaya vybor v tablice */ int current; /* nomer vybrannogo elementa */ int shift; /* chislo elementov pered oknom */ WINDOW *win; /* okno v kotorom razmeshchena tablica */ int left, top, height, width; /* razmery i raspolozhenie tablicy v okne */ int space; /* interval mezhdu kolonkami */ int elen; /* maks. shirina kolonki */ int tcols; /* chislo kolonok v tablice */ int cols; /* chislo kolonok v vidimoj chasti tablicy */ int cutpos; /* poziciya dlya obrubaniya slishkom dlinnyh strok */ int scrollok; /* rolliruetsya ? */ int exposed; /* narisovana ? */ int elems; /* tekushchee chislo el-tov v podokne */ int maxelems; /* maksimal'noe chislo el-tov v podokne */ int maxshift; /* maksimal'nyj sdvig */ int bg_attrib, sel_attrib; /* cvet fona i vybrannogo elementa */ Point savep; /* Funkcii proyavki/spryatyvaniya okna */ int (*showMe)(struct _Table *tbl); void (*hideMe)(struct _Table *tbl); void (*scrollBar)(struct _Table *tbl, int whichbar, int n, int among); /* Obrabotchik special'nyh klavish */ int *hitkeys; int (*handler)(struct _Table *tbl, int c, HandlerReply *reply); } Table; #define T_BOLD M_BOLD #define T_NOSEL I_NOSEL #define T_HATCH M_HATCH #define T_LABEL M_LABEL #define T_SET(m, i, flg) (((m)->items)[i]).fl |= (flg) #define T_CLR(m, i, flg) (((m)->items)[i]).fl &= ~(flg) #define T_TST(m, i, flg) ((((m)->items)[i]).fl & (flg)) #define T_ITEM(m, i) ((((m)->items)[i]).s) /* Format 'd' nizhe vstavlen lish' dlya tekushchego sostoyaniya ispol'zovaniya * formatov v nashem proekte: */ #define T_ITEMF(m, i, cut) \ ((m)->fmt && *(m)->fmt != 'd' ? \ TblConvert(T_ITEM((m), i), (m)->fmt, (cut)) : T_ITEM((m), i)) #define T_VISIBLE(tbl, new) ((tbl)->exposed == YES && \ (new) >= (tbl)->shift && (new) < (tbl)->shift + (tbl)->elems) #define TLABSIZE 2 /* shirina polya metok */ #define T_REFUSED(t) ((t)->key < 0 || (t)->key == ESC ) int TblCount( Table *tbl ); void TblInit( Table *tbl, int forcedOneColumn ); void TblChkCur ( Table *tbl ); int TblChkShift( Table *tbl ); void TblChk ( Table *tbl ); char *TblConvert( char *s, char *fmt, int cutpos ); void TblPointAt ( Table *tbl, int snew ); void TblPoint ( Table *tbl, int snew, int eraseOld ); void TblDraw ( Table *tbl ); void TblDrawItem( Table *tbl, int at, int reverse, int selection); void TblBox ( Table *tbl, int at, int reverse, int hatched, int width, int axl, int axi, int ay); int TblClear( Table *tbl ); int TblPlaceByName( Table *tbl, char *p ); void TblReport( Table *tbl ); void TblTag ( Table *tbl, int at, int flag); void TblUntag( Table *tbl, int at, int flag); void TblRetag( Table *tbl, int at, int flag); void TblTagAll( Table *tbl, char *pattern, int flag ); void TblUntagAll( Table *tbl, char *pattern, int flag ); int TblUsualSelect( Table *tbl ); /* _______________________ fajl table.c _________________________ */ #include "w.h" #include "glob.h" #include "menu.h" #include "table.h" extern char STRING_BUFFER[MAXLEN]; /* imported from menu.c */ /* nado ukazat' razmer, chtob rabotal sizeof(STRING_BUFFER) */ /* Pereformatirovat' stroku po formatu fmt dlya vydachi v tablicu. * Poka predlozhena prostejshaya interpretaciya. */ char *TblConvert( char *s, char *fmt, int cutpos ){ if( fmt && *fmt == 'd'){ register i, j, len; char *p = strrchr(s, '.'); if((len = strlen(s)) < DIR_SIZE && *s != '.' && p ){ int sufxlen = strlen(p); for(i=0; i < len - sufxlen ; ++i) STRING_BUFFER[i] = s[i]; for(; i < DIR_SIZE - sufxlen; ++i) STRING_BUFFER[i] = ' '; for(j=0; i < DIR_SIZE; j++, ++i) STRING_BUFFER[i] = p[j]; STRING_BUFFER[i] = '\0'; } else strcpy(STRING_BUFFER, s); if(cutpos > 0 && cutpos < sizeof(STRING_BUFFER)) STRING_BUFFER[cutpos] = '\0'; } else { /* bez formata, tol'ko obrubanie */ if( cutpos <= 0 ) cutpos = 32000; /* Obrubanie vyklyucheno */ strncpy(STRING_BUFFER, s, MIN(sizeof(STRING_BUFFER) - 1, cutpos)); } return STRING_BUFFER; } /* Obrubit' s do dliny cutpos bukv */ char *TblCut( char *s, int cutpos ){ if( cutpos <= 0 ) return s; strncpy(STRING_BUFFER, s, MIN(sizeof(STRING_BUFFER) - 1, cutpos)); return STRING_BUFFER; } /* Podschet elementov tablicy i shiriny stolbca */ int TblCount( Table *tbl ){ register i, L, LL; char *s; L = i = 0; if( tbl->items) while((s = T_ITEM(tbl, i)) != NULL ){ if( tbl->fmt ) s = TblConvert(s, tbl->fmt, 0); LL = strlen(s); if( LL > L ) L = LL; i++; } tbl->nitems = i; return L; } /* Razmetka tablicy. Na vhode: t->items Massiv dannyh, pokazyvaemyj v menyu. t->exposed = NO Tablica uzhe narisovana ? t->fmt Format strok, vyvodimyh v tablicu. t->win Okno dlya razmeshcheniya tablicy. t->showMe Funkciya proyavki okna. t->hideMe Funkciya upryatyvaniya okna. t->hitkeys Special'nye klavishi []. Konec -1. t->handler Obrabotchik ili NULL. t->width SHirina polya tablicy. t->height Vysota polya tablicy. t->left Levyj kraj tablicy v okne. t->top Verhnij kraj tablicy v okne. t->scrollBar Funkciya risovaniya scroll-bar-a ili NULL. t->bg_attrib Cvet fona (== cvetu fona okna). t->sel_attrib Cvet vybrannogo elementa. forcedOneColumn == YES delaet tablicu v 1 kolonku. */ void TblInit( Table *tbl, int forcedOneColumn ){ int mlen = TblCount( tbl ); /* samyj shirokij element tablicy */ /* usech' do shiriny tablicy */ if( mlen > tbl->width || forcedOneColumn ) mlen = tbl->width; /* slishkom shiroko */ /* shirina stolbca tablicy = shirina elementa + pole metok + razdelitel' */ tbl->elen = mlen + TLABSIZE + 1; /* #####stroka_element| */ /* metki element 1 */ /* chislo stolbcov vo vsej tablice */ tbl->tcols = (tbl->nitems + tbl->height - 1) / tbl->height; /* chislo stolbcov, vidimyh cherez okno (+1 dlya oshibok okrugleniya) */ tbl->cols = tbl->width / (tbl->elen + 1); if( tbl->cols == 0 ){ /* slishkom shirokaya tablica */ tbl->cols = 1; /* tablica v odnu kolonku */ tbl->elen = tbl->width - 2; mlen = tbl->elen - (TLABSIZE + 1); tbl->cutpos = mlen; /* i pridetsya obrubat' stroki */ } else tbl->cutpos = 0; /* bez obrubaniya */ tbl->cols = MIN(tbl->cols, tbl->tcols); /* interval mezhdu kolonkami */ tbl->space = (tbl->width - tbl->cols * tbl->elen)/(tbl->cols+1); if( tbl->space < 0 ){ beep(); tbl->space = 0; } /* skol'ko elementov umeshchaetsya v okno */ tbl->maxelems = tbl-> cols * tbl->height; tbl->maxshift = (tbl->tcols * tbl->height) - tbl->maxelems; if( tbl->maxshift < 0 ) tbl->maxshift = 0; /* trebuetsya li rollirovanie tablicy cherez okno */ tbl->scrollok = (tbl->nitems > tbl->maxelems); tbl->elems = tbl->shift = tbl->current = 0; /* poka */ tbl->exposed = NO; /* tablica eshche ne narisovana */ tbl->key = (-1); } /* Proverit' korrektnost' tekushchej pozicii */ void TblChkCur( Table *tbl ){ if( tbl->current >= tbl->nitems ) tbl->current = tbl->nitems - 1; if( tbl->current < 0 ) tbl->current = 0; } /* Proverit' korrektnost' sdviga (chisla elementov PERED oknom) */ int TblChkShift( Table *tbl ){ register int oldshift = tbl->shift; /* v kolonke dolzhno byt' vidno dostatochno mnogo elementov */ if( tbl->cols == 1 && /* tablica v 1 kolonku */ tbl->tcols > 1 && /* no vsego v nej ne odna kolonka */ tbl->nitems - tbl->shift < tbl->height / 2 + 1 ) tbl->shift = tbl->nitems - (tbl->height/2 + 1); if( tbl->shift > tbl->maxshift ) tbl->shift = tbl->maxshift; if( tbl->shift < 0 ) tbl->shift = 0; return tbl->shift != oldshift; /* skorrektirovano ? */ } /* Proverit' korrektnost' parametrov tablicy */ void TblChk( Table *tbl ){ again: TblChkCur( tbl ); TblChkShift( tbl ); if( tbl -> maxelems ){ if( tbl -> current >= tbl->shift + tbl->maxelems ){ tbl->shift = tbl->current - (tbl->maxelems - 1); goto again; } if( tbl->current < tbl->shift ){ tbl->shift = tbl->current; goto again; } } } /* Ukazat' na snew-tyj element spiska, pererisovat' kartinku */ void TblPointAt( Table *tbl, int snew ){ int curCol; /* tekushchij stolbec vsej tablicy (dlya current) */ int newCol; /* nuzhnyj stolbec tablicy (dlya snew) */ int colw; /* nuzhnyj stolbec OKNA (dlya snew) */ int gap; /* zazor */ int newshift = tbl->shift; /* novyj sdvig okna ot nachala massiva */ int drawn = NO; /* tablica celikom pererisovana ? */ /* PRoverit' korrektnost' nomera zhelaemogo elementa */ if( snew < 0 ) snew = 0; if( snew >= tbl->nitems ) snew = tbl->nitems - 1; if( tbl->current == snew && tbl->exposed == YES) return; /* uzhe stoim na trebuemom elemente */ #define WANTINC 1 #define WANTDEC (tbl->cols-1-WANTINC) gap = (tbl->height - (tbl->shift % tbl->height)) % tbl->height; /* gap - eto smeshchenie, kotoroe prevrashchaet stroguyu postolbcovuyu strukturu --0-- --3-- --1-- --4-- --2-- --5-- v sdvinutuyu strukturu ____ |------ gap=2___/ pusto g0 --1-- g3 | --4-- g6 .... \____pusto g1 --2-- g4 | --5-- g7 --0-- g2 --3-- g5 | --6-- g8 |------ shift=4 */ /* operaciya prokrutki dannyh cherez tablicu: TblRoll() _________________*/ /* |lement uzhe viden v tekushchem okne ? */ /* Parametr elems vychislyaetsya v TblDraw() */ if( T_VISIBLE(tbl, snew)) goto ThisWindow; /* smooth scrolling (gladkoe rollirovanie) */ if( snew == tbl->shift + tbl->elems && /* element neposredstvenno sleduyushchij ZA oknom */ tbl->current == tbl->shift + tbl->elems - 1 /* kursor stoit v nizhnem pravom uglu okna */ ){ newshift++; gap--; if ( gap < 0 ) gap = tbl->height - 1 ; goto do_this; } if( snew == tbl->shift - 1 && /* element neposredstvenno stoyashchij PERED oknom */ tbl->current == tbl->shift /* i kursor stoit v verhnem levom uglu okna tablicy */ ){ newshift --; gap = (gap + 1) % tbl->height; goto do_this; } /* jump scrolling (prokrutka skachkom) */ curCol = (tbl->current+gap) / tbl->height; newCol = (snew +gap) / tbl->height; if( tbl->cols > 1 ){ if( newCol > curCol ) colw = WANTINC; else colw = WANTDEC; } else colw = 0; newshift = (newCol - colw) * tbl->height - gap ; do_this: if( tbl->shift != newshift || tbl->exposed == NO){ tbl->shift = newshift; TblChkShift( tbl ); /* >= 0 && <= max */ TblDraw( tbl ); /* pererisovat' vse okno s novogo mesta */ drawn = YES; /* pererisovano celikom */ } ThisWindow: /* postavit' kursor v tekushchem okne bez pererisovki okna */ TblPoint( tbl, snew, !drawn ); /* tbl->current = snew; sdelaetsya v TblPoint() */ } /* Postavit' kursor na element v tekushchem okne */ void TblPoint ( Table *tbl, int snew, int eraseOld ){ if( ! T_VISIBLE(tbl, snew)){ beep(); /* ERROR !!! */ return; } if( eraseOld && tbl->current != snew ) TblDrawItem( tbl, tbl->current, NO, YES ); TblDrawItem( tbl, snew, YES, YES ); tbl->current = snew; TblReport( tbl ); } /* Narisovat' scroll bar v nuzhnoj pozicii. Krome togo, * v etu funkciyu mozhno vklyuchit' i drugie dejstviya, naprimer * vydachu imeni T_ITEM(tbl, tbl->current) na ramke okna. */ void TblReport( Table *tbl ){ if ( tbl->scrollBar ) (*tbl->scrollBar)( tbl, BAR_VER|BAR_HOR, tbl->current, tbl->nitems); GetBack( tbl->savep, tbl->win ); /* kursor na mesto ! */ } /* Pererisovat' vse okno tablicy */ void TblDraw( Table *tbl ){ register next; /* chislo elementov v tablice (mozhet ostat'sya nezanyatoe * mesto v pravoj nizhnej chasti okna */ tbl->elems = MIN(tbl->nitems - tbl->shift, tbl->maxelems ); for( next = 0; next < tbl->maxelems; next++ ) TblDrawItem(tbl, next + tbl->shift, NO, tbl->scrollok ? YES : NO); tbl->exposed = YES; /* okno izobrazheno */ } /* Narisovat' element tablicy */ void TblDrawItem( Table *tbl, int at, int reverse, int selection){ register WINDOW *w = tbl->win; int pos; char *s; int hatch, bold, label, under; int ax, axl, ay, column; if( at >= 0 && at < tbl->nitems ){ s = T_ITEM( tbl, at ); if( tbl->fmt ) s = TblConvert(s, tbl->fmt, tbl->cutpos); else if( tbl->cutpos > 0 ) s = TblCut(s, tbl->cutpos); /* vydeleniya */ hatch = T_TST( tbl, at, T_HATCH ); bold = T_TST( tbl, at, T_BOLD ); label = T_TST( tbl, at, T_LABEL ); under = T_TST( tbl, at, I_EXE ); } else { s = "~"; label = hatch = bold = under = NO; } at -= tbl->shift; /* koordinatu v spiske perevesti v koord. okna */ ay = tbl->top + at % tbl->height; column = at / tbl->height; /* nachalo polya metok */ axl = tbl->left + tbl->space + column * (tbl->space + tbl->elen); /* nachalo stroki-elementa */ ax = axl + TLABSIZE; if(selection) TblBox( tbl, at, reverse, reverse && hatch, strlen(s), axl, ax, ay ); wattrset (w, reverse ? tbl->sel_attrib : tbl->bg_attrib); if( hatch ) wattron(w, A_ITALICS); if( bold ) wattron(w, A_BOLD); if( under ) wattron(w, A_UNDERLINE); mvwaddstr(w, ay, ax, s); wattrset(w, tbl->bg_attrib | (bold ? A_BOLD:0)); if( label ) mvwaddch(w, ay, axl, LABEL); if( under ){ wattron(w, A_BOLD); mvwaddch(w, ay, axl+1, BOX_HATCHED);} wattrset(w, tbl->bg_attrib); if( column != tbl->cols-1 ) /* ne poslednij stolbec */ mvwaddch(w, ay, axl+tbl->elen-1 + (tbl->space+1)/2, VER_LINE); wmove(w, ay, ax-1); /* kursor pered nachalom stroki */ SetPoint(tbl->savep, ay, ax-1); /* zapomnit' koordinaty kursora */ } /* Zachistit' oblast' okna dlya risovaniya elementa tablicy */ void TblBox(Table *tbl, int at, int reverse, int hatched, int width, int axl, int axi, int ay){ register WINDOW *w = tbl->win; int len = tbl->elen; wattrset (w, tbl->bg_attrib); wboxerase(w, axl, ay, axl+len-1, ay); wattrset (w, reverse ? tbl->sel_attrib : tbl->bg_attrib); /* esli nizhe zadat' axl+len+1, to podsvechennyj * pryamougol'nik budet fiksirovannogo razmera */ wboxerase(w, axi, ay, axl+width-1, ay); wattrset (w, tbl->bg_attrib); } /* Zachistit' pryamougol'nuyu rabochuyu oblast' okna tbl->win, * v kotoroj budet izobrazhat'sya tablica. * |ta funkciya nigde ne vyzyvaetsya YAVNO, poetomu VY dolzhny * vyzyvat' ee sami posle kazhdogo TblInit() - * dlya etogo udobno pomestit' ee v demon (*showMe)(); */ int TblClear( Table *tbl ){ tbl->exposed = NO; tbl->elems = 0; /* |to vsegda proishodit pri exposed:= NO */ wboxerase( tbl->win, tbl->left, tbl->top, tbl->left + tbl->width - 1, tbl->top + tbl->height - 1); return 1; } /* Pometit' element v tablice */ void TblTag( Table *tbl, int at, int flag){ if( T_TST(tbl, at, flag)) return; T_SET(tbl, at, flag); if( T_VISIBLE(tbl, at)) TblDrawItem(tbl, at, tbl->current == at ? YES:NO, YES ); } /* Snyat' pometku s elementa tablicy */ void TblUntag( Table *tbl, int at, int flag){ if( ! T_TST(tbl, at, flag)) return; T_CLR(tbl, at, flag); if( T_VISIBLE(tbl, at)) TblDrawItem(tbl, at, tbl->current == at ? YES:NO, YES ); } /* Izmenit' pometku elementa tablicy */ void TblRetag( Table *tbl, int at, int flag){ if( T_TST(tbl, at, flag)) T_CLR(tbl, at, flag); else T_SET(tbl, at, flag); if( T_VISIBLE(tbl, at)) TblDrawItem(tbl, at, tbl->current == at ? YES:NO, YES ); } /* Ispol'zuetsya v match() dlya vydachi soobshcheniya ob oshibke */ void TblMatchErr(){} /* Pometit' elementy, ch'i imena udovletvoryayut shablonu */ void TblTagAll( Table *tbl, char *pattern, int flag ){ register i; for(i=0; i < tbl->nitems; i++) if( !T_TST(tbl, i, I_DIR) && match( T_ITEMF(tbl, i, 0), pattern)) TblTag( tbl, i, flag ); } /* Snyat' pometki s elementov po shablonu imeni */ void TblUntagAll( Table *tbl, char *pattern, int flag ){ register i; for(i=0; i < tbl->nitems; i++) if( match( T_ITEMF(tbl, i, 0), pattern)) TblUntag( tbl, i, flag ); } /* Ukazat' na element po shablonu ego imeni */ int TblPlaceByName( Table *tbl, char *p ){ register i; char *s; for( i=0; i < tbl->nitems; i++ ){ s = T_ITEMF(tbl, i, 0); if( match( s, p )){ if( tbl->exposed == NO ){ /* Zadat' nekorrektnyj shift, * chtoby okno polnost'yu pererisovalos' */ tbl->shift = tbl->nitems+1; tbl->elems = 0; } TblPointAt( tbl, i ); return i; } } return (-1); } /* Peremeshchenie po tablice naborom pervyh bukv nazvaniya elementa */ static int TblTrack( Table *tbl, int c){ char *s; register i; int from; /* s kakogo elementa nachinat' poisk */ int found = 0; /* skol'ko bylo najdeno */ int plength = 0; int more = 0; char pattern[20]; if( c >= 0400 || iscntrl(c)){ beep(); return 0; } AddCh: from = 0; pattern[plength] = c; pattern[plength+1] = '*'; pattern[plength+2] = '\0'; plength++; More: for(i = from; i < tbl->nitems; i++){ s = T_ITEMF(tbl, i, 0); if( match(s, pattern)){ ++found; from = i+1; TblPointAt( tbl, i ); c = WinGetch( tbl->win ); switch(c){ case '\t': /* find next matching */ more++; goto More; case KEY_BACKSPACE: case '\177': case '\b': if( plength > 1 ){ plength--; pattern[plength] = '*'; pattern[plength+1] = '\0'; from = 0; more++; goto More; } else goto out; default: if( c >= 0400 || iscntrl(c)) return c; if( plength >= sizeof pattern - 2 ) goto out; goto AddCh; } } } /* ne najdeno */ if(more && found){ /* net BOLXSHE podhodyashchih, no VOOBSHCHE - est' */ beep(); more = found = from = 0; goto More; } out: beep(); return 0; } /* Vybor v tablice */ int TblUsualSelect( Table *tbl ){ int c, want; tbl->key = (-1); if( tbl->items == NULL || tbl->nitems <= 0 ) return TOTAL_NOSEL; TblChk( tbl ); if( tbl->showMe ) if((*tbl->showMe)(tbl) <= 0 ) return (-1); if( !tbl->win ) return TOTAL_NOSEL; if( tbl->exposed == NO ){ TblDraw ( tbl ); } /* Ukazat' tekushchij element */ TblPoint( tbl, tbl->current, NO); TblReport( tbl ); for( ;; ){ c = WinGetch(tbl->win); INP: if( tbl->hitkeys && tbl->handler ){ HandlerReply reply; if( is_in(c, tbl->hitkeys)){ c = (*tbl->handler)(tbl, c, &reply); TblReport( tbl ); /* restore scroll bar */ switch( reply ){ case HANDLER_CONTINUE: continue; case HANDLER_NEWCHAR: goto INP; case HANDLER_OUT: goto out; case HANDLER_SWITCH: default: break; /* goto switch(c) */ } } } sw: switch( c ){ case KEY_LEFT: want = tbl->current - tbl->height; goto mv; case KEY_RIGHT: want = tbl->current + tbl->height; goto mv; case KEY_UP: want = tbl->current - 1; goto mv; case KEY_DOWN: next: want = tbl->current + 1; goto mv; case KEY_HOME: want = 0; goto mv; case KEY_END: want = tbl->nitems - 1; goto mv; case KEY_NPAGE: want = tbl->current + tbl->elems; goto mv; case KEY_PPAGE: want = tbl->current - tbl->elems; goto mv; case KEY_IC: if( T_TST(tbl, tbl->current, T_LABEL )) T_CLR(tbl, tbl->current, T_LABEL ); else T_SET(tbl, tbl->current, T_LABEL); if( tbl->current == tbl->nitems - 1 /* LAST */){ TblPoint(tbl, tbl->current, NO ); break; } TblPointAt(tbl, tbl->current ); /* if not goto next; * but break; * then use * TblPoint(tbl, tbl->current, NO); * here */ goto next; case KEY_DC: if( T_TST(tbl, tbl->current, T_HATCH )) T_CLR(tbl, tbl->current, T_HATCH ); else T_SET(tbl, tbl->current, T_HATCH); if( tbl->current == tbl->nitems - 1 /* LAST */){ TblPoint(tbl, tbl->current, NO ); break; } TblPointAt(tbl, tbl->current ); goto next; case ESC: case '\r': case '\n': goto out; case 0: break; default: c = TblTrack(tbl, c); if( c ) goto INP; break; } continue; mv: TblPointAt( tbl, want ); } out: wnoutrefresh( tbl->win ); if( tbl->hideMe ) (*tbl->hideMe)(tbl); return ((tbl->key = c) == ESC ? -1 : tbl->current ); } # Primer 23 - simple visual shell. # UNIX commander ######################################################################### # |to fajl Makefile dlya proekta uxcom - prostogo menyu-orientirovannogo # ekrannogo interfejsa dlya perehodov po fajlovoj sisteme. # Klyuch -Ikatalog ukazyvaet iz kakogo kataloga dolzhny brat'sya # include-fajly, podklyuchaemye po #include "imyaFajla". # Proekt sostoit iz neskol'kih fajlov: # Primer 17, Primer 18, Primer 19, Primer 21, Primer 23 i drugih. # # + Left Right _Commands Tools Sorttype + # | /usr/a+---------------------008/013-+ | # +-----------------| Glavnoe menyu |---+--+ # | .. +--------------------------+--+ | | # | .BAD | Current directory | | | | # | .contents.m| Root directory | | |##| # | DUMP | Menus | | | | # | Makefile +--------------------------+ | | | # | PLAN | Help | | | | # | _points | Unimplemented | | | | # | table | Change sorttype |##| | | # | #unbold | _Look directory history | | | | # | #uxcom +--------------------------+ | | | # | x.++ | Quit | | | | # | 00 +--------------------------+ | | | # | 11 | Redraw screen | | | | # | LOOP_p +--------------------------+--+ | | # | LOOP_q .c | etc | | # | LOOP_strt .c | install | | # +-------------------------+-------------------------+ | # | points 165 -r--r-- | .cshrc 2509 -rw-r--r-- | | # +-------------------------+-------------------------+ | # | Istoriya puteshestvij | | # +---------------------------------------------------+--+ # SHELL=/bin/sh SRCS = glob.c w.c menu.c pull.c match.c pwd.c hist.c line.c table.c \ main.c treemk.c OBJS = glob.o w.o menu.o pull.o match.o pwd.o hist.o line.o table.o \ main.o treemk.o # INCLUDE = /usr/include # LIB = -lncurses INCLUDE = -I../../src/curses LIB = ../../src/curses/libncurses.a DEFINES = -DUSG -DTERMIOS CC = cc -O # standartnyj C-compiler + optimizaciya #CC = gcc -O # GNU C-compiler uxcom: $(OBJS) $(CC) $(OBJS) -o $@ $(LIB) sync; ls -l $@; size $@ glob.o: glob.c glob.h # eto fajl "Primer 18" $(CC) -c glob.c w.o: w.c w.h # eto fajl "Primer 17" $(CC) -c $(INCLUDE) $(DEFINES) w.c menu.o: menu.c glob.h w.h menu.h # eto fajl "Primer 19" $(CC) -c $(INCLUDE) $(DEFINES) menu.c pull.o: pull.c glob.h w.h menu.h pull.h # eto fajl "Primer 20" $(CC) -c $(INCLUDE) $(DEFINES) pull.c match.o: match.c $(CC) -c -DMATCHONLY \ -DMATCH_ERR="TblMatchErr()" match.c pwd.o: pwd.c $(CC) -c -DU42 -DCWDONLY pwd.c treemk.o: treemk.c $(CC) -c $(DEFINES) \ -DERR_CANT_READ=tree_err_cant_read \ -DERR_NAME_TOO_LONG=tree_name_too_long \ -DTREEONLY -DU42 treemk.c hist.o: hist.c hist.h glob.h menu.h w.h # eto fajl "Primer 21" $(CC) -c $(INCLUDE) $(DEFINES) hist.c line.o: line.c w.h glob.h menu.h hist.h line.h # "Primer 21" $(CC) -c $(INCLUDE) $(DEFINES) line.c table.o: table.c w.h glob.h menu.h table.h # "Primer 22" $(CC) -c $(INCLUDE) $(DEFINES) table.c main.o: main.c glob.h w.h menu.h hist.h line.h pull.h table.h $(CC) -c $(INCLUDE) $(DEFINES) main.c w.h: wcur.h touch w.h /* _______________________ fajl main.c __________________________ */ /* Nizhe predpolagaetsya, chto vy raskrasili v /etc/termcap * * vydeleniya A_STANDOUT i A_REVERSE v RAZNYE cveta ! */ #include "w.h" #include "glob.h" #include "menu.h" #include "hist.h" #include "line.h" #include "table.h" #include "pull.h" #include <signal.h> #include <ustat.h> #include <locale.h> void t_enter(), t_leave(); LineEdit edit; /* redaktor stroki */ Hist hcwd, hedit, hpat; /* istorii: */ /* poseshchennye katalogi, nabrannye komandy, shablony imen */ Menu mwrk, msort; /* dolzhny imet' klass static */ PullMenu pull; typedef enum { SEL_WRK=0, SEL_PANE1, SEL_PANE2, SEL_PULL, SEL_HELP } Sel; Sel current_menu; /* tekushchee aktivnoe menyu */ Sel previous_menu; /* predydushchee aktivnoe menyu */ #define SEL_PANE (current_menu == SEL_PANE1 || current_menu == SEL_PANE2) typedef struct { Table t; /* tablica s imenami fajlov */ DirContents d; /* soderzhimoe katalogov */ } FileWidget; FileWidget tpane1, tpane2; /* levaya i pravaya paneli */ FileWidget *A_pane = &tpane1; /* aktivnaya panel' */ FileWidget *B_pane = &tpane2; /* protivopolozhnaya panel' */ #define A_tbl (&A_pane->t) #define A_dir (&A_pane->d) #define B_tbl (&B_pane->t) #define B_dir (&B_pane->d) #define TblFW(tbl) ((tbl) == A_tbl ? A_pane : B_pane) void ExchangePanes(){ /* Obmenyat' ukazateli na paneli */ FileWidget *tmp = A_pane; A_pane = B_pane; B_pane = tmp; current_menu = (current_menu == SEL_PANE1 ? SEL_PANE2 : SEL_PANE1); } #define Other_pane(p) ((p) == A_pane ? B_pane : A_pane) #define Other_tbl(t) ((t) == A_tbl ? B_tbl : A_tbl ) WINDOW *panewin; /* okno, soderzhashchee obe paneli = stdscr */ typedef enum { NORUN=0, RUNCMD=1, CHDIR=2, TAG=3, FIND=4 } RunType; #define REPEAT_KEY 666 /* psevdoklavisha "povtori vybor v menyu" */ #define LEAVE_KEY 777 /* psevdoklavisha "pokin' eto menyu" */ #define NOSELECTED (-1) /* v menyu nichego poka ne vybrano */ #define CENTER (COLS/2-2) /* liniya razdela panelej */ int done; /* zakonchena li programma ? */ char CWD[MAXLEN]; /* polnoe imya tekushchego kataloga */ char SELECTION[MAXLEN]; /* imya vybrannogo fajla */ /*-----------------------------------------------------------------*/ /* Vydat' podskazku v stroke redaktora */ /*-----------------------------------------------------------------*/ #include <stdarg.h> void Message(char *s, ... ){ char msg[80]; va_list args; int field_width; va_start(args, s); vsprintf(msg, s, args); va_end(args); wattrset (panewin, A_tbl->sel_attrib); field_width = A_tbl->width + B_tbl->width - 3; mvwprintw (panewin, LINES-2, tpane1.t.left+1, " %*.*s ", -field_width, field_width, msg); wattrset (panewin, A_tbl->bg_attrib); wnoutrefresh(panewin); } /*-----------------------------------------------------------------* * Menyu poryadka sortirovki imen fajlov. * *-----------------------------------------------------------------*/ Info sort_info[] = { { "Po vozrastaniyu", 0}, { "Po ubyvaniyu", 0}, { "Po suffiksu", 0}, { "Bez sortirovki", 0}, { "Po razmeru", M_HATCH}, { NULL, 0} }; /* Pri vhode v menyu sortirovki ukazat' tekushchij tip sortirovki */ void sort_show(Menu *m){ MnuPointAt(&msort, (int) sorttype); } /* Vybrat' tip sortirovki imen fajlov */ static void SelectSortType(int sel){ if( sel == NOSELECTED ) sel = MnuUsualSelect(&msort, NO); MnuHide(&msort); current_menu = previous_menu; if(M_REFUSED(&msort)) return; sorttype = (Sort) sel; A_dir->lastRead = B_dir->lastRead = 0L; /* forsirovat' perechitku */ /* no nichego yavno ne peresortirovyvat' i ne pererisovyvat' */ } /*-----------------------------------------------------------------* * Otslezhivanie soderzhimogo katalogov i pereinicializaciya menyu. * *-----------------------------------------------------------------*/ #define NON_VALID(d) ((d)->readErrors || (d)->valid == NO) /* Smenit' soderzhimoe tablicy i spiska fajlov */ void InitTblFromDir(FileWidget *wd, int chdired, char *savename){ char *msg, *name; Table *tbl = &(wd->t); DirContents *d = &wd->d; int saveind = tbl->current, saveshift = tbl->shift; char *svname = NULL; if(tbl->nitems > 0 ) svname = strdup(T_ITEMF(tbl, saveind, 0)); /* Nesushchestvuyushchie i nechitaemye katalogi vydelit' osobo */ if( NON_VALID(d)) wattrset(tbl->win, A_REVERSE); TblClear(tbl); if(d->valid == NO){ msg = "Ne sushchestvuet"; name = d->name; goto Report; } else if(d->readErrors){ /* togda d->files->s == NULL */ msg = "Ne chitaetsya"; name = d->name; Report: mvwaddstr(tbl->win, tbl->top + tbl->height/2, tbl->left + (tbl->width - strlen(name))/2, name); mvwaddstr(tbl->win, tbl->top + tbl->height/2+1, tbl->left + (tbl->width - strlen(msg))/2, msg); } wattrset(tbl->win, tbl->bg_attrib); tbl->items = d->files; TblInit(tbl, NO); /* Postarat'sya sohranit' poziciyu v tablice */ if( chdired ) TblPlaceByName(tbl, savename); else { if( svname == NULL || TblPlaceByName(tbl, svname) < 0 ){ tbl->shift = saveshift; tbl->current = saveind; TblChk(tbl); } } if(svname) free(svname); } /* Perejti v katalog i zapomnit' ego polnoe imya */ int mychdir(char *newdir){ int code = chdir(newdir); if( code < 0 ) return code; getwd(CWD); in_the_root = (strcmp(CWD, "/") == 0); HistAdd(&hcwd, CWD, 0); /* zapomnit' v istorii katalogov */ t_enter(&tpane1.t); /* na ramke narisovat' imya tekushchego kataloga */ return code; } /* Izmenit' tekushchij katalog i perechitat' ego soderzhimoe */ int cd(char *newdir, FileWidget *wd, char *oldname){ char oldbase[MAXLEN], *s, *strrchr(char *,char); /* Spasti v oldbase bazovoe imya starogo kataloga oldname (obychno CWD) */ if(s = strrchr(oldname, '/')) s++; else s = oldname; strcpy(oldbase, s); if( mychdir(newdir) < 0){ /* ne mogu perejti v katalog */ Message("Ne mogu perejti v %s", *newdir ? newdir : "???"); beep(); return (-1); } if( ReadDir(CWD, &wd->d)){ /* soderzhimoe izmenilos' */ InitTblFromDir (wd, YES, oldbase); return 1; } return 0; } /* Proverit' soderzhimoe obeih panelej */ void checkBothPanes(){ /* Sluchaj NON_VALID nuzhen tol'ko dlya togo, chtoby Init... vosstanovil