|
|
1.1 root 1: /*
2: * UAE - The Un*x Amiga Emulator
3: *
4: * ncurses frontend for a text-based user interface.
5: *
6: * Copyright 1996 Bernd Schmidt
7: * If you find the routines in this file useful, you may use them in your
8: * programs without restrictions. Essentially, it's in the public domain.
9: *
10: */
11:
12:
13: #include "sysconfig.h"
14: #include "sysdeps.h"
15:
1.1.1.2 root 16: #ifdef HAVE_NCURSES_H
1.1 root 17: #include <ncurses.h>
1.1.1.2 root 18: #else
19: #include <curses.h>
20: #endif
21: #include <ctype.h>
1.1 root 22:
23: #include "config.h"
24: #include "options.h"
1.1.1.2 root 25: #include "uae.h"
1.1 root 26: #include "tui.h"
27:
1.1.1.3 root 28: #ifdef DONT_HAVE_ATTR_T
29: typedef int attr_t;
30: #endif
31:
1.1 root 32: static WINDOW *currwin;
33:
34: static WINDOW *winstack[10]; /* more than enough */
35: static int winnr = 0;
36:
37: void tui_setup(void)
38: {
39: int i;
1.1.1.3 root 40:
1.1 root 41: for (i = 0; i < 10; i++)
42: winstack[i] = NULL;
43: /* From the ncurses manpage... */
1.1.1.4 ! root 44: initscr (); start_color (); cbreak(); noecho(); nonl (); intrflush (stdscr, FALSE); keypad (stdscr, TRUE);
1.1 root 45: currwin = stdscr;
1.1.1.4 ! root 46: if (has_colors ()) {
! 47: init_pair (1, COLOR_WHITE, COLOR_BLUE);
! 48: init_pair (2, COLOR_BLACK, COLOR_WHITE);
! 49: wattron (currwin, COLOR_PAIR (1) | A_BOLD);
! 50: wbkgd (currwin, ' ' | COLOR_PAIR (1));
1.1 root 51: }
1.1.1.3 root 52:
1.1 root 53: winstack[0] = stdscr;
54: winnr = 1;
55: }
56:
1.1.1.4 ! root 57: int tui_lines (void)
1.1 root 58: {
59: return LINES;
60: }
61:
1.1.1.4 ! root 62: int tui_cols (void)
1.1 root 63: {
64: return COLS;
65: }
66:
1.1.1.4 ! root 67: void tui_shutdown (void)
1.1 root 68: {
1.1.1.4 ! root 69: endwin ();
1.1 root 70: }
71:
1.1.1.4 ! root 72: void tui_refresh (void)
1.1 root 73: {
1.1.1.2 root 74: int w;
75: for (w = 0; w < winnr; w++) {
1.1.1.4 ! root 76: touchwin (winstack[w]);
! 77: wnoutrefresh (winstack[w]);
1.1.1.2 root 78: }
1.1.1.4 ! root 79: doupdate ();
1.1 root 80: }
81:
1.1.1.4 ! root 82: void tui_puts (const char *s)
1.1 root 83: {
1.1.1.4 ! root 84: waddstr (currwin, s);
1.1 root 85: }
86:
87: void tui_cursoff(void)
88: {
89: }
90:
1.1.1.4 ! root 91: void tui_curson (void)
1.1 root 92: {
93: }
94:
95: void tui_putc(char c)
96: {
1.1.1.4 ! root 97: waddch (currwin, c);
1.1 root 98: }
99:
1.1.1.4 ! root 100: void tui_cr (void)
1.1 root 101: {
1.1.1.4 ! root 102: waddch (currwin, '\r');
1.1 root 103: }
104:
105: char tui_getc(void)
106: {
1.1.1.4 ! root 107: return getch ();
1.1 root 108: }
109:
1.1.1.4 ! root 110: void tui_gotoxy (int x, int y)
1.1 root 111: {
112: x--; y--;
1.1.1.4 ! root 113: wmove (currwin, y, x);
1.1 root 114: }
115:
1.1.1.4 ! root 116: void tui_selwin (int w)
1.1 root 117: {
118: currwin = winstack[w];
119: }
120:
1.1.1.4 ! root 121: void tui_clrwin (int w)
1.1 root 122: {
1.1.1.4 ! root 123: werase (winstack[w]);
1.1 root 124: }
125:
126: void tui_drawbox(int w)
127: {
1.1.1.4 ! root 128: wborder (winstack[w], 0, 0, 0, 0, 0, 0, 0, 0);
1.1 root 129: }
130:
1.1.1.4 ! root 131: void tui_hline (int x1, int y1, int x2)
1.1 root 132: {
1.1.1.4 ! root 133: wmove (currwin, y1-1, x1-1);
! 134: whline (currwin, 0, x2-x1+1);
1.1 root 135: }
136:
137: int tui_dlog(int x1, int y1, int x2, int y2)
138: {
139: x1--; y1--;
1.1.1.4 ! root 140: winstack[winnr] = newwin (y2 - y1, x2 - x1, y1, x1);
1.1 root 141: return winnr++;
142: }
143:
1.1.1.4 ! root 144: void tui_dlogdie (int w)
1.1 root 145: {
146: if (currwin == winstack[w])
147: currwin = stdscr;
1.1.1.4 ! root 148: delwin (winstack[w]);
1.1 root 149: winstack[w] = NULL;
150: while (winstack[winnr-1] == NULL)
151: winnr--;
1.1.1.3 root 152:
1.1 root 153: for (w = 0; w < winnr; w++)
1.1.1.4 ! root 154: redrawwin (winstack[w]), wrefresh (winstack[w]);
1.1 root 155: }
156:
1.1.1.4 ! root 157: int tui_gets (char *buf, int x, int y, int n)
1.1 root 158: {
159: int i = 0;
160: for (;;) {
1.1.1.2 root 161: int c, j;
162:
163: buf[i] = 0;
1.1.1.4 ! root 164: wmove (currwin, y, x);
1.1 root 165: for (j = 0; j < i; j++)
1.1.1.4 ! root 166: waddch (currwin, buf[j]);
1.1 root 167: for (; j < n; j++)
1.1.1.4 ! root 168: waddch (currwin, ' ');
1.1.1.2 root 169:
1.1.1.4 ! root 170: wmove (currwin, y, x + i);
! 171: wrefresh (currwin);
1.1.1.3 root 172:
1.1.1.4 ! root 173: c = getch ();
1.1.1.2 root 174:
1.1.1.4 ! root 175: wmove (currwin, y, x + i);
1.1 root 176: if (c == 13)
177: return 1;
178: else if (c == 27)
179: return 0;
1.1.1.2 root 180: else if (i > 0 && c == KEY_BACKSPACE)
181: i--;
1.1.1.4 ! root 182: else if (i + 1 < n && !iscntrl (c))
1.1 root 183: buf[i++] = c;
184: }
185: }
186:
1.1.1.4 ! root 187: int tui_wgets (char *buf, const char *title, int n)
1.1 root 188: {
1.1.1.4 ! root 189: int l = strlen (title);
1.1.1.2 root 190: int ww = (l > n ? l : n) + 2;
1.1.1.4 ! root 191: int w = tui_dlog((tui_cols ()-ww)/2, tui_lines ()/2-1, (tui_cols ()+ww)/2, tui_lines ()/2+1);
1.1.1.2 root 192: int result;
193:
1.1.1.4 ! root 194: tui_selwin (w); tui_drawbox(w);
! 195: wmove (currwin, 0, (ww-l)/2);
! 196: waddstr (currwin, title);
! 197: result = tui_gets (buf, 1, 1, n);
! 198: tui_dlogdie (w);
1.1.1.2 root 199: return result;
200: }
201:
1.1.1.4 ! root 202: int tui_menubrowse (struct bstring *menu, int xoff, int yoff, int selected, int height)
1.1.1.2 root 203: {
204: int count = 0, maxsel = 0, maxw = 0;
1.1.1.3 root 205: int i, j, w, s, yp, oldyp;
206: chtype moresave[6][2];
207: int xpos, ypos;
1.1.1.2 root 208:
209: const char *mtitle = NULL;
1.1.1.3 root 210:
1.1.1.2 root 211: for (i = 0; menu[i].val != -3; i++) {
212: int tmp;
1.1.1.3 root 213: if (menu[i].val == -4) {
214: if (maxsel < selected)
215: selected--;
216: continue;
217: }
1.1.1.2 root 218: if (menu[i].val != 0) {
219: count++;
220: if (menu[i].val != -2)
221: maxsel++;
222: } else
223: mtitle = menu[i].data;
1.1.1.4 ! root 224: if ((tmp = strlen (menu[i].data)) > maxw)
1.1.1.2 root 225: maxw = tmp;
226: }
1.1.1.3 root 227: if (height > count)
228: height = count;
1.1.1.2 root 229: maxw += 3;
1.1.1.4 ! root 230: if (strlen (mtitle ? mtitle : "") + 8 > maxw)
! 231: maxw = strlen (mtitle ? mtitle : "") + 8;
1.1.1.3 root 232: if (xoff > 0)
233: xpos = xoff;
234: else
1.1.1.4 ! root 235: xpos = tui_cols () + xoff - maxw - 1;
1.1.1.3 root 236: if (yoff > 0)
237: ypos = yoff;
238: else
1.1.1.4 ! root 239: ypos = tui_lines () + yoff - height - 2;
1.1.1.3 root 240: w = tui_dlog(xpos, ypos, xpos+maxw, ypos+height+1);
1.1.1.4 ! root 241: tui_selwin (w);
1.1.1.2 root 242: tui_drawbox(w);
243: if (mtitle != NULL) {
1.1.1.4 ! root 244: mvwaddstr (currwin, 0, 1, mtitle);
1.1.1.2 root 245: }
1.1.1.3 root 246: for (i = 0; i < 6; i++) {
1.1.1.4 ! root 247: moresave[i][0] = mvwinch (currwin, 0, maxw-6+i);
! 248: moresave[i][1] = mvwinch (currwin, height+1, maxw-6+i);
1.1.1.3 root 249: }
250: s = yp = 0; oldyp = -1;
1.1.1.2 root 251: for (;;) {
252: int c;
253: int s2;
1.1.1.3 root 254:
255: while (selected < yp)
256: yp--;
257: while (selected >= yp + height)
258: yp++;
259: if (yp == 0)
260: for (i = 0; i < 6; i++)
1.1.1.4 ! root 261: mvwaddch (currwin, 0, maxw-6+i, moresave[i][0]);
1.1.1.3 root 262: else
1.1.1.4 ! root 263: mvwaddstr (currwin, 0, maxw-6, "(more)");
1.1.1.3 root 264: if (yp + height == count)
265: for (i = 0; i < 6; i++)
1.1.1.4 ! root 266: mvwaddch (currwin, height+1, maxw-6+i, moresave[i][1]);
1.1.1.3 root 267: else
1.1.1.4 ! root 268: mvwaddstr (currwin, height+1, maxw-6, "(more)");
1.1.1.3 root 269: for (i = s2 = j = 0; i < count; i++, j++) {
1.1.1.2 root 270: int k, x;
271: attr_t a = s2 == selected ? A_STANDOUT : 0;
1.1.1.3 root 272: while (menu[j].val == 0 || menu[j].val == -4)
1.1.1.2 root 273: j++;
1.1.1.3 root 274: if (i >= yp && i < yp+height) {
1.1.1.4 ! root 275: mvwaddch (currwin, 1+i-yp, 1, ' ' | a);
1.1.1.3 root 276: for (k = x = 0; menu[j].data[k]; k++, x++) {
277: int a2 = 0;
278: c = menu[j].data[k];
279: if (c == '_')
280: c = menu[j].data[++k], a2 = A_UNDERLINE;
1.1.1.4 ! root 281: mvwaddch (currwin, 1+i-yp, 2+x, c | a | a2);
1.1.1.3 root 282: }
283: for (; x < maxw-2; x++) {
1.1.1.4 ! root 284: mvwaddch (currwin, 1+i-yp, 2+x, ' ' | a);
1.1.1.3 root 285: }
1.1.1.2 root 286: }
1.1.1.3 root 287: if (menu[j].val != -2)
1.1.1.2 root 288: s2++;
289: }
290:
1.1.1.4 ! root 291: tui_refresh ();
! 292: c = getch ();
1.1.1.2 root 293: if (c == 27) {
1.1.1.4 ! root 294: tui_dlogdie (w);
1.1.1.2 root 295: return -1;
296: } else if (c == KEY_ENTER || c == 13 || c == ' ') {
1.1.1.4 ! root 297: tui_dlogdie (w);
1.1.1.3 root 298: for (i = s2 = j = 0; s2 <= selected; j++) {
299: if (menu[j].val == -4) {
300: i++; j++; continue;
301: }
302: while (menu[j].val == 0)
303: j++;
304: if (s2 == selected)
305: return i;
306: if (menu[j].val != -2)
307: s2++, i++;
308: }
309: abort();
1.1.1.2 root 310: } else switch (c) {
311: case KEY_UP:
312: if (selected > 0)
313: selected--;
314: break;
315: case KEY_DOWN:
316: if (selected + 1 < count)
317: selected++;
318: break;
319: case KEY_PPAGE:
1.1.1.3 root 320: if (selected > height)
321: selected -= height;
322: else
323: selected = 0;
1.1.1.2 root 324: break;
325: case KEY_NPAGE:
1.1.1.3 root 326: if (selected + height < count)
327: selected += height;
328: else
329: selected = count-1;
1.1.1.2 root 330: break;
331: default:
1.1.1.3 root 332: for (j = i = 0; menu[i].val != -3; i++)
1.1.1.4 ! root 333: if (menu[i].val == toupper (c)) {
! 334: tui_dlogdie (w);
1.1.1.2 root 335: return j;
1.1.1.3 root 336: } else if (menu[i].val == -1 || menu[i].val == -4 || menu[i].val > 0) {
1.1.1.2 root 337: j++;
338: }
339:
340: break;
341: }
342: }
343: return -1; /* Can't get here */
1.1 root 344: }
345:
1.1.1.2 root 346: void tui_errorbox(const char *err)
347: {
348: const char *hak = "Hit any key";
1.1.1.4 ! root 349: int n = strlen (hak);
! 350: int l = strlen (err);
1.1.1.2 root 351: int ww = (l > n ? l : n) + 2;
1.1.1.4 ! root 352: int w = tui_dlog((tui_cols ()-ww)/2, tui_lines ()/2-1, (tui_cols ()+ww)/2, tui_lines ()/2+1);
! 353: tui_selwin (w); tui_drawbox(w);
1.1.1.3 root 354:
1.1.1.4 ! root 355: wmove (currwin, 0, (ww-6)/2);
! 356: waddstr (currwin, "Error!");
! 357: wmove (currwin, 1, (ww-l)/2);
! 358: waddstr (currwin, err);
! 359: wmove (currwin, 2, (ww-n)/2);
! 360: waddstr (currwin, hak);
1.1.1.3 root 361:
1.1.1.4 ! root 362: wrefresh (currwin);
1.1.1.2 root 363: for (;;) {
1.1.1.4 ! root 364: int c = getch ();
1.1.1.2 root 365: if (c == 13)
366: break;
367: }
1.1.1.4 ! root 368: tui_dlogdie (w);
1.1.1.2 root 369: }
1.1 root 370:
371: static char *pattern;
372: static int maxlen;
373:
1.1.1.4 ! root 374: static void put_filename (char *s, int x, int y, attr_t a)
1.1 root 375: {
376: char buf[256];
377: int i;
378:
1.1.1.4 ! root 379: tui_gotoxy (x,y);
! 380: if (strcmp (s, ".") == 0)
! 381: strcpy (buf, "(none)");
1.1 root 382: else
1.1.1.4 ! root 383: strcpy (buf, s);
1.1 root 384: buf[maxlen] = 0;
1.1.1.4 ! root 385: for (i = 0; i < strlen (buf); i++)
! 386: waddch (currwin, buf[i] | a);
1.1 root 387: for (; i < maxlen; i++)
1.1.1.4 ! root 388: waddch (currwin, ' ' | a);
1.1 root 389: }
390:
391: static char fsbuf[256];
392:
1.1.1.4 ! root 393: static int selectfn (const struct dirent *de)
1.1 root 394: {
395: int l1, l2;
396:
1.1.1.4 ! root 397: /* l1 = strlen (pattern + 1);*/
! 398: l2 = strlen (de->d_name);
1.1 root 399:
1.1.1.4 ! root 400: if (l2 >= tui_cols ()-10) /* Restrict length of filenames so we won't mess up the display */
1.1 root 401: return 0;
402:
403: /* No pattern matching for now. But we don't show hidden files. */
1.1.1.4 ! root 404: if (strcmp (de->d_name, ".") != 0 && strcmp (de->d_name, "..") != 0
1.1 root 405: && de->d_name[0] == '.')
406: return 0;
407: if (l2 > maxlen)
408: maxlen = l2;
409: return 1;
410: }
411:
1.1.1.3 root 412: static int my_alphasort (const void *a, const void *b)
413: {
414: return strcmp ((*(struct dirent **) a)->d_name,
415: (*(struct dirent **) b)->d_name);
416: }
417:
418: char *tui_filereq(char *s, char *oldfile, const char *title)
1.1 root 419: {
420: char cwd[256];
421: char *retval = fsbuf;
422: char *tmp;
423: int fin = 0;
1.1.1.3 root 424: chtype moresave[6][2];
1.1 root 425:
426: /* Save wd */
1.1.1.4 ! root 427: if (getcwd (cwd, 256) == NULL)
1.1 root 428: return NULL;
429:
430: /* Change into directory of old file */
1.1.1.4 ! root 431: strcpy (fsbuf, oldfile);
! 432: tmp = strrchr (fsbuf, '/');
1.1 root 433: if (tmp != NULL) {
434: *tmp = 0;
1.1.1.4 ! root 435: if (strlen (fsbuf) > 0)
! 436: chdir (fsbuf);
1.1 root 437: }
1.1.1.3 root 438:
1.1 root 439: pattern = s;
440: if (s[0] != '*')
441: fprintf(stderr, "Can't handle wildcard %s\n", s);
1.1.1.4 ! root 442: if (s[1] != 0 && strchr (s+1, '*') != NULL)
1.1 root 443: fprintf(stderr, "Can't handle wildcard %s\n", s);
444: for (;!fin;) {
445: struct dirent **names;
446: int i, w, n, l, yp, oldyp, s;
1.1.1.3 root 447:
1.1 root 448: maxlen = 0;
1.1.1.4 ! root 449: n = scandir (".", &names, selectfn, my_alphasort);
1.1.1.3 root 450:
1.1 root 451: if (n <= 0)
452: return NULL;
1.1.1.4 ! root 453: if (title != NULL && strlen (title) + 6 > maxlen)
! 454: maxlen = strlen (title) + 6;
1.1 root 455: l = n;
456: if (l > 15)
457: l = 15;
458: yp = s = 0; oldyp = -1;
1.1.1.4 ! root 459: w = tui_dlog (tui_cols () - maxlen - 8, 5, tui_cols () - 5, 5 + l + 1);
! 460: tui_selwin (w); tui_drawbox (w);
1.1.1.3 root 461: if (title)
1.1.1.4 ! root 462: mvwaddstr (currwin, 0, 2, title);
1.1.1.3 root 463: for (i = 0; i < 6; i++) {
1.1.1.4 ! root 464: moresave[i][0] = mvwinch (currwin, 0, maxlen-3+i);
! 465: moresave[i][1] = mvwinch (currwin, l+1, maxlen-3+i);
1.1.1.3 root 466: }
1.1 root 467: for (;;) {
468: int c;
469: char tmp[256];
470: while (s < yp)
471: yp--;
472: while (s >= yp + l)
473: yp++;
474: if (oldyp != yp) {
475: oldyp = yp;
476: for (i = 0; i < l; i++) {
1.1.1.4 ! root 477: put_filename (names[i + yp]->d_name, 3, 2 + i, 0);
1.1 root 478: }
479: }
1.1.1.4 ! root 480: put_filename (names[s]->d_name, 3, 2 + s - yp, A_STANDOUT);
1.1.1.3 root 481:
482: if (yp == 0)
483: for (i = 0; i < 6; i++)
1.1.1.4 ! root 484: mvwaddch (currwin, 0, maxlen-3+i, moresave[i][0]);
1.1.1.3 root 485: else
1.1.1.4 ! root 486: mvwaddstr (currwin, 0, maxlen-3, "(more)");
1.1.1.3 root 487: if (yp + l == n)
488: for (i = 0; i < 6; i++)
1.1.1.4 ! root 489: mvwaddch (currwin, l+1, maxlen-3+i, moresave[i][1]);
1.1.1.3 root 490: else
1.1.1.4 ! root 491: mvwaddstr (currwin, l+1, maxlen-3, "(more)");
1.1.1.3 root 492:
1.1.1.4 ! root 493: tui_refresh ();
! 494: c = getch ();
! 495: put_filename (names[s]->d_name, 3, 2 + s - yp, 0);
1.1 root 496: if (c == 27) {
497: retval = NULL; fin = 1;
498: break;
499: } else if (c == KEY_ENTER || c == 13 || c == ' ') {
500: int err;
1.1.1.3 root 501:
1.1.1.4 ! root 502: if (strcmp (names[s]->d_name, ".") == 0) {
1.1 root 503: fin = 1;
1.1.1.4 ! root 504: strcpy (fsbuf, "");
1.1 root 505: break;
506: }
1.1.1.4 ! root 507: err = chdir (names[s]->d_name);
1.1.1.3 root 508:
1.1 root 509: if (err == 0)
510: break;
511: else if (errno == ENOTDIR) {
512: fin = 1;
1.1.1.4 ! root 513: if (getcwd (fsbuf, 256) == NULL)
1.1 root 514: retval = NULL;
1.1.1.4 ! root 515: if (strlen (fsbuf) + strlen (names[s]->d_name) + 2 >= 256)
1.1 root 516: retval = NULL;
517: else {
518: strcat(fsbuf, "/");
519: strcat(fsbuf, names[s]->d_name);
520: }
521: break;
522: } /* else what? */
523: }
524: switch (c) {
525: case KEY_UP:
526: if (s > 0)
527: s--;
528: break;
529: case KEY_DOWN:
530: if (s + 1 < n)
531: s++;
532: break;
533: case KEY_PPAGE:
534: if (s > l)
535: s -= l;
536: else
537: s = 0;
538: break;
539: case KEY_NPAGE:
540: if (s + l < n)
541: s += l;
542: else
543: s = n - 1;
544: break;
545: default:
1.1.1.3 root 546: i = 0;
547: if (names[s]->d_name[0] == c)
548: i = s+1;
549: for (; i < n*2; i++) {
550: int j = i;
551: if (i >= n)
552: j -= n;
553: if (names[j]->d_name[0] == c) {
554: s = j;
1.1 root 555: break;
556: }
1.1.1.3 root 557: }
1.1 root 558: }
559: }
560: #if 0
561: /* @@@ is this right? */
562: for (i = 0; i < n; i++)
1.1.1.4 ! root 563: free (names[i]);
! 564: free (names);
1.1 root 565: #endif
1.1.1.4 ! root 566: tui_dlogdie (w);
1.1 root 567: }
1.1.1.4 ! root 568: chdir (cwd);
1.1 root 569: return retval;
570: }
571:
1.1.1.4 ! root 572: int tui_backup_optionsfile (void)
1.1 root 573: {
574: char tmp[257];
1.1.1.4 ! root 575: strcpy (tmp, optionsfile);
! 576: strcat (tmp, "~");
! 577: return rename (optionsfile, tmp);
1.1 root 578: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.