/* Terminality - a portable terminal handling library * Copyright (C) 1998-2002, Emil Mikulic. * This is LGPL - look at COPYING.LIB */ /* Project: Terminality/GUI * File: textview.cpp * Author: Michal Safranek * Description: Text viewer implementation */ #include #include #include #define ESC "\x01B" /* ESC char for color combinations */ const char textview_rcsid[] = "$Id: textview.cpp,v 1.2 2002/07/26 01:39:40 darkmoon Exp $"; // Initialise textview textview::textview(int xx, int yy, int ww, int hh){ content = NULL; hscroll = scroll = 0; x = xx; y = yy; w = ww; h = hh; FG = LightGray; /* FIXME: Any reasonable default? */ BG = COLOR_FORM_BG; fixed_colors = beeps = false; horiz_scroll = true; maxchars = 0; reg_id = register_add(Textview, this); } // Initialise textview textview::textview(int xx, int yy, int ww, int hh, char *cont){ content = NULL; hscroll = scroll = 0; x = xx; y = yy; w = ww; h = hh; FG = LightGray; /* FIXME: Any reasonable default? */ BG = COLOR_FORM_BG; fixed_colors = beeps = false; horiz_scroll = true; maxchars = 0; set_content(cont); reg_id = register_add(Textview, this); } // destroy TW textview::~textview(){ int i; // Kill old content (if any) if(content){ for(i = 0; i < tn_list_size(content); i++){ xfree(tn_list_getdata(content, i)); } tn_list_free(content); tn_list_kill(content); content = NULL; } register_del(reg_id); } // change scheme void textview::change_scheme(void){ if(fixed_colors) return; /* FIXME: Change FG ?!? */ BG = COLOR_FORM_BG; } // draw it void textview::draw(void){ int i, j, count, skip; color c; unsigned char *tmp = NULL; setcolor(FG, BG); gotoxy(x,y); // Clean up the space ... for(j = y; j < h + y; j++){ for(i = x; i < w + x; i++){ gotoxy(i, j); writech(' '); } } count = tn_list_size(content); // How many lines is registered? for(j = 1; j <= h; j++){ if(j + scroll > count) break; // We're out of content tmp = (unsigned char*)tn_list_getdata(content, j+scroll-1); // Get content gotoxy(x, y - 1 + j); setcolor(FG, BG); skip = hscroll; for(i = 1; i <= w;){ if(*tmp == 0) break; // No chars left if(*tmp == 27){ // Color escape? if(*(tmp + 1) && *(tmp + 2)) { // No end of string? Good ... if(*(tmp + 1) == 'f' || *(tmp + 1) == 'b') { // Color escape tmp += 2; switch(*tmp){ case '0': c = Black; break; case '1': c = Blue; break; case '2': c = Green; break; case '3': c = Cyan; break; case '4': c = Red; break; case '5': c = Magenta; break; case '6': c = Brown; break; case '7': c = LightGray; break; case '8': c = DarkGray; break; case '9': c = LightBlue; break; case 'a': c = LightGreen; break; case 'b': c = LightCyan; break; case 'c': c = LightRed; break; case 'd': c = LightMagenta; break; case 'e': c = Yellow; break; case 'f': c = White; break; case 'n': case '!': if(*(tmp - 1) == 'f'){ c = FG; }else{ c = BG; } break; default: // Invalid color if(*(tmp - 1) == 'f'){ c = LightGray; }else{ c = Black; } } if(*(tmp - 1) == 'f'){ fgcolor(c); }else{ bgcolor(c); } tmp++; continue; } } } if(!skip){ if(*tmp < 32 && *tmp != '\t'){ writech('.'); // FIXME: Why it can't display // chars < 32 ? }else{ if(*tmp == '\t'){ writech(' '); }else{ writech(*tmp); } } i++; }else{ skip--; } tmp++; } } } // run TW int textview::run(void){ key k; cursor cs = get_cursor(); set_cursor(none); while(1){ draw(); // draw menu update(); k = readkey(); // read key // FIXME: This should be new type not Custom k = keyhandler(k, Custom); k = handle_key(k, Custom, this); switch(k){ // handle keypress case KEY_NOTHING: break; case KEY_UP: if(scroll){ scroll--; }else{ if(beeps) beep(); } break; case ' ': case KEY_ENTER: case KEY_DOWN: if(scroll < tn_list_size(content) - h){ scroll++; }else{ if(beeps) beep(); } break; case KEY_LEFT: if(horiz_scroll){ if(hscroll){ hscroll--; }else{ if(beeps) beep(); } }else{ if(beeps) beep(); } break; case KEY_RIGHT: if(horiz_scroll){ if(hscroll < maxchars - w){ hscroll++; }else{ if(beeps) beep(); } }else{ if(beeps) beep(); } break; case KEY_HOME: if(scroll){ scroll = 0; }else{ if(beeps) beep(); } break; case KEY_END: if(scroll < tn_list_size(content) - h){ scroll = tn_list_size(content) - h; }else{ if(beeps) beep(); } break; case KEY_PGUP: if(scroll == 0){ if(beeps) beep(); }else{ if(scroll >= h){ scroll -= h; }else{ scroll = 0; } } break; case KEY_TAB: case KEY_PGDOWN: if(scroll < tn_list_size(content) - h){ if(scroll < tn_list_size(content)-2*h){ scroll += h; }else{ scroll = tn_list_size(content) - h; } }else{ if(beeps) beep(); } break; case KEY_ESC: set_cursor(cs); return -1; default: if(beeps) beep(); } } } // set content of the view void textview::set_content(char *str){ char *tmp = NULL, *end = NULL, *n = NULL; int i; // Kill old content (if any) if(content){ for(i = 0; i < tn_list_size(content); i++){ xfree(tn_list_getdata(content, i)); } tn_list_free(content); tn_list_kill(content); content = NULL; } // Set new if(! *str) return; tmp = str; while(*tmp){ if(! (end = strchr(tmp, '\n'))){ // no trailing '\n' end = str + strlen(str); } // what a wonderful reimplementation of strdup using xmalloc ... n = (char *) xmalloc((end - tmp) + 1); memcpy(n, tmp, (end - tmp)); *(n + (end - tmp)) = 0; maxchars = (unsigned)maxchars int main(void){ #ifdef __DJGPP__ _fmode = O_BINARY; #endif initcons(); clrscr(); #ifdef PLAINTEXTVIEW_TEST textview *n = new textview(5, 5, 15, 5); n->FG = White; n->BG = Blue; n->horiz_scroll = true; n->beeps = true; n->set_content("bla123456789012345\nbla2\n1\n2\n3\n4\n5"); #if 0 // file import if(n->import_file("blah")){ printw("file import failed ... :(\n\r"); update(); }else{ n->run(); } #else n->run(); #endif delete n; #else winTextview *nn = new winTextview(5, 5, 15, 5, "Pokus"); nn->FG = White; nn->BG = Blue; nn->LF = LightCyan; nn->DF = Cyan; nn->horiz_scroll = true; nn->beeps = true; nn->set_content("bla123456789012345\nbla2\n1\n2\n3\n4\n5"); nn->run(); delete nn; #endif donecons(); } #endif