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