00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #ifndef _LISTWIDGET_H
00023 #define _LISTWIDGET_H
00024
00025 #ifdef HAVE_CONFIG_H
00026 # include <config.h>
00027 #endif
00028
00029 #ifdef HAVE_NCURSES_H
00030 # include <ncurses.h>
00031 #else // HAVE_NCURSES_H
00032 # ifdef HAVE_CURSES_H
00033 # include <curses.h>
00034 # else
00035 # error "Neither curses.h nor ncurses.h available"
00036 # endif // HAVE_CURSES_H
00037 #endif // HAVE_NCURSES_H
00038 #include "curswa.h"
00039
00040 #ifdef HAVE_ITERATOR
00041 # include <iterator>
00042 #endif
00043
00044 #ifdef HAVE_LIST
00045 # include <list>
00046 #endif
00047
00048 #include "uiexception.h"
00049 #include "colors.h"
00050 #include "basewindow.h"
00051
00052 namespace YAPETUI {
00053
00068 template<class T>
00069 class ListWidget {
00070 private:
00071 WINDOW* window;
00072
00073 int width;
00074 int height;
00075
00082 int start_pos;
00090 int cur_pos;
00091
00092 protected:
00093 typename std::list<T> itemlist;
00094 typedef typename std::list<T>::size_type l_size_type;
00095
00096 inline ListWidget(const ListWidget& lw) {}
00097 inline const ListWidget& operator=(const ListWidget& lw) { return *this; }
00098
00099 int pagesize() { return height-2; }
00100
00101 void clearWin() throw(UIException) {
00102 Colors::setcolor(window, LISTWIDGET);
00103 int retval = wclear(window);
00104 if (retval == ERR)
00105 throw UIException("Error clearing window");
00106
00107 retval = box(window, 0, 0);
00108 if (retval == ERR)
00109 throw UIException("Error drawing box around window");
00110 }
00111
00112 void showScrollIndicators() throw(UIException) {
00113 if (start_pos > 0) {
00114 int retval = mvwaddch(window,
00115 1,
00116 width - 1,
00117 '^');
00118 if (retval == ERR)
00119 throw UIException("Unable to display scroll up indicator");
00120 }
00121
00122 if ( itemlist.size() - 1 > start_pos + cur_pos &&
00123 itemlist.size() > pagesize()) {
00124 int retval = mvwaddch(window,
00125 height - 2,
00126 width - 1,
00127 'v');
00128 if (retval == ERR)
00129 throw UIException("Unable to display scroll down indicator");
00130 }
00131 }
00132
00133 void showListItems() throw(UIException) {
00134 int usable_width = width - 2;
00135
00136 clearWin();
00137
00138 typename std::list<T>::iterator itemlist_pos = itemlist.begin();
00139
00140 for(int i=0; i<start_pos; itemlist_pos++,i++);
00141
00142 for(int i=0; i<pagesize() && itemlist_pos != itemlist.end(); itemlist_pos++, i++) {
00143 int retval = mymvwaddnstr(window,
00144 1 + i,
00145 1,
00146 (*itemlist_pos).c_str(),
00147 usable_width);
00148 if (retval == ERR)
00149 throw UIException("Unable to display item");
00150 }
00151
00152 showScrollIndicators();
00153 }
00154
00155 void showSelected(int old_pos) throw(UIException) {
00156 int retval = 0;
00157
00158 if (itemlist.size() > 0) {
00159 retval = mymvwchgat(window,
00160 cur_pos + 1,
00161 1,
00162 width-2,
00163 A_REVERSE,
00164 Colors::getcolor(LISTWIDGET),
00165 NULL);
00166 if (retval == ERR)
00167 throw UIException("Error move cursor");
00168
00169 }
00170
00171 if (old_pos > -1) {
00172 retval = mymvwchgat(window,
00173 old_pos + 1,
00174 1,
00175 width-2,
00176 A_NORMAL,
00177 Colors::getcolor(LISTWIDGET),
00178 NULL);
00179 if (retval == ERR)
00180 throw UIException("Error move cursor");
00181 }
00182 retval = touchwin(window);
00183 if (retval == ERR)
00184 throw UIException("Error touching window");
00185
00186 retval = wrefresh(window);
00187 if (retval == ERR)
00188 throw UIException("Error refreshing window");
00189 }
00190
00191 void scrollUp() {
00192 if (itemlist.size() == 0) return;
00193
00194 if (cur_pos>0) {
00195 int old_pos = cur_pos--;
00196 showSelected(old_pos);
00197 } else {
00198 if (start_pos>0) {
00199 start_pos--;
00200 showListItems();
00201 showSelected(-1);
00202 }
00203 }
00204 }
00205
00206 void scrollDown() {
00207 if (itemlist.size() == 0) return;
00208
00209 if ( ((l_size_type)(cur_pos+start_pos))<itemlist.size()-1) {
00210 if (cur_pos < pagesize()-1 ) {
00211 int old_pos = cur_pos++;
00212 showSelected(old_pos);
00213 } else {
00214 if (((l_size_type)start_pos)<itemlist.size()-1) {
00215 start_pos++;
00216 showListItems();
00217 showSelected(-1);
00218 }
00219 }
00220 }
00221 }
00222
00223 void scrollPageUp() {
00224 if (itemlist.size() == 0) return;
00225
00226 int old_pos = cur_pos;
00227 cur_pos = 0;
00228 if ( start_pos - pagesize() > 0 ) {
00229 start_pos -= pagesize();
00230 }else {
00231 start_pos = 0;
00232 }
00233 showListItems();
00234 showSelected(old_pos);
00235 }
00236
00237 void scrollPageDown() {
00238 if (itemlist.size() == 0) return;
00239
00240 int old_pos = cur_pos;
00241 if ( ((l_size_type)pagesize()) > itemlist.size() - 1 ) {
00242 cur_pos = itemlist.size() - 1;
00243 start_pos = 0;
00244 } else {
00245 start_pos += pagesize() - 1;
00246 if ( ((l_size_type)start_pos) > itemlist.size() -1 ) {
00247 start_pos = itemlist.size() - pagesize() - 1;
00248 }
00249 cur_pos = 0;
00250 }
00251
00252 showListItems();
00253 showSelected(old_pos);
00254 }
00255
00256 void scrollHome() {
00257 if (itemlist.size() == 0) return;
00258
00259 start_pos = 0;
00260 int old_pos = cur_pos;
00261 cur_pos = 0;
00262 showListItems();
00263 showSelected(old_pos);
00264 }
00265
00266 void scrollEnd() {
00267 if (itemlist.size() == 0) return;
00268
00269 int old_pos = cur_pos;
00270 start_pos = itemlist.size() - pagesize();
00271 if (start_pos < 0) {
00272 start_pos = 0;
00273 cur_pos = itemlist.size()-1;
00274 } else {
00275 cur_pos = pagesize()-1;
00276 }
00277
00278 showListItems();
00279 showSelected(old_pos);
00280 }
00281
00282 void createWindow(int sx, int sy, int w, int h) throw(UIException) {
00283 window = newwin(h, w, sy, sx);
00284 if (window == NULL)
00285 throw UIException("Error creating list window");
00286
00287 Colors::setcolor(window, LISTWIDGET);
00288
00289 int retval = keypad(window, true);
00290 if (retval == ERR)
00291 throw UIException("Error enabling keypad");
00292
00293 box(window, 0, 0);
00294
00295
00296 width = w;
00297 height = h;
00298 }
00299
00300 public:
00321 ListWidget(std::list<T> l, int sx, int sy, int w, int h)
00322 throw(UIException) : window(NULL),
00323 width(w),
00324 height(h),
00325 start_pos(0),
00326 cur_pos(0),
00327 itemlist(l) {
00328 if ( sx == -1 ||
00329 sy == -1 ||
00330 width == -1 ||
00331 height == -1 )
00332 throw UIException("No idea of the dimension of the list");
00333
00334 createWindow(sx, sy, width, height);
00335 }
00336
00337 virtual ~ListWidget() {
00338 wclear(window);
00339 delwin(window);
00340 }
00341
00351 void setList(typename std::list<T>& l) {
00352 itemlist = l;
00353 start_pos = 0;
00354 cur_pos = 0;
00355 showListItems();
00356 showSelected(-1);
00357 }
00358
00366 void replaceCurrentItem(T& item) {
00367 typename std::list<T>::iterator itemlist_pos = itemlist.begin();
00368 for (int i=0;
00369 i<(start_pos + cur_pos) && itemlist_pos != itemlist.end();
00370 itemlist_pos++, i++);
00371
00372 *itemlist_pos = item;
00373 }
00374
00375 void deleteSelectedItem() {
00376 if (itemlist.size()==0) return;
00377 typename std::list<T>::iterator itemlist_pos = itemlist.begin();
00378 for (int i=0;
00379 i<(start_pos + cur_pos) && itemlist_pos != itemlist.end();
00380 itemlist_pos++, i++);
00381
00382 if (itemlist_pos == itemlist.end()) return;
00383 itemlist.erase(itemlist_pos);
00384 scrollUp();
00385 }
00386
00387
00388 const std::list<T>& getList() const { return itemlist; }
00389 std::list<T>& getList() { return itemlist; }
00390
00413 virtual int focus() throw(UIException) {
00414 int retval = box(window, 0, 0);
00415 if (retval == ERR)
00416 throw UIException("Error re-setting the border");
00417
00418 showScrollIndicators();
00419
00420 retval = wrefresh(window);
00421 if (retval == ERR)
00422 throw UIException("Error refreshing the list widget");
00423
00424 int ch;
00425 bool stay_in_loop = true;
00426 while (stay_in_loop) {
00427 ch = wgetch(window);
00428 switch (ch) {
00429 case KEY_UP:
00430 scrollUp();
00431 break;
00432 case KEY_DOWN:
00433 scrollDown();
00434 break;
00435 case KEY_HOME:
00436 case KEY_A1:
00437 scrollHome();
00438 break;
00439 case KEY_END:
00440 case KEY_C1:
00441 scrollEnd();
00442 break;
00443 case KEY_NPAGE:
00444 case KEY_C3:
00445 scrollPageDown();
00446 break;
00447 case KEY_PPAGE:
00448 case KEY_A3:
00449 scrollPageUp();
00450 break;
00451 case KEY_REFRESH:
00452 BaseWindow::refreshAll();
00453 break;
00454 default:
00455 stay_in_loop = false;
00456 break;
00457 }
00458 }
00459
00460 retval = box(window, 0, '-');
00461 if (retval == ERR)
00462 throw UIException("Error re-setting the border");
00463 retval = wrefresh(window);
00464 if (retval == ERR)
00465 throw UIException("Error refreshing the list widget");
00466
00467 return ch;
00468 }
00469
00470 void refresh() throw(UIException) {
00471 showListItems();
00472 showSelected(-1);
00473
00474 int retval = wrefresh(window);
00475 if (retval == ERR)
00476 throw UIException("Error refreshing list");
00477 }
00478
00479 void resize(int sx, int sy, int w, int h) throw(UIException) {
00480 int retval = wclear(window);
00481 if (retval == ERR)
00482 throw UIException("Error clearing list");
00483
00484 retval = wrefresh(window);
00485 if (retval == ERR)
00486 throw UIException("Error refreshing window");
00487
00488 retval = delwin(window);
00489 if (retval == ERR)
00490 throw UIException("Error deleting window");
00491
00492 createWindow(sx, sy, w, h);
00493 }
00494
00495 int getListPos() { return start_pos + cur_pos; }
00496
00497 T getSelectedItem() {
00498 typename std::list<T>::iterator itemlist_pos = itemlist.begin();
00499 for (int i=0;
00500 i<(start_pos + cur_pos) && itemlist_pos != itemlist.end();
00501 itemlist_pos++, i++);
00502 return *itemlist_pos;
00503 }
00504
00505 l_size_type size() { return itemlist.size(); }
00506 };
00507
00508 }
00509 #endif // _LISTWIDGET_H