/* Terminality - a portable terminal handling library * Copyright (C) 1998-2002, Emil Mikulic. * This is LGPL - look at COPYING.LIB */ /* Project: Terminality/GUI * File: listing.cpp * Author: Michal Safranek * Description: Implement the listingItem, listingSeparator and listing classes */ #include const char listing_rcsid[] = "$Id: listing.cpp,v 1.9 2002/07/26 01:39:40 darkmoon Exp $"; // listingItem implementation ... #define LI_SETUP() MORE = COLOR_LITEM_MORE; \ HEADING = COLOR_LITEM_HEADING; \ ITEM_BG = COLOR_LITEM_ITEMBG; \ EMPTY_BG = COLOR_LITEM_EMPTYBG; \ HEADING_BG = COLOR_LITEM_HEADINGBG; \ MORE_BG = COLOR_LITEM_MOREBG; \ ITEM = COLOR_LITEM_ITEM; \ SELECTED_ITEM_BG = COLOR_LITEM_SITEMBG; \ SELECTED_MORE_BG = COLOR_LITEM_SMOREBG; \ EMPTY = COLOR_LITEM_EMPTY; \ SELECTED_EMPTY_BG = COLOR_LITEM_SEMPTYBG; \ SELECTED_ITEM = COLOR_LITEM_SITEM; \ SELECTED_EMPTY = COLOR_LITEM_SEMPTY; \ SELECTED_MORE = COLOR_LITEM_SMORE; \ MORE_CHR = '>'; // Initialise listingItem listingItem::listingItem() { visible = true; fixed_colors = false; items = colors = NULL; heading = NULL; x = w = 0; separator = false; LI_SETUP(); }; // Initialise listingItem listingItem::listingItem(int xx, int ww, char *hding) { visible = true; fixed_colors = false; x = xx; w = ww; heading = (char *)xmalloc(strlen(hding)+1); strcpy(heading,hding); items = colors = NULL; separator = false; LI_SETUP(); }; // Initialise listingItem listingItem::listingItem(int xx, int ww, char *hding, tn_list *itms) { visible = true; fixed_colors = false; x = xx; w = ww; heading = (char *)xmalloc(strlen(hding)+1); strcpy(heading,hding); items = itms; colors = NULL; separator = false; LI_SETUP(); } // Initialise listingItem listingItem::listingItem(int xx, int ww, char *hding, tn_list *itms, tn_list *clrs) { visible = true; fixed_colors = false; x = xx; w = ww; heading = (char *)xmalloc(strlen(hding)+1); strcpy(heading,hding); items = itms; colors = clrs; separator = false; LI_SETUP(); } // Get size of 'items' int listingItem::size(void) const { return items ? tn_list_size(items):0; } // Draw (possibly ) th item on x, ... // C(more?"with":"without") 'more data' flag void listingItem::draw(int n, int y, bool selected, bool more) { char *item = NULL; enum { H/*EADING*/, I/*TEM*/, E/*MPTY*/ } what; int count = tn_list_size(items); color *clr = NULL; color fg, bg; if (!visible) return; if (!y) return; what = I; if (!separator && n >= count) what = E; if (n == -1) what = H; // Setup colors if (colors && n >= 0 && n < tn_list_size(colors)) clr = (color *)tn_list_getdata(colors, n); if (has_color()) { /* colors */ #define IF_SELECTED(I) \ if (!selected){ setcolor(I, I##_BG); } \ else { setcolor(SELECTED_##I, SELECTED_##I##_BG); } switch (what) { case H: setcolor(HEADING,HEADING_BG); break; case I: if (clr) { if ((fg = clr[0+(selected?1:0)]) == Default) fg = selected?SELECTED_ITEM:ITEM; if ((bg = clr[2+(selected?1:0)]) == Default) bg = selected?SELECTED_ITEM_BG:ITEM_BG; setcolor(fg, bg); } else { IF_SELECTED(ITEM); } break; case E: IF_SELECTED(EMPTY); break; } } else { /* plain */ switch (what) { case H: highvideo(); break; case I: normvideo(); break; case E: lowvideo(); break; } } // Draw a empty box gotoxy(x,y); for (int i=0; i= count) return; // Empty box ... // Fill it up gotoxy(x,y); if (!separator) { char *temp = (char *)xmalloc(w+1); if (n == -1) { strncpy(temp,heading,w); } else { item = (char *)tn_list_getdata(items, n); strncpy(temp,item,w); } temp[w] = 0; printw("%s", temp); xfree(temp); } else { item = heading; writech(_c(*((unsigned char *) heading))); } // Draw 'more' if permitted && needed if (more && (n==-1?strlen(heading):strlen(item)) > (unsigned) w) { IF_SELECTED(MORE); gotoxy(x+w-1,y); printw("%c", MORE_CHR); } #undef IF_SELECTED } // Destroy listingItem listingItem::~listingItem() { xfree(heading); }; // listingSeparator implementation ... // Construct listingSeparator listingSeparator::listingSeparator(int xx) { x = xx; w = 1; heading = (char *)xmalloc(2); heading[0] = VLINE; heading[1] = 0; items = tn_list_new(heading); colors = NULL; separator = true; LI_SETUP(); // why the hell i can't use this? :( It makes no error and it also // has no effect :( //listingSeparator::listingSeparator(xx,'|'); } // Construct listingSeparator listingSeparator::listingSeparator(int xx, tn_list *clrs) { x = xx; w = 1; heading = (char *)xmalloc(2); heading[0] = VLINE; heading[1] = 0; items = tn_list_new(heading); colors = clrs; separator = true; LI_SETUP(); } listingSeparator::listingSeparator(int xx, char sep) { x = xx; w = 1; heading = (char *)xmalloc(2); heading[0] = sep; heading[1] = 0; items = tn_list_new(heading); colors = NULL; separator = true; LI_SETUP(); } listingSeparator::listingSeparator(int xx, char sep, tn_list *clrs) { x = xx; w = 1; heading = (char *)xmalloc(2); heading[0] = sep; heading[1] = 0; items = tn_list_new(heading); colors = clrs; separator = true; LI_SETUP(); } listingSeparator::~listingSeparator() { tn_list_free(items); tn_list_kill(items); } // listing implementation ... // Default keypress handle int listing_default_handle(key x, /*tn_list*/ void *l, int a) { return 0; } // Initialise listing listing::listing(listingItem *i, ...) { va_list va; listingItem *curr; handle = &listing_default_handle; visible = fixed_colors = false; current = 0; scroll = 0; items = NULL; count = 0; BACKGROUND = COLOR_LISTING_BG; // colors va_start(va, i); // start the va_list curr = i; // get first item // as long as the item isn't a NULL while (curr) { // add to queue if (!items) items = tn_list_new(curr); else tn_list_add(items, curr); // get count if(count < curr->size()) count = curr->size(); // get next item curr = va_arg(va, listingItem*); } va_end(va); // set other params ... x = y = 1; w = 80; h = 25; more = true; reg_id = register_add(Listing, this); } listing::listing(int xx, int yy, int ww, int hh, listingItem *i, ...) { va_list va; listingItem *curr; handle = &listing_default_handle; visible = fixed_colors = false; current = 0; scroll = 0; items = NULL; count = 0; BACKGROUND = Black; // colors va_start(va, i); // start the va_list curr = i; // as long as the item isn't a NULL while (curr) { // add to queue if(!items) items = tn_list_new(curr); else tn_list_add(items, curr); // get count if (count < curr->size()) count = curr->size(); // get next item curr = va_arg(va, listingItem*); } va_end(va); // set other params ... x = xx; y = yy; w = ww; h = hh; more = true; reg_id = register_add(Listing, this); } // destroy listing listing::~listing() { // first kill all listingItems listingItem *tmp; for (int i=0; i < tn_list_size(items); i++) { tmp = (listingItem*)tn_list_getdata(items, i); delete tmp; } if (items) { tn_list_free(items); tn_list_kill(items); } register_del(reg_id); } // draw listing void listing::draw(void) const { int i,j; listingItem **tmp; if (!visible) return; bgcolor(BACKGROUND); // Clear whole area for (i = 0; i < h; i++ ) { gotoxy(x,y+i); for (j = 0; j < w; j++) { writech(' '); } } // Alloc ... tmp = (listingItem **) xmalloc(tn_list_size(items) * sizeof(struct listItem*)); // Draw heading for (i = 0; i < tn_list_size(items); i++) { tmp[0] = (listingItem *) tn_list_getdata(items, i); (tmp[0])->draw(-1,y,false,more); } for (i = 0; i < tn_list_size(items); i++) { tmp[i] = (listingItem *) tn_list_getdata(items, i); } // Draw the rest for (i = 0; i < h-1; i++) { for (j = 0; j < tn_list_size(items); j++) { tmp[j]->draw(scroll+i,y+1+i,current==i,more); } } gotoxy(x,y+current+1); xfree(tmp); } // Update element count void listing::update_count(void){ int i, cnt = 0; listingItem *li = NULL; for (i = 0; i < tn_list_size(items); i++){ li = (listingItem *) tn_list_getdata(items, i); if(!li->separator && cnt < li->size()) cnt = li->size(); } if(count != cnt && (current + scroll >= cnt - 1) && cnt){ if(!current){ if(scroll) scroll--; }else{ current--; } } count = cnt; } // Get element count int listing::get_count(void){ return count; } // get choice and return listingItem # // returns -1 on abort (ESC) int listing::run(void) { key k; int h = this->h - 1; // heading cursor cs = get_cursor(); bool old_vis = visible; visible = true; set_cursor(none); while (1) { draw(); // draw menu update(); k = readkey(); // read key k = keyhandler(k, Listing); k = handle_key(k, Listing, this); k = handle(k, this, current + scroll); switch (k) { // handle keypress case KEY_NOTHING: break; case KEY_UP: if (current+scroll > 0) { if (!current) scroll--; else current--; } else beep(); break; case KEY_DOWN: if (current+scroll < count-1) { if (current < h-1) current++; else scroll++; } else beep(); break; case KEY_HOME: if (!scroll && !current) beep(); else { scroll = 0; current = 0; } break; case KEY_END: if (current + scroll == count - 1) beep(); else { if(count >= h){ current = h - 1; scroll = count - h; }else{ current = count - 1; scroll = 0; } } break; case KEY_PGUP: if (current + scroll == 0) beep(); else { if (current + scroll - 2*h >= 0) { scroll -= h; } else { current = 0; scroll = 0; } } break; case KEY_PGDOWN: if (current + scroll == count - 1) beep(); else { if (current + scroll + 2*h < count - 1) { scroll += h; }else { if(count >= h){ current = h - 1; scroll = count - h; }else{ current = count - 1; scroll = 0; } } } break; case KEY_ENTER: set_cursor(cs); visible = old_vis; return (current + scroll); case KEY_ESC: set_cursor(cs); visible = old_vis; return -1; default: beep(); } } } // set keypress handle void listing::set_handle(key (*fce)(key, void *, int)) { handle = fce; } // set default keypress handle void listing::default_handle(void) { handle = &listing_default_handle; } // Change color scheme void listingItem::change_scheme(void) { if(fixed_colors) return; MORE = COLOR_LITEM_MORE; HEADING = COLOR_LITEM_HEADING; ITEM_BG = COLOR_LITEM_ITEMBG; EMPTY_BG = COLOR_LITEM_EMPTYBG; HEADING_BG = COLOR_LITEM_HEADINGBG; MORE_BG = COLOR_LITEM_MOREBG; ITEM = COLOR_LITEM_ITEM; SELECTED_ITEM_BG = COLOR_LITEM_SITEMBG; SELECTED_MORE_BG = COLOR_LITEM_SMOREBG; EMPTY = COLOR_LITEM_EMPTY; SELECTED_ITEM = COLOR_LITEM_SITEM; SELECTED_EMPTY = COLOR_LITEM_SEMPTY; SELECTED_EMPTY_BG = COLOR_LITEM_SEMPTYBG; SELECTED_MORE = COLOR_LITEM_SMORE; } // Change color scheme void listing::change_scheme(void) { int i; if (fixed_colors) return; for (i = 0; i < tn_list_size(items); i++) { ((listingItem *) tn_list_getdata(items, i))->change_scheme(); } BACKGROUND = COLOR_LISTING_BG; }