4 A Programmer's Text Editor
8 Copyright (C) 1991-2007 Angel Ortega <angel@triptico.com>
10 This program is free software; you can redistribute it and/or
11 modify it under the terms of the GNU General Public License
12 as published by the Free Software Foundation; either version 2
13 of the License, or (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 http://www.triptico.com
28 /* main TUI namspace */
34 mp.colors.menu = { 'text' => [ 'white', 'blue' ], 'flags' => [ 'bright' ] };
38 sub mp.tui.prompt(prompt, y)
39 /* draw a prompt on screen */
41 /* no y? default to last line */
45 /* delete all possible newlines */
46 prompt = sregex("/\n/g", prompt, ' ');
48 mp.tui.attr(mp.colors.menu.attr);
50 mp.tui.addstr(prompt);
51 mp.tui.attr(mp.colors.normal.attr);
56 sub mp.tui.readline(prompt, history, default, flags)
57 /* the readline function, with special functionality in 'flags' */
61 mp.tui.prompt(prompt ~ ' ', flags.y);
65 /* get the history stack */
66 h = mp.get_history(history);
71 /* store in c[2] the usable size */
72 push(c, mp.window.tx - c[0] - 1);
78 /* is the string bigger than the usable size? */
79 if (size(r) >= c[2]) {
80 /* if x is beyond the usable size,
85 s = splice(s, NULL, v, c[2]);
89 /* if it's a password, change everything to asterisks */
91 s = sregex('/./g', s, flags.password);
93 /* draws the string */
94 mp.tui.move(c[0], c[1], 1);
96 mp.tui.move(c[0] + x - v, c[1]);
98 local k = mp.tui.getkey();
111 if (k eq 'backspace' && x > 0) {
113 r = splice(r, NULL, x, 1);
118 r = splice(r, NULL, x, 1);
128 r = splice(r, NULL, x, -1);
132 if (k eq 'cursor-up' && size(h)) {
138 if (k eq 'cursor-down' && size(h)) {
144 if (k eq 'cursor-left' && x > 0) {
148 if (k eq 'cursor-right' && x < size(r)) {
160 if (k eq 'tab' && flags.file) {
161 local l = glob(r ~ '*');
164 local p = mp.tui.list(prompt, l, 0);
176 r = splice(r, k, x, 0);
182 /* if a string was accepted, store in the history */
183 if (h != NULL && size(r) && h[-1] ne r)
190 sub mp.tui.list(prompt, data, pos)
191 /* select from a list */
195 mp.tui.attr(mp.colors.menu.attr);
196 mp.tui.move(0, 0, 1);
197 mp.tui.addstr(prompt);
198 mp.tui.attr(mp.colors.normal.attr);
201 ty = mp.window.ty - 1;
204 r = '/^.{1,' ~ (mp.window.tx) ~ '}/';
215 if (pos >= size(data))
216 pos = size(data) - 1;
224 /* draw all the lines */
227 local l = data[n + vy];
233 mp.tui.move(0, n + 1, 1);
236 mp.tui.attr(mp.colors.cursor.attr);
238 mp.tui.attr(mp.colors.normal.attr);
240 mp.tui.addstr(regex(r,
241 sprintf("%-" ~ mp.window.tx ~ "s", l)));
246 /* clean the rest of lines */
247 mp.tui.attr(mp.colors.normal.attr);
249 mp.tui.move(0, n + 1, 1);
255 if (k eq 'cursor-up')
258 if (k eq 'cursor-down')
264 if (k eq 'page-down')
271 pos = size(data) - 1;
286 sub mp.tui.confirm(msg, def, ypos)
291 /* get the initials for localized 'Yes' and 'No' */
292 y = regex('/^./', L("Yes"));
293 n = regex('/^./', L("No"));
296 msg = msg ~ ' (' ~ y ~ '/' ~ n ~ ')';
299 /* a default option? add to prompt */
300 msg = msg ~ ' [' ~ (def && y || n) ~ ']';
303 mp.tui.prompt(msg, ypos);
305 while (ret == NULL) {
306 local k = mp.tui.getkey();
308 if (regex('/^' ~ y ~ '$/i', k))
310 if (regex('/^' ~ n ~ '$/i', k))
315 ret = (def && 1 || 2);
323 sub mp.drv.alert(msg)
325 mp.tui.prompt(msg ~ L(" [ENTER]"));
327 while (mp.tui.getkey() ne 'enter');
331 sub mp.drv.openfile(prompt)
333 mp.tui.readline(prompt, 'openfile', NULL, { 'file' => 1 } );
337 sub mp.drv.savefile(prompt)
339 mp.tui.readline(prompt, 'savefile', NULL, { 'file' => 1 } );
343 sub mp.drv.confirm(msg, def)
345 mp.tui.confirm(msg, def);
349 sub mp.drv.form(widgets)
352 local pos = mp.window.ty - size(widgets);
355 /* print first all prompts */
356 foreach (w, widgets) {
357 if (w.type ne 'list')
358 mp.tui.prompt(w.label, y++);
363 /* now iterate widgets */
364 foreach (w, widgets) {
367 if (w.type eq 'text')
368 r1 = mp.tui.readline(w.label, w.history, w.value,
371 if (w.type eq 'password')
372 r1 = mp.tui.readline(w.label, NULL, NULL,
373 { 'password' => '*', 'y' => y });
375 if (w.type eq 'checkbox') {
376 /* return value conversion */
377 local c = [ NULL, 1, 0 ];
379 r1 = c[mp.tui.confirm(w.label, w.value, y)];
382 if (w.type eq 'list')
383 r1 = mp.tui.list(w.label, w.list, w.value);
406 while (action == NULL && key ne 'escape') {
412 mx = size(mp.menu) - 1;
413 if (mx >= size(mp.menu))
416 /* draw the menu bar */
417 mp.tui.attr(mp.colors.menu.attr);
418 mp.tui.move(0, 0, 1);
420 while (n < size(mp.menu)) {
422 local l = L(mp.menu[n][0]);
424 /* strip (by now) the & */
425 l = sregex('/&/g', l, NULL);
427 mp.tui.attr(mp.colors.menu.attr);
431 pos = mp.tui.getxy();
432 mp.tui.attr(mp.colors.cursor.attr);
440 /* get the menu options */
443 /* calculate panel optimal dimensions */
447 local l = mp.menu_label(i);
449 if (size(l) > pos[2])
453 /* if the panel will surpass the right margin,
455 if (pos[0] + pos[2] > mp.window.tx - 2)
456 pos[0] = mp.window.tx - pos[2] - 2;
459 mp.tui.attr(mp.colors.menu.attr);
460 mp.tui.openpanel(pos[0], 1, pos[2] + 2, size(mo) + 2);
464 while (key ne 'escape') {
465 /* draw the options */
467 while (n < size(mo)) {
468 local l = mp.menu_label(mo[n]);
472 mp.tui.attr(mp.colors.cursor.attr);
474 mp.tui.attr(mp.colors.menu.attr);
477 mp.tui.move(1, 1 + n);
478 mp.tui.addstr(sprintf("%-" ~ pos[2] ~ "s", l));
484 /* move the hw cursor to the selected option */
485 mp.tui.move(1, 1 + my);
489 key = mp.tui.getkey();
491 if (key eq 'cursor-up') {
492 /* move up avoiding separators */
502 if (key eq 'cursor-down') {
503 /* move down avoiding separators */
505 if (++my >= size(mo))
513 if (key eq 'cursor-right') {
518 if (key eq 'cursor-left') {
523 if (key eq 'enter') {
532 mp.tui.attr(mp.color.normal.attr);
535 mp.process_action(action);
541 sub mp.drv.busy(onoff)
543 mp.tui.prompt(onoff && L("Please, wait...") || '');
547 /* returns the main namespace */