|
|
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... */
44: initscr(); start_color(); cbreak(); noecho(); nonl(); intrflush(stdscr, FALSE); keypad(stdscr, TRUE);
45: currwin = stdscr;
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));
51: }
1.1.1.3 ! root 52:
1.1 root 53: winstack[0] = stdscr;
54: winnr = 1;
55: }
56:
57: int tui_lines(void)
58: {
59: return LINES;
60: }
61:
62: int tui_cols(void)
63: {
64: return COLS;
65: }
66:
67: void tui_shutdown(void)
68: {
69: endwin();
70: }
71:
72: void tui_refresh(void)
73: {
1.1.1.2 root 74: int w;
75: for (w = 0; w < winnr; w++) {
76: touchwin(winstack[w]);
77: wnoutrefresh(winstack[w]);
78: }
79: doupdate();
1.1 root 80: }
81:
82: void tui_puts(const char *s)
83: {
84: waddstr(currwin, s);
85: }
86:
87: void tui_cursoff(void)
88: {
89: }
90:
91: void tui_curson(void)
92: {
93: }
94:
95: void tui_putc(char c)
96: {
97: waddch(currwin, c);
98: }
99:
100: void tui_cr(void)
101: {
102: waddch(currwin, '\r');
103: }
104:
105: char tui_getc(void)
106: {
107: return getch();
108: }
109:
110: void tui_gotoxy(int x, int y)
111: {
112: x--; y--;
113: wmove(currwin, y, x);
114: }
115:
116: void tui_selwin(int w)
117: {
118: currwin = winstack[w];
119: }
120:
121: void tui_clrwin(int w)
122: {
1.1.1.2 root 123: werase(winstack[w]);
1.1 root 124: }
125:
126: void tui_drawbox(int w)
127: {
128: wborder(winstack[w], 0, 0, 0, 0, 0, 0, 0, 0);
129: }
130:
131: void tui_hline(int x1, int y1, int x2)
132: {
133: wmove(currwin, y1-1, x1-1);
134: whline(currwin, 0, x2-x1+1);
135: }
136:
137: int tui_dlog(int x1, int y1, int x2, int y2)
138: {
139: x1--; y1--;
140: winstack[winnr] = newwin(y2 - y1, x2 - x1, y1, x1);
141: return winnr++;
142: }
143:
144: void tui_dlogdie(int w)
145: {
146: if (currwin == winstack[w])
147: currwin = stdscr;
148: delwin(winstack[w]);
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++)
154: redrawwin(winstack[w]), wrefresh(winstack[w]);
155: }
156:
157: int tui_gets(char *buf, int x, int y, int n)
158: {
159: int i = 0;
160: for (;;) {
1.1.1.2 root 161: int c, j;
162:
163: buf[i] = 0;
1.1 root 164: wmove(currwin, y, x);
165: for (j = 0; j < i; j++)
166: waddch(currwin, buf[j]);
167: for (; j < n; j++)
168: waddch(currwin, ' ');
1.1.1.2 root 169:
1.1 root 170: wmove(currwin, y, x + i);
171: wrefresh(currwin);
1.1.1.3 ! root 172:
1.1.1.2 root 173: c = getch();
174:
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--;
182: else if (i + 1 < n && !iscntrl(c))
1.1 root 183: buf[i++] = c;
184: }
185: }
186:
187: int tui_wgets(char *buf, const char *title, int n)
188: {
189: int l = strlen(title);
1.1.1.2 root 190: int ww = (l > n ? l : n) + 2;
191: int w = tui_dlog((tui_cols()-ww)/2, tui_lines()/2-1, (tui_cols()+ww)/2, tui_lines()/2+1);
192: int result;
193:
1.1 root 194: tui_selwin(w); tui_drawbox(w);
195: wmove(currwin, 0, (ww-l)/2);
196: waddstr(currwin, title);
1.1.1.2 root 197: result = tui_gets(buf, 1, 1, n);
198: tui_dlogdie(w);
199: return result;
200: }
201:
1.1.1.3 ! 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;
224: if ((tmp = strlen(menu[i].data)) > maxw)
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.3 ! root 230: if (strlen(mtitle ? mtitle : "") + 8 > maxw)
! 231: maxw = strlen(mtitle ? mtitle : "") + 8;
! 232: if (xoff > 0)
! 233: xpos = xoff;
! 234: else
! 235: xpos = tui_cols() + xoff - maxw - 1;
! 236: if (yoff > 0)
! 237: ypos = yoff;
! 238: else
! 239: ypos = tui_lines() + yoff - height - 2;
! 240: w = tui_dlog(xpos, ypos, xpos+maxw, ypos+height+1);
1.1.1.2 root 241: tui_selwin(w);
242: tui_drawbox(w);
243: if (mtitle != NULL) {
1.1.1.3 ! 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++) {
! 247: moresave[i][0] = mvwinch(currwin, 0, maxw-6+i);
! 248: moresave[i][1] = mvwinch(currwin, height+1, maxw-6+i);
! 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++)
! 261: mvwaddch(currwin, 0, maxw-6+i, moresave[i][0]);
! 262: else
! 263: mvwaddstr(currwin, 0, maxw-6, "(more)");
! 264: if (yp + height == count)
! 265: for (i = 0; i < 6; i++)
! 266: mvwaddch(currwin, height+1, maxw-6+i, moresave[i][1]);
! 267: else
! 268: mvwaddstr(currwin, height+1, maxw-6, "(more)");
! 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) {
! 275: mvwaddch(currwin, 1+i-yp, 1, ' ' | a);
! 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;
! 281: mvwaddch(currwin, 1+i-yp, 2+x, c | a | a2);
! 282: }
! 283: for (; x < maxw-2; x++) {
! 284: mvwaddch(currwin, 1+i-yp, 2+x, ' ' | a);
! 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:
291: tui_refresh();
292: c = getch();
293: if (c == 27) {
294: tui_dlogdie(w);
295: return -1;
296: } else if (c == KEY_ENTER || c == 13 || c == ' ') {
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.2 root 333: if (menu[i].val == toupper(c)) {
334: tui_dlogdie(w);
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";
349: int n = strlen(hak);
350: int l = strlen(err);
351: int ww = (l > n ? l : n) + 2;
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.2 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.2 root 362: wrefresh(currwin);
363: for (;;) {
364: int c = getch();
365: if (c == 13)
366: break;
367: }
368: tui_dlogdie(w);
369: }
1.1 root 370:
371: static char *pattern;
372: static int maxlen;
373:
374: static void put_filename(char *s, int x, int y, attr_t a)
375: {
376: char buf[256];
377: int i;
378:
379: tui_gotoxy(x,y);
380: if (strcmp(s, ".") == 0)
381: strcpy(buf, "(none)");
382: else
383: strcpy(buf, s);
384: buf[maxlen] = 0;
385: for (i = 0; i < strlen(buf); i++)
386: waddch(currwin, buf[i] | a);
387: for (; i < maxlen; i++)
388: waddch(currwin, ' ' | a);
389: }
390:
391: static char fsbuf[256];
392:
393: static int selectfn(const struct dirent *de)
394: {
395: int l1, l2;
396:
397: /* l1 = strlen(pattern + 1);*/
398: l2 = strlen(de->d_name);
399:
400: if (l2 >= tui_cols()-10) /* Restrict length of filenames so we won't mess up the display */
401: return 0;
402:
403: /* No pattern matching for now. But we don't show hidden files. */
404: if (strcmp(de->d_name, ".") != 0 && strcmp(de->d_name, "..") != 0
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 */
427: if (getcwd(cwd, 256) == NULL)
428: return NULL;
429:
430: /* Change into directory of old file */
431: strcpy(fsbuf, oldfile);
432: tmp = strrchr(fsbuf, '/');
433: if (tmp != NULL) {
434: *tmp = 0;
435: if (strlen(fsbuf) > 0)
436: chdir(fsbuf);
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);
442: if (s[1] != 0 && strchr(s+1, '*') != NULL)
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.3 ! root 449: n = scandir(".", &names, selectfn, my_alphasort);
! 450:
1.1 root 451: if (n <= 0)
452: return NULL;
1.1.1.3 ! 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.3 ! root 459: w = tui_dlog(tui_cols() - maxlen - 8, 5, tui_cols() - 5, 5 + l + 1);
1.1 root 460: tui_selwin(w); tui_drawbox(w);
1.1.1.3 ! root 461: if (title)
! 462: mvwaddstr(currwin, 0, 2, title);
! 463: for (i = 0; i < 6; i++) {
! 464: moresave[i][0] = mvwinch(currwin, 0, maxlen-3+i);
! 465: moresave[i][1] = mvwinch(currwin, l+1, maxlen-3+i);
! 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++) {
477: put_filename(names[i + yp]->d_name, 3, 2 + i, 0);
478: }
479: }
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++)
! 484: mvwaddch(currwin, 0, maxlen-3+i, moresave[i][0]);
! 485: else
! 486: mvwaddstr(currwin, 0, maxlen-3, "(more)");
! 487: if (yp + l == n)
! 488: for (i = 0; i < 6; i++)
! 489: mvwaddch(currwin, l+1, maxlen-3+i, moresave[i][1]);
! 490: else
! 491: mvwaddstr(currwin, l+1, maxlen-3, "(more)");
! 492:
1.1 root 493: tui_refresh();
494: c = getch();
495: put_filename(names[s]->d_name, 3, 2 + s - yp, 0);
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 root 502: if (strcmp(names[s]->d_name, ".") == 0) {
503: fin = 1;
504: strcpy(fsbuf, "");
505: break;
506: }
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;
513: if (getcwd(fsbuf, 256) == NULL)
514: retval = NULL;
515: if (strlen(fsbuf) + strlen(names[s]->d_name) + 2 >= 256)
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.3 ! root 563: free(names[i]);
1.1 root 564: free(names);
565: #endif
566: tui_dlogdie(w);
567: }
568: chdir(cwd);
569: return retval;
570: }
571:
572: int tui_backup_optionsfile(void)
573: {
574: char tmp[257];
575: strcpy(tmp, optionsfile);
576: strcat(tmp, "~");
577: return rename(optionsfile, tmp);
578: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.