home *** CD-ROM | disk | FTP | other *** search
- /*
- * MultiMail offline mail reader
- * Interface, ShadowedWin, ListWindow
-
- Copyright (c) 1996 Kolossvary Tamas <thomas@tvnet.hu>
- Copyright (c) 1997 John Zero <john@graphisoft.hu>
- Copyright (c) 1999 William McBrine <wmcbrine@clark.net>
-
- Distributed under the GNU General Public License.
- For details, see the file COPYING in the parent directory. */
-
- #include "interfac.h"
-
- Win::Win(int height, int width, int topline, chtype backg)
- {
- // All windows are centered horizontally.
-
- win = newwin(height, width, topline, (COLS - width) / 2);
- Clear(backg);
-
- keypad(win, TRUE);
- cursor_off();
- }
-
- Win::~Win()
- {
- delwin(win);
- }
-
- void Win::Clear(chtype backg)
- {
- wbkgdset(win, backg | ' ');
- werase(win);
- wbkgdset(win, ' ');
- wattrset(win, backg);
- }
-
- void Win::put(int y, int x, chtype z)
- {
- mvwaddch(win, y, x, z);
- }
-
- void Win::put(int y, int x, char z)
- {
- mvwaddch(win, y, x, (unsigned char) z);
- }
-
- void Win::put(int y, int x, const chtype *z, int len)
- {
- // The cast is to suppress warnings with certain implementations
- // of curses that omit "const" from the prototype.
-
- if (!len)
- len = COLS;
-
- mvwaddchnstr(win, y, x, (chtype *) z, len);
- }
-
- int Win::put(int y, int x, const char *z)
- {
- // Formerly just mvwaddstr() -- this ensures printing of (most)
- // characters outside the ASCII range, instead of control codes.
-
- chtype z2;
- int counter = 0;
-
- wmove(win, y, x);
-
- for (; *z; z++) {
- z2 = ((unsigned char) *z);
- switch (z2) {
- #ifndef __PDCURSES__ // unprintable control codes
- case 14: // double musical note
- z2 = 19;
- break;
- case 15: // much like an asterisk
- z2 = '*';
- break;
- case 155: // ESC + high bit = slash-o,
- z2 = 'o'; // except in CP 437
- break;
- case 8: // backspace
- case 12: // form feed
- z2 = '#';
- break;
- #endif
- case 27: // ESC
- z2 = '`';
- break;
- case '\t': // TAB
- z2 = ' ';
- int i = 7 - (counter % 8);
- counter += i;
- while (i--)
- waddch(win, z2);
- }
- if ((z2 < ' ') || (z2 > 126))
- z2 |= A_ALTCHARSET;
- waddch(win, z2);
- counter++;
- }
- return counter;
- }
-
- void Win::attrib(chtype z)
- {
- wattrset(win, z);
- }
-
- void Win::horizline(int y, int len)
- {
- wmove(win, y, 1);
- whline(win, ACS_HLINE, len);
- }
-
- void Win::update()
- {
- wrefresh(win);
- }
-
- void Win::delay_update()
- {
- wnoutrefresh(win);
- }
-
- void Win::wtouch()
- {
- touchwin(win);
- wnoutrefresh(win);
- }
-
- void Win::wscroll(int i)
- {
- scrollok(win, TRUE);
- wscrl(win, i);
- scrollok(win, FALSE);
- }
-
- /* The cursor toggling routines for PDCurses are ugly, I know; especially
- in the mismatched use of the standard curs_set() to disable, and a
- private PDCurses function to enable. Unfortunately, this seems to be
- the only combination which works correctly on all platforms. (OS/2 Full
- Screen sessions are a particular problem.)
- */
- void Win::cursor_on()
- {
- leaveok(win, FALSE);
- #if defined (__PDCURSES__) && !defined(XCURSES)
- PDC_set_cursor_mode(curs_start, curs_end);
- #else
- curs_set(1);
- #endif
- }
-
- void Win::cursor_off()
- {
- leaveok(win, TRUE);
- curs_set(0);
- }
-
- int Win::keypressed()
- {
- // Return key status immediately (non-blocking)
-
- nodelay(win, TRUE);
- return wgetch(win);
- }
-
- int Win::inkey()
- {
- // Wait until key pressed, OR signal received (e.g., SIGWINCH)
-
- nodelay(win, FALSE);
- return wgetch(win);
- }
-
- void Win::boxtitle(chtype backg, const char *title, chtype titleAttrib)
- {
- wattrset(win, backg);
- box(win, 0, 0);
-
- if (title) {
- put(0, 2, ACS_RTEE);
- put(0, 3 + strlen(title), ACS_LTEE);
- wattrset(win, titleAttrib);
- put(0, 3, title);
- wattrset(win, backg);
- }
- }
-
- ShadowedWin::ShadowedWin(int height, int width, int topline, chtype backg,
- const char *title, chtype titleAttrib) : Win(height, width,
- topline, backg)
- {
- // The text to be in "shadow" is taken from different windows,
- // depending on the curses implementation. Note that the default,
- // "stdscr", just makes the shadowed area solid black; only with
- // ncurses and PDCurses does it draw proper shadows.
-
- #ifdef USE_SHADOWS
- int i, j;
- chtype *right, *lower;
- # ifndef NCURSES_VERSION
- # ifdef __PDCURSES__
- WINDOW *&newscr = curscr;
- # else
- WINDOW *&newscr = stdscr;
- # endif
- # endif
- int xlimit = 2 + (interface->active() != letter);
- int firstcol = (COLS - width) / 2;
-
- while ((width + firstcol) > (COLS - xlimit))
- width--;
- while ((height + topline) > (LINES - 1))
- height--;
-
- right = new chtype[(height - 1) << 1];
- lower = new chtype[width + 1];
-
- // Gather the old text and attribute info:
-
- for (i = 0; i < (height - 1); i++)
- for (j = 0; j < 2; j++)
- right[(i << 1) + j] = (mvwinch(newscr,
- (topline + i + 1), (firstcol + width + j)) &
- (A_CHARTEXT | A_ALTCHARSET));
-
- mvwinchnstr(newscr, (topline + height), (firstcol + 2), lower, width);
-
- // Redraw it in darkened form:
-
- shadow = newwin(height, width, topline + 1, firstcol + 2);
- leaveok(shadow, TRUE);
-
- for (i = 0; i < (height - 1); i++)
- for (j = 0; j < 2; j++)
- mvwaddch(shadow, i, width - 2 + j,
- (right[(i << 1) + j] | C_SHADOW));
- for (i = 0; i < width; i++)
- mvwaddch(shadow, height - 1, i, (lower[i] & (A_CHARTEXT |
- A_ALTCHARSET)) | C_SHADOW);
-
- wnoutrefresh(shadow);
- #endif
- boxtitle(backg, title, titleAttrib);
-
- #ifdef USE_SHADOWS
- delete[] lower;
- delete[] right;
- #endif
- }
-
- ShadowedWin::~ShadowedWin()
- {
- #ifdef USE_SHADOWS
- delwin(shadow);
- #endif
- }
-
- void ShadowedWin::touch()
- {
- #ifdef USE_SHADOWS
- touchwin(shadow);
- wnoutrefresh(shadow);
- #endif
- Win::wtouch();
- }
-
- int ShadowedWin::getstring(int y, int x, char *string, int maxlen,
- chtype bg_color, chtype fg_color)
- {
- int i, j, end, c;
- char *tmp = new char[maxlen];
-
- cropesp(string);
-
- wattrset(win, fg_color);
- for (i = 0; i < maxlen; i++) {
- put(y, x + i, ACS_BOARD);
- tmp[i] = '\0';
- }
- maxlen--;
-
- put(y, x, string); // Hmm...
-
- cursor_on();
- update();
-
- i = end = 0;
- bool first_key = true;
-
- while (!end) {
- c = inkey();
-
- // these keys make the string "accepted" and editable:
- if (first_key) {
- first_key = false;
-
- switch (c) {
- case KEY_LEFT:
- case KEY_RIGHT:
- case 8:
- case KEY_BACKSPACE:
- case KEY_HOME:
- case KEY_END:
- strncpy(tmp, string, maxlen);
- i = strlen(tmp);
- }
- }
-
- switch (c) {
- case KEY_DOWN:
- end++;
- case KEY_UP:
- end++;
- case MM_ENTER:
- end++;
- case '\033': // Escape
- end++;
- break;
- case KEY_LEFT:
- if (i > 0)
- i--;
- break;
- case KEY_RIGHT:
- if ((i < maxlen) && tmp[i])
- i++;
- break;
- case 127:
- case KEY_DC: // Delete key
- strncpy(&tmp[i], &tmp[i + 1], maxlen - i);
- tmp[maxlen] = '\0';
- break;
- case 8: // Ctrl-H
- case KEY_BACKSPACE:
- if (i > 0) {
- strncpy(&tmp[i - 1], &tmp[i], maxlen - i);
- tmp[maxlen] = '\0';
- i--;
- }
- break;
- case KEY_HOME:
- i = 0;
- break;
- case KEY_END:
- i = strlen(tmp);
- break;
- default:
- for (j = maxlen; j > i; j--)
- tmp[j] = tmp[j - 1];
- tmp[i] = c;
- if (i < maxlen)
- i++;
- }
- for (j = 0; j <= maxlen; j++)
- put(y, x + j, (tmp[j] ? (unsigned char) tmp[j] :
- ACS_BOARD));
- wmove(win, y, x + i);
- update();
- }
-
- if (tmp[0])
- strcpy(string, tmp);
-
- wattrset(win, bg_color);
-
- j = strlen(string);
- for (i = 0; i <= maxlen; i++)
- put(y, x + i, ((i < j) ? string[i] : ' '));
-
- update();
- cursor_off();
-
- delete[] tmp;
-
- return end - 1;
- }
-
- InfoWin::InfoWin(int height, int width, int topline, chtype backg,
- const char *title, chtype titleAttrib, int bottx, int topx) :
- ShadowedWin(height, width, topline, backg, title, titleAttrib)
- {
- lineBuf = new char[COLS];
- info = new Win(height - bottx, width - 2, topline + topx, backg);
- }
-
- InfoWin::~InfoWin()
- {
- delete info;
- delete[] lineBuf;
- }
-
- void InfoWin::irefresh()
- {
- info->delay_update();
- }
-
- void InfoWin::touch()
- {
- ShadowedWin::touch();
- info->wtouch();
- }
-
- void InfoWin::oneline(int i, chtype ch)
- {
- info->attrib(ch);
- info->put(i, 0, lineBuf);
- }
-
- void InfoWin::iscrl(int i)
- {
- info->wscroll(i);
- }
-
- ListWindow::ListWindow()
- {
- position = active = 0;
- oldPos = oldActive = oldHigh = -100;
- lynxNav = mm.resourceObject->getInt(UseLynxNav);
- useScrollBars = mm.resourceObject->getInt(UseScrollBars);
- }
-
- ListWindow::~ListWindow()
- {
- }
-
- void ListWindow::checkPos(int limit)
- {
- if (active >= limit)
- active = limit - 1;
-
- if (active < 0)
- active = 0;
-
- if (active < position)
- position = active;
- else
- if (active - position >= list_max_y)
- position = active - list_max_y + 1;
-
- if (limit > list_max_y) {
- if (position < 0)
- position = 0;
- else
- if (position > limit - list_max_y)
- position = limit - list_max_y;
- } else
- position = 0;
- }
-
- chtype ListWindow::setHighlight(chtype ch)
- {
- chtype backg = PAIR_NUMBER(ch) & 7;
-
- switch (backg) {
- case COLOR_BLACK:
- case COLOR_RED:
- case COLOR_BLUE:
- ch = REVERSE(COLOR_WHITE, COLOR_BLACK);
- break;
- default:
- ch = REVERSE(COLOR_BLACK, COLOR_WHITE);
- }
- return ch;
- }
-
- void ListWindow::Draw()
- {
- const chtype current = ACS_DIAMOND | A_ALTCHARSET;
- const chtype old =
- #ifdef __PDCURSES__
- ACS_BOARD;
- #else
- ACS_CKBOARD;
- #endif
- int i, j, limit = NumOfItems();
-
- checkPos(limit);
-
- // Highlight bar:
-
- if (useScrollBars && (limit > list_max_y)) {
- if (oldHigh == -100) {
- list->attrib(borderCol);
- for (i = top_offset; i < (top_offset +
- list_max_y); i++)
- list->put(i, list_max_x + 1, old);
- }
-
- i = active * list_max_y / limit;
-
- if (i != oldHigh) {
- list->attrib(borderCol);
- list->put(top_offset + oldHigh, list_max_x + 1, old);
- list->put(top_offset + i, list_max_x + 1, current);
- list->delay_update();
-
- oldHigh = i;
- }
- }
-
- // Scroll or redraw:
-
- i = position - oldPos;
- switch (i) {
- case -1:
- case 1:
- list->iscrl(i);
- case 0:
- if (active != oldActive) {
- j = oldActive - position;
- if ((j >= 0) && (j < list_max_y))
- oneLine(j);
- }
- oneLine(active - position);
- list->irefresh();
- break;
- default:
- for (j = 0; j < list_max_y; j++) {
- oneLine(j);
- if (position + j == limit - 1)
- j = list_max_y;
- }
- list->touch();
- }
- oldPos = position;
- oldActive = active;
- }
-
- void ListWindow::DrawOne(int i, chtype ch)
- {
- // Highlight, if drawing the active bar
-
- if (position + i == active)
- ch = setHighlight(ch);
-
- list->oneline(i, ch);
- }
-
- void ListWindow::DrawAll()
- {
- oldPos = oldActive = oldHigh = -100;
- Draw();
- }
-
- void ListWindow::Move(direction dir)
- {
- int limit = NumOfItems();
-
- switch (dir) {
- case UP:
- active--;
- break;
- case DOWN:
- active++;
- break;
- case PGUP:
- position -= list_max_y;
- active -= list_max_y;
- break;
- case PGDN:
- position += list_max_y;
- active += list_max_y;
- break;
- case HOME:
- active = 0;
- break;
- case END:
- active = limit - 1;
- break;
- }
- checkPos(limit);
- }
-
- void ListWindow::setActive(int x)
- {
- active = x;
- }
-
- int ListWindow::getActive()
- {
- return active;
- }
-
- searchret ListWindow::search(const char *item, int mode)
- {
- int limit = NumOfItems();
- searchret found = False;
-
- statetype orgstate = interface->active();
- for (int x = active + 1; (x < limit) && (found == False); x++) {
- if (list->keypressed() == 27) {
- found = Abort;
- break;
- }
- found = oneSearch(x, item, mode);
- if (found == True) {
- active = x;
- if (interface->active() == orgstate)
- Draw();
- }
- }
-
- checkPos(limit);
- return found;
- }
-
- void ListWindow::Prev()
- {
- Move(UP);
- }
-
- void ListWindow::Next()
- {
- Move(DOWN);
- }
-
- bool ListWindow::KeyHandle(int key)
- {
- bool draw = true, end = false;
-
- switch (key) {
- case KEY_LEFT:
- if (lynxNav) {
- draw = false;
- end = interface->back();
- break;
- }
- case MM_MINUS:
- Prev();
- break;
- case KEY_RIGHT:
- if (lynxNav) {
- draw = false;
- end = interface->select();
- break;
- }
- case '\t':
- case MM_PLUS:
- Next();
- break;
- case KEY_DOWN:
- Move(DOWN);
- break;
- case KEY_UP:
- Move(UP);
- break;
- case KEY_HOME:
- Move(HOME);
- break;
- case KEY_END:
- Move(END);
- break;
- case 'B':
- case KEY_PPAGE:
- Move(PGUP);
- break;
- case ' ':
- case 'F':
- case KEY_NPAGE:
- Move(PGDN);
- break;
- default:
- draw = false;
- end = extrakeys(key);
- }
- if (draw)
- Draw();
-
- return end;
- }
-