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