You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

459 lines
12 KiB

  1. /* $Id: slangui.c,v 1.11 2000/01/07 22:45:09 joeyh Exp $ */
  2. /* slangui.c - SLang user interface routines */
  3. /* TODO: the redraw code is a bit broken, also this module is using way too many
  4. * global vars */
  5. #include "slangui.h"
  6. #include <slang.h>
  7. #include <libintl.h>
  8. #include <stdlib.h>
  9. #include <string.h>
  10. #include <ctype.h>
  11. #include "data.h"
  12. #include "strutl.h"
  13. #include "macros.h"
  14. #include "help.h"
  15. /* Slang object number mapping */
  16. #define DEFAULTOBJ 0
  17. #define SHADOWOBJ 2 /* must be 2 due to slang weirdness */
  18. #define CHOOSEROBJ 1
  19. #define DESCOBJ 3
  20. #define STATUSOBJ 4
  21. #define DIALOGOBJ 5
  22. #define CURSOROBJ 6
  23. #define BUTTONOBJ 7
  24. #define CHOOSERWINDOW 0
  25. #define DESCWINDOW 1
  26. #define HELPWINDOW 2
  27. #define ROWS SLtt_Screen_Rows
  28. #define COLUMNS SLtt_Screen_Cols
  29. struct _chooserinfo_t {
  30. int coloffset;
  31. int rowoffset;
  32. int height;
  33. int width;
  34. int index;
  35. int topindex;
  36. int whichwindow;
  37. };
  38. /* Module private variables */
  39. static struct _chooserinfo_t _chooserinfo = {3, 3, 0, 0, 0, 0, 0};
  40. static int _resizing = 0;
  41. static int _initialized = 0;
  42. static struct packages_t *_packages = NULL;
  43. static struct packages_t *_taskpackages = NULL;
  44. static struct package_t **_taskpackagesary = NULL;
  45. static void write_centered_str(int row, int coloffset, int width, char *txt)
  46. {
  47. int col;
  48. int len = strlen(txt);
  49. if (txt == NULL) return;
  50. SLsmg_fill_region(row, coloffset, 1, width, ' ');
  51. if (coloffset + len >= width) col = 0;
  52. else col = (width - len) / 2;
  53. SLsmg_gotorc(row, coloffset + col);
  54. SLsmg_write_nstring(txt, width);
  55. }
  56. void ui_init(int argc, char * const argv[], struct packages_t *taskpkgs, struct packages_t *pkgs)
  57. {
  58. _taskpackages = taskpkgs;
  59. _taskpackagesary = packages_enumerate(taskpkgs);
  60. _packages = pkgs;
  61. SLang_set_abort_signal(NULL);
  62. /* assign attributes to objects */
  63. SLtt_set_color(DEFAULTOBJ, NULL, "white", "blue");
  64. SLtt_set_color(SHADOWOBJ, NULL, "gray", "black");
  65. SLtt_set_color(CHOOSEROBJ, NULL, "black", "lightgray");
  66. SLtt_set_color(CURSOROBJ, NULL, "lightgray", "blue");
  67. SLtt_set_color(DESCOBJ, NULL, "black", "cyan");
  68. SLtt_set_color(STATUSOBJ, NULL, "yellow", "blue");
  69. SLtt_set_color(DIALOGOBJ, NULL, "black", "lightgray");
  70. SLtt_set_color(BUTTONOBJ, NULL, "white", "blue");
  71. ui_resize();
  72. _initialized = 1;
  73. }
  74. int ui_shutdown(void)
  75. {
  76. SLsmg_reset_smg();
  77. SLang_reset_tty();
  78. _initialized = 0;
  79. return 0;
  80. }
  81. int ui_running(void)
  82. {
  83. return _initialized;
  84. }
  85. void ui_resize(void)
  86. {
  87. char buf[160];
  88. _resizing = 1;
  89. /* SIGWINCH handler */
  90. if (-1 == SLang_init_tty(-1, 0, 1)) DIE(_("Unable to initialize the terminal"));
  91. SLtt_get_terminfo();
  92. if (-1 == SLsmg_init_smg()) DIE(_("Unable to initialize screen output"));
  93. if (-1 == SLkp_init()) DIE(_("Unable to initialize keyboard interface"));
  94. /*
  95. if (SLtt_Screen_Rows < 20 || SLtt_Screen_Cols < 70) {
  96. DIE(_("Sorry, tasksel needs a terminal with at least 70 columns and 20 rows"));
  97. }
  98. */
  99. _chooserinfo.height = ROWS - 2 * _chooserinfo.rowoffset;
  100. _chooserinfo.width = COLUMNS - 2 *_chooserinfo.coloffset;
  101. SLsmg_cls();
  102. /* Show version and status lines */
  103. SLsmg_set_color(STATUSOBJ);
  104. snprintf(buf, 160, "%s v%s - %s",
  105. _("Debian Task Installer"), VERSION,
  106. _("(c) 1999 SPI and others"));
  107. SLsmg_gotorc(0, 0);
  108. SLsmg_write_nstring(buf, strlen(buf));
  109. write_centered_str(ROWS-1, 0, COLUMNS,
  110. _(" h - Help SPACE - Toggle selection i - Task info q - Exit"));
  111. _resizing = 0;
  112. switch (_chooserinfo.whichwindow) {
  113. case CHOOSERWINDOW: ui_drawscreen(); break;
  114. case HELPWINDOW: ui_showhelp(); break;
  115. case DESCWINDOW: ui_showpackageinfo(); break;
  116. }
  117. }
  118. int ui_eventloop(void)
  119. {
  120. int done = 0;
  121. int ret = 0;
  122. int c, i;
  123. _chooserinfo.topindex = 0;
  124. _chooserinfo.index = 0;
  125. ui_redrawcursor(0);
  126. while (!done) {
  127. c = SLkp_getkey();
  128. switch (c) {
  129. case SL_KEY_UP:
  130. case SL_KEY_LEFT:
  131. ui_clearcursor(_chooserinfo.index);
  132. if (_chooserinfo.index > 0)
  133. _chooserinfo.index--;
  134. else
  135. _chooserinfo.index = _taskpackages->count - 1;
  136. ui_redrawcursor(_chooserinfo.index);
  137. break;
  138. case SL_KEY_DOWN:
  139. case SL_KEY_RIGHT:
  140. ui_clearcursor(_chooserinfo.index);
  141. if (_chooserinfo.index < _taskpackages->count - 1)
  142. _chooserinfo.index++;
  143. else
  144. _chooserinfo.index = 0;
  145. ui_redrawcursor(_chooserinfo.index);
  146. break;
  147. case SL_KEY_PPAGE:
  148. ui_clearcursor(_chooserinfo.index);
  149. _chooserinfo.index -= _chooserinfo.height;
  150. if (_chooserinfo.index < 0) _chooserinfo.index = 0;
  151. ui_redrawcursor(_chooserinfo.index);
  152. break;
  153. case SL_KEY_NPAGE:
  154. ui_clearcursor(_chooserinfo.index);
  155. _chooserinfo.index += _chooserinfo.height;
  156. if (_chooserinfo.index >= _taskpackages->count - 1)
  157. _chooserinfo.index = _taskpackages->count - 1;
  158. ui_redrawcursor(_chooserinfo.index);
  159. break;
  160. case SL_KEY_ENTER: case '\r': case '\n':
  161. case ' ':
  162. ui_toggleselection(_chooserinfo.index);
  163. ui_redrawcursor(_chooserinfo.index);
  164. break;
  165. case 'A': case 'a':
  166. for (i = 0; i < _taskpackages->count; i++) _taskpackagesary[i]->selected = 1;
  167. ui_drawscreen();
  168. break;
  169. case 'N': case 'n':
  170. for (i = 0; i < _taskpackages->count; i++) _taskpackagesary[i]->selected = 0;
  171. ui_drawscreen();
  172. break;
  173. case 'H': case 'h': case SL_KEY_F(1): ui_showhelp(); break;
  174. case 'I': case 'i': ui_showpackageinfo(); break;
  175. case 'Q': case 'q': done = 1; break;
  176. }
  177. }
  178. return ret;
  179. }
  180. void ui_shadow(int y, int x, unsigned int dy, unsigned int dx)
  181. {
  182. int c;
  183. unsigned short ch;
  184. if (SLtt_Use_Ansi_Colors) {
  185. for (c=0;c<dy-1;c++) {
  186. SLsmg_gotorc(c+1+y, x+dx);
  187. /*
  188. * Note: 0x02 corresponds to the current color. 0x80FF gets the
  189. * character plus alternate character set attribute. -- JED
  190. */
  191. ch = SLsmg_char_at();
  192. ch = (ch & 0x80FF) | (0x02 << 8);
  193. SLsmg_write_raw(&ch, 1);
  194. }
  195. for (c=0;c<dx;c++) {
  196. SLsmg_gotorc(y+dy, x+1+c);
  197. ch = SLsmg_char_at();
  198. ch = (ch & 0x80FF) | (0x02 << 8);
  199. SLsmg_write_raw(&ch, 1);
  200. }
  201. }
  202. }
  203. int ui_drawbox(int obj, int r, int c, unsigned int dr, unsigned int dc,
  204. int shadow)
  205. {
  206. if (shadow)
  207. ui_shadow(r, c, dr, dc);
  208. SLsmg_set_color(obj);
  209. SLsmg_draw_box(r, c, dr, dc);
  210. SLsmg_fill_region(r+1, c+1, dr-2, dc-2, ' ');
  211. return 0;
  212. }
  213. int ui_drawscreen(void)
  214. {
  215. int i;
  216. /* Draw the chooser screen */
  217. SLsmg_set_color(DEFAULTOBJ);
  218. ui_drawbox(CHOOSEROBJ, _chooserinfo.rowoffset - 1, _chooserinfo.coloffset - 1, _chooserinfo.height + 2, _chooserinfo.width + 2, 1);
  219. ui_title(_chooserinfo.rowoffset - 1, _chooserinfo.coloffset - 1, COLUMNS - 3,
  220. _("Select task packages to install"));
  221. for (i = _chooserinfo.topindex; i < _chooserinfo.topindex + _chooserinfo.height; i++)
  222. if (i < _taskpackages->count) ui_drawchooseritem(i);
  223. ui_redrawcursor(_chooserinfo.index);
  224. SLsmg_refresh();
  225. return 0;
  226. }
  227. void ui_button(int row, int col, char *txt)
  228. {
  229. SLsmg_set_color(BUTTONOBJ);
  230. SLsmg_gotorc(row, col);
  231. SLsmg_write_char('<');
  232. SLsmg_write_string(txt);
  233. SLsmg_write_char('>');
  234. }
  235. void ui_title(int row, int col, int width, char *title)
  236. {
  237. int pos = col + (width - strlen(title))/2;
  238. SLsmg_gotorc(row, pos - 1);
  239. SLsmg_set_char_set(1);
  240. SLsmg_write_char(SLSMG_RTEE_CHAR);
  241. SLsmg_set_char_set(0);
  242. SLsmg_write_char(' ');
  243. SLsmg_write_string(title);
  244. SLsmg_write_char(' ');
  245. SLsmg_set_char_set(1);
  246. SLsmg_write_char(SLSMG_LTEE_CHAR);
  247. SLsmg_set_char_set(0);
  248. }
  249. void ui_dialog(int row, int col, int height, int width, char *title, char *msg, int reflow)
  250. {
  251. char *reflowbuf;
  252. int ri, c;
  253. char *line, *txt;
  254. if (reflow)
  255. reflowbuf = reflowtext(width - 2, msg);
  256. else
  257. reflowbuf = msg;
  258. SLsmg_set_color(DIALOGOBJ);
  259. ui_drawbox(DIALOGOBJ, row, col, height, width, 1);
  260. SLsmg_fill_region(row+1, col+1, height-2, width-2, ' ');
  261. if (title)
  262. ui_title(row, col, width, title);
  263. if (reflowbuf != NULL) {
  264. txt = reflowbuf;
  265. ri = 0;
  266. while ((line = strsep(&txt, "\n")) && (ri < height - 3)) {
  267. SLsmg_gotorc(row + 1 + ri, col + 1);
  268. SLsmg_write_nstring(line, width - 2);
  269. ri++;
  270. }
  271. }
  272. ui_button(row+height-2, col+(width-4)/2, "Ok");
  273. SLsmg_refresh();
  274. SLsig_block_signals();
  275. do {
  276. c = 0;
  277. if (SLang_input_pending(5)) c = SLkp_getkey();
  278. } while (!(c == '\n' || c == '\r' || c == SL_KEY_ENTER || isspace(c)) && (_resizing == 0));
  279. SLsig_unblock_signals();
  280. if (reflow) FREE(reflowbuf);
  281. }
  282. void ui_drawchooseritem(int index)
  283. {
  284. char buf[1024];
  285. ASSERT(_taskpackages != NULL);
  286. if (index >= _taskpackages->count) DIE("Index out of bounds: %d >= %d", index, _taskpackages->count);
  287. if (index < _chooserinfo.topindex) return;
  288. SLsmg_set_color(CHOOSEROBJ);
  289. SLsmg_gotorc(_chooserinfo.rowoffset + index - _chooserinfo.topindex, _chooserinfo.coloffset + 1);
  290. snprintf(buf, 1024, "[%c] %s",
  291. (_taskpackagesary[index]->selected == 0 ? ' ' : '*'),
  292. _taskpackagesary[index]->prettyname);
  293. /* I fear the 1 below is an off-by-one error somewhere -- Joeyh */
  294. SLsmg_write_nstring(buf, _chooserinfo.width - 1);
  295. SLsmg_gotorc(_chooserinfo.rowoffset + index - _chooserinfo.topindex, _chooserinfo.coloffset + _taskpackages->maxnamelen + 5);
  296. SLsmg_write_nstring(_taskpackagesary[index]->shortdesc, _chooserinfo.width - _taskpackages->maxnamelen - 5);
  297. }
  298. void ui_toggleselection(int index)
  299. {
  300. ASSERT(_taskpackages != NULL);
  301. if (index >= _taskpackages->count) DIE("Index out of bounds: %d >= %d", index, _taskpackages->count);
  302. if (_taskpackagesary[index]->selected == 0)
  303. _taskpackagesary[index]->selected = 1;
  304. else
  305. _taskpackagesary[index]->selected = 0;
  306. SLsmg_set_color(CHOOSEROBJ);
  307. SLsmg_gotorc(_chooserinfo.rowoffset + index - _chooserinfo.topindex, _chooserinfo.coloffset + 1);
  308. if (_taskpackagesary[index]->selected == 0)
  309. SLsmg_write_string("[ ]");
  310. else
  311. SLsmg_write_string("[*]");
  312. SLsmg_gotorc(_chooserinfo.rowoffset + index - _chooserinfo.topindex, _chooserinfo.coloffset + 3);
  313. SLsmg_refresh();
  314. }
  315. void ui_redrawchooser(void)
  316. {
  317. int i;
  318. for (i = _chooserinfo.topindex; i < _chooserinfo.topindex + _chooserinfo.height; i++)
  319. if (i < _taskpackages->count) ui_drawchooseritem(i);
  320. }
  321. void ui_redrawcursor(int index)
  322. {
  323. /* Check to see if we have to scroll the selection */
  324. if (index + 1 - _chooserinfo.height > _chooserinfo.topindex) {
  325. _chooserinfo.topindex = index + 1 - _chooserinfo.height;
  326. ui_redrawchooser();
  327. } else if (index < _chooserinfo.topindex) {
  328. _chooserinfo.topindex = 0;
  329. ui_redrawchooser();
  330. }
  331. SLsmg_set_color(CURSOROBJ);
  332. SLsmg_gotorc(_chooserinfo.rowoffset + index - _chooserinfo.topindex, _chooserinfo.coloffset + 2);
  333. SLsmg_write_string(_taskpackagesary[index]->selected == 0 ? " " : "*");
  334. SLsmg_refresh();
  335. }
  336. void ui_clearcursor(int index)
  337. {
  338. SLsmg_set_color(DIALOGOBJ);
  339. SLsmg_gotorc(_chooserinfo.rowoffset + index - _chooserinfo.topindex, _chooserinfo.coloffset + 2);
  340. SLsmg_write_string(_taskpackagesary[index]->selected == 0 ? " " : "*");
  341. }
  342. void ui_showhelp(void)
  343. {
  344. _chooserinfo.whichwindow = HELPWINDOW;
  345. ui_dialog(3, 3, ROWS - 9, COLUMNS - 10, _("Help"), HELPTXT, 1);
  346. _chooserinfo.whichwindow = CHOOSERWINDOW;
  347. ui_drawscreen();
  348. }
  349. void ui_showpackageinfo(void)
  350. {
  351. struct package_t *pkg, *deppkg;
  352. int i;
  353. int width = COLUMNS - 6;
  354. char buf[4096];
  355. char shortbuf[256];
  356. char *desc = NULL;
  357. int bufleft;
  358. int index = _chooserinfo.index;
  359. ASSERT(_taskpackages != NULL);
  360. _chooserinfo.whichwindow = DESCWINDOW;
  361. if (index >= _taskpackages->count) DIE("Index out of bounds: %d >= %d", index, _taskpackages->count);
  362. pkg = _taskpackagesary[index];
  363. ASSERT(pkg != NULL);
  364. desc = reflowtext(width, pkg->longdesc);
  365. /* pack buf with package info */
  366. snprintf(buf, sizeof(buf), "Description:\n%s\n\nDependent packages:\n", desc);
  367. FREE(desc);
  368. bufleft = sizeof(buf) - strlen(buf) - 1;
  369. ASSERT(width < sizeof(shortbuf));
  370. for (i = 0; i < pkg->dependscount; i++) {
  371. deppkg = packages_find(_packages, pkg->depends[i]);
  372. snprintf(shortbuf, sizeof(shortbuf), "%s - %s\n", pkg->depends[i],
  373. ((deppkg && deppkg->shortdesc) ? deppkg->shortdesc : _("(no description available)")));
  374. strncat(buf, shortbuf, bufleft);
  375. bufleft = sizeof(buf) - strlen(buf) - 1;
  376. }
  377. ui_dialog(2, 2, ROWS-4, COLUMNS-4, pkg->name, buf, 0);
  378. _chooserinfo.whichwindow = CHOOSERWINDOW;
  379. ui_drawscreen();
  380. }