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.
 
 
 

870 lines
23 KiB

  1. /* $Id: slangui.c,v 1.24 2001/11/22 17:53:48 tausq Rel $ */
  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 "tasksel.h"
  6. #include "slangui.h"
  7. #include <slang.h>
  8. #include <libintl.h>
  9. #include <stdlib.h>
  10. #include <string.h>
  11. #include <ctype.h>
  12. #include "data.h"
  13. #include "util.h"
  14. #include "strutl.h"
  15. #include "macros.h"
  16. #define TASK_SHORTDESC(t) ((t)->task_pkg ? (t)->task_pkg->shortdesc : _("(no description)"))
  17. #define TASK_LONGDESC(t) ((t)->task_pkg ? (t)->task_pkg->longdesc : _("(no description)"))
  18. #define TASK_SECTION(t) ((t)->task_pkg && (t)->task_pkg->section ? (t)->task_pkg->section : "misc")
  19. /* Slang object number mapping */
  20. #define DEFAULTOBJ 0
  21. #define SHADOWOBJ 2 /* must be 2 due to slang weirdness */
  22. #define CHOOSEROBJ 1
  23. #define DESCOBJ 3
  24. #define STATUSOBJ 4
  25. #define DIALOGOBJ 5
  26. #define CURSOROBJ 6
  27. #define SELBUTTONOBJ 7
  28. #define BUTTONOBJ 8
  29. #define SELHIGHLIGHT 9
  30. #define HIGHLIGHT 10
  31. #define SCROLLBAR 11
  32. #define CHOOSERWINDOW 0
  33. #define DESCWINDOW 1
  34. #define HELPWINDOW 2
  35. #define NUM_BUTTONS 3
  36. #define BUTTON_NONE 0
  37. #define BUTTON_FINISH 1
  38. #define BUTTON_INFO 2
  39. #define BUTTON_HELP 3
  40. #define SCROLLBAR_NONE 0
  41. #define SCROLLBAR_HORIZ 1
  42. #define SCROLLBAR_VERT 2
  43. #define ROWS SLtt_Screen_Rows
  44. #define COLUMNS SLtt_Screen_Cols
  45. struct _chooserinfo_t {
  46. int coloffset;
  47. int rowoffset;
  48. int height;
  49. int width;
  50. int index;
  51. int topindex;
  52. int whichwindow;
  53. };
  54. /* Module private variables */
  55. static struct _chooserinfo_t _chooserinfo = {3, 3, 0, 0, 0, 0, 0};
  56. static int _resizing = 0;
  57. static int _initialized = 0;
  58. static struct packages_t *_packages = NULL;
  59. static struct tasks_t *_tasks = NULL;
  60. static struct task_t **_tasksary = NULL;
  61. static int *_displayhint = NULL;
  62. static int _displaylines;
  63. struct { char *section, *desc; } sectiondesc[] = {
  64. { "user", N_("End-user") },
  65. { "server", N_("Servers") },
  66. { "devel", N_("Development") },
  67. { "l10n", N_("Localization") },
  68. { "hware", N_("Hardware Support") },
  69. { "misc", N_("Miscellaneous") },
  70. {0}
  71. };
  72. static char *getsectiondesc(char *sec) {
  73. int i;
  74. for (i = 0; sectiondesc[i].section; i++)
  75. if (strcmp(sec, sectiondesc[i].section) == 0)
  76. return _(sectiondesc[i].desc);
  77. return sec;
  78. }
  79. static void initdisplayhints(void) {
  80. int i, j, k;
  81. char *lastsec = NULL;
  82. _displaylines = 0;
  83. for (i = 0; i < _tasks->count; i++) {
  84. char *sec = TASK_SECTION(_tasksary[i]);
  85. if (lastsec == NULL || strcmp(lastsec, sec) != 0) {
  86. _displaylines++;
  87. lastsec = sec;
  88. }
  89. _displaylines++;
  90. }
  91. _displayhint = MALLOC(sizeof(int)*_displaylines);
  92. k = 0;
  93. for (i = 0; sectiondesc[i].section; i++) {
  94. for (j = 0; j < _tasks->count; j++) {
  95. char *sec = TASK_SECTION(_tasksary[j]);
  96. if (strcmp(sec, sectiondesc[i].section) == 0) {
  97. _displayhint[k++] = -1;
  98. for (; j < _tasks->count; j++) {
  99. char *sec = TASK_SECTION(_tasksary[j]);
  100. if (strcmp(sec, sectiondesc[i].section) == 0) {
  101. _displayhint[k++] = j;
  102. }
  103. }
  104. break;
  105. }
  106. }
  107. }
  108. lastsec = NULL;
  109. for (i = 0; i < _tasks->count; i++) {
  110. char *sec = TASK_SECTION(_tasksary[i]);
  111. for (j = 0; sectiondesc[j].section; j++) {
  112. if (strcmp(sectiondesc[j].section, sec) == 0) {
  113. j = -1; break;
  114. }
  115. }
  116. if (j == -1) continue;
  117. if (lastsec == NULL || strcmp(lastsec, sec) != 0) {
  118. _displayhint[k++] = -1;
  119. lastsec = sec;
  120. }
  121. _displayhint[k++] = i;
  122. }
  123. }
  124. int taskseccompare(const void *pl, const void *pr)
  125. {
  126. const struct task_t *l = *((const struct task_t **)pl);
  127. const struct task_t *r = *((const struct task_t **)pr);
  128. char *ls = NULL, *rs = NULL;
  129. int y = strcmp(l->name, r->name);
  130. if (y == 0) return 0;
  131. if (l->task_pkg && l->task_pkg->section) ls = l->task_pkg->section;
  132. if (r->task_pkg && r->task_pkg->section) rs = r->task_pkg->section;
  133. if (ls && rs) {
  134. int x = strcmp(ls, rs);
  135. if (x != 0) return x;
  136. } else if (ls) {
  137. return -1;
  138. } else if (rs) {
  139. return 1;
  140. }
  141. return y;
  142. }
  143. void ui_init(int argc, char * const argv[], struct tasks_t *tasks, struct packages_t *pkgs)
  144. {
  145. _tasks = tasks;
  146. _tasksary = tasks_enumerate(tasks);
  147. qsort(_tasksary, _tasks->count, sizeof(_tasksary[0]), taskseccompare);
  148. initdisplayhints();
  149. _packages = pkgs;
  150. SLang_set_abort_signal(tasksel_signalhandler);
  151. /* assign attributes to objects */
  152. SLtt_set_color(DEFAULTOBJ, NULL, "white", "blue");
  153. SLtt_set_color(SHADOWOBJ, NULL, "gray", "black");
  154. SLtt_set_color(CHOOSEROBJ, NULL, "black", "lightgray");
  155. SLtt_set_color(CURSOROBJ, NULL, "blue", "lightgray");
  156. SLtt_set_color(DESCOBJ, NULL, "black", "cyan");
  157. SLtt_set_color(STATUSOBJ, NULL, "yellow", "blue");
  158. SLtt_set_color(DIALOGOBJ, NULL, "black", "lightgray");
  159. SLtt_set_color(SELBUTTONOBJ, NULL, "lightgray", "blue");
  160. SLtt_set_color(BUTTONOBJ, NULL, "lightgray", "red");
  161. SLtt_set_color(SELHIGHLIGHT, NULL, "white", "blue");
  162. SLtt_set_color(HIGHLIGHT, NULL, "white", "red");
  163. SLtt_set_color(SCROLLBAR, NULL, "black", "lightgray");
  164. ui_resize();
  165. _initialized = 1;
  166. }
  167. int ui_shutdown(void)
  168. {
  169. SLsmg_reset_smg();
  170. SLang_reset_tty();
  171. _initialized = 0;
  172. return 0;
  173. }
  174. int ui_running(void)
  175. {
  176. return _initialized;
  177. }
  178. void ui_resize(void)
  179. {
  180. char buf[160];
  181. _resizing = 1;
  182. /* SIGWINCH handler */
  183. if (-1 == SLang_init_tty(-1, 0, 1)) DIE(_("Unable to initialize the terminal"));
  184. SLtt_get_terminfo();
  185. if (-1 == SLsmg_init_smg()) DIE(_("Unable to initialize screen output"));
  186. if (-1 == SLkp_init()) DIE(_("Unable to initialize keyboard interface"));
  187. /*
  188. if (SLtt_Screen_Rows < 20 || SLtt_Screen_Cols < 70) {
  189. DIE(_("Sorry, tasksel needs a terminal with at least 70 columns and 20 rows"));
  190. }
  191. */
  192. _chooserinfo.height = ROWS - 2 * _chooserinfo.rowoffset - 3;
  193. _chooserinfo.width = COLUMNS - 2 *_chooserinfo.coloffset;
  194. SLsmg_cls();
  195. /* Show version and status lines */
  196. SLsmg_set_color(STATUSOBJ);
  197. snprintf(buf, 160,
  198. _("Debian Task Installer v%s - (c) 1999-2001 SPI and others"),
  199. VERSION);
  200. SLsmg_gotorc(0, 0);
  201. SLsmg_write_nstring(buf, strlen(buf));
  202. _resizing = 0;
  203. switch (_chooserinfo.whichwindow) {
  204. case CHOOSERWINDOW: ui_drawscreen(); break;
  205. case HELPWINDOW: ui_showhelp(); break;
  206. case DESCWINDOW: ui_showpackageinfo(); break;
  207. }
  208. }
  209. int ui_eventloop(void)
  210. {
  211. int done = 0;
  212. int ret = 0;
  213. int c, i;
  214. int onitem = 0;
  215. _chooserinfo.topindex = 0;
  216. _chooserinfo.index = 0;
  217. ui_redrawcursor(0);
  218. while (!done) {
  219. c = SLkp_getkey();
  220. switch (c) {
  221. case SL_KEY_LEFT:
  222. onitem = ui_cycleselection(-1);
  223. SLsmg_refresh();
  224. break;
  225. case SL_KEY_UP:
  226. ui_clearcursor(_chooserinfo.index);
  227. if (_chooserinfo.index > 0)
  228. _chooserinfo.index--;
  229. else
  230. _chooserinfo.index = _displaylines - 1;
  231. ui_redrawcursor(_chooserinfo.index);
  232. break;
  233. case SL_KEY_RIGHT:
  234. onitem = ui_cycleselection(1);
  235. SLsmg_refresh();
  236. break;
  237. case SL_KEY_DOWN:
  238. ui_clearcursor(_chooserinfo.index);
  239. if (_chooserinfo.index < _displaylines - 1)
  240. _chooserinfo.index++;
  241. else
  242. _chooserinfo.index = 0;
  243. ui_redrawcursor(_chooserinfo.index);
  244. break;
  245. case SL_KEY_PPAGE:
  246. ui_clearcursor(_chooserinfo.index);
  247. _chooserinfo.index -= _chooserinfo.height;
  248. if (_chooserinfo.index < 0) _chooserinfo.index = 0;
  249. ui_redrawcursor(_chooserinfo.index);
  250. break;
  251. case SL_KEY_NPAGE:
  252. ui_clearcursor(_chooserinfo.index);
  253. _chooserinfo.index += _chooserinfo.height;
  254. if (_chooserinfo.index > _displaylines - 1)
  255. _chooserinfo.index = _displaylines - 1;
  256. ui_redrawcursor(_chooserinfo.index);
  257. break;
  258. case SL_KEY_ENTER: case '\r': case '\n':
  259. case ' ':
  260. if (onitem == BUTTON_NONE) {
  261. ui_toggleselection(_chooserinfo.index);
  262. ui_redrawcursor(_chooserinfo.index);
  263. }
  264. else if (onitem == BUTTON_FINISH) {
  265. done = 1;
  266. }
  267. else if (onitem == BUTTON_INFO) {
  268. ui_showpackageinfo();
  269. }
  270. else if (onitem == BUTTON_HELP) {
  271. ui_showhelp();
  272. }
  273. break;
  274. case '\t':
  275. onitem = ui_cycleselection(1);
  276. SLsmg_refresh();
  277. break;
  278. case 'A': case 'a':
  279. for (i = 0; i < _tasks->count; i++) _tasksary[i]->selected = 1;
  280. ui_drawscreen();
  281. break;
  282. case 'N': case 'n':
  283. for (i = 0; i < _tasks->count; i++) _tasksary[i]->selected = 0;
  284. ui_drawscreen();
  285. break;
  286. case 'H': case 'h': case SL_KEY_F(1): ui_showhelp(); break;
  287. case 'I': case 'i': ui_showpackageinfo(); break;
  288. case 'F': case 'f': case 'Q': case 'q': done = 1; break;
  289. }
  290. }
  291. return ret;
  292. }
  293. void ui_shadow(int y, int x, unsigned int dy, unsigned int dx)
  294. {
  295. int c;
  296. unsigned short ch;
  297. if (SLtt_Use_Ansi_Colors) {
  298. for (c=0;c<dy-1;c++) {
  299. SLsmg_gotorc(c+1+y, x+dx);
  300. /*
  301. * Note: 0x02 corresponds to the current color. 0x80FF gets the
  302. * character plus alternate character set attribute. -- JED
  303. */
  304. ch = SLsmg_char_at();
  305. ch = (ch & 0x80FF) | (0x02 << 8);
  306. SLsmg_write_raw(&ch, 1);
  307. }
  308. for (c=0;c<dx;c++) {
  309. SLsmg_gotorc(y+dy, x+1+c);
  310. ch = SLsmg_char_at();
  311. ch = (ch & 0x80FF) | (0x02 << 8);
  312. SLsmg_write_raw(&ch, 1);
  313. }
  314. }
  315. }
  316. int ui_drawbox(int obj, int r, int c, unsigned int dr, unsigned int dc,
  317. int shadow)
  318. {
  319. if (shadow)
  320. ui_shadow(r, c, dr, dc);
  321. SLsmg_set_color(obj);
  322. SLsmg_draw_box(r, c, dr, dc);
  323. SLsmg_fill_region(r+1, c+1, dr-2, dc-2, ' ');
  324. return 0;
  325. }
  326. void _drawbutton(int which, int issel)
  327. {
  328. switch (which) {
  329. case BUTTON_FINISH: // Left justified
  330. ui_button(_chooserinfo.rowoffset + _chooserinfo.height + 1,
  331. _chooserinfo.coloffset + 3, _("^Finish"), issel);
  332. break;
  333. case BUTTON_INFO: //Centered
  334. /*
  335. * TODO: This centering isn't perfect, since it doesn't take the size
  336. * of the other buttons into account.
  337. */
  338. ui_button(_chooserinfo.rowoffset + _chooserinfo.height + 1,
  339. _chooserinfo.coloffset + (_chooserinfo.width - strlen(_("Task ^Info")) + 1) / 2,
  340. _("Task ^Info"), issel);
  341. break;
  342. case BUTTON_HELP: // Right justified
  343. ui_button(_chooserinfo.rowoffset + _chooserinfo.height + 1,
  344. _chooserinfo.coloffset + _chooserinfo.width - 5 - strlen(_("^Help")) + 1,
  345. _("^Help"), issel);
  346. break;
  347. }
  348. }
  349. int ui_cycleselection(int amount)
  350. {
  351. static int whichsel = 0;
  352. _drawbutton(whichsel, 0);
  353. ui_redrawcursor(_chooserinfo.index);
  354. whichsel = whichsel + amount;
  355. if (whichsel > NUM_BUTTONS)
  356. whichsel = 0;
  357. else if (whichsel < 0)
  358. whichsel = NUM_BUTTONS;
  359. if (whichsel > 0)
  360. _drawbutton(whichsel, 1);
  361. ui_redrawcursor(_chooserinfo.index);
  362. return whichsel;
  363. }
  364. int ui_drawscreen(void)
  365. {
  366. int i;
  367. /* Draw the chooser screen */
  368. SLsmg_set_color(DEFAULTOBJ);
  369. ui_drawbox(CHOOSEROBJ, _chooserinfo.rowoffset - 1, _chooserinfo.coloffset - 1, _chooserinfo.height + 5, _chooserinfo.width + 2, 1);
  370. ui_title(_chooserinfo.rowoffset - 1, _chooserinfo.coloffset - 1, COLUMNS - 3,
  371. _("Select tasks to install"));
  372. for (i = _chooserinfo.topindex; i < _chooserinfo.topindex + _chooserinfo.height; i++)
  373. ui_drawchooseritem(i);
  374. ui_vscrollbar(_chooserinfo.rowoffset, _chooserinfo.coloffset + _chooserinfo.width - 1, _chooserinfo.height, 0);
  375. for (i = 0; i <= NUM_BUTTONS; i++)
  376. _drawbutton(i, 0);
  377. ui_cycleselection(0);
  378. SLsmg_refresh();
  379. return 0;
  380. }
  381. /* Widgets */
  382. void ui_vscrollbar(int row, int col, int height, double percent)
  383. {
  384. int i;
  385. /* fudge the percent a bit -- this makes sure it shows up properly */
  386. percent -= 0.05;
  387. if (percent < 0.01) percent = 0.01;
  388. if (percent > 100.0) percent = 100.0;
  389. SLsmg_set_color(SCROLLBAR);
  390. for (i = 0; i < height; i++) {
  391. SLsmg_gotorc(row+i, col);
  392. if (((double)i)/height < percent &&
  393. ((double)i+1)/height >= percent) {
  394. SLsmg_set_char_set(1);
  395. SLsmg_write_char(SLSMG_DIAMOND_CHAR);
  396. SLsmg_set_char_set(0);
  397. /* SLsmg_write_char('#'); */
  398. } else {
  399. SLsmg_set_char_set(1);
  400. SLsmg_write_char(SLSMG_CKBRD_CHAR);
  401. SLsmg_set_char_set(0);
  402. }
  403. }
  404. }
  405. void ui_hscrollbar(int row, int col, int width, double percent)
  406. {
  407. int i;
  408. /* fudge the percent a bit -- this makes sure it shows up properly */
  409. percent -= 0.05;
  410. if (percent < 0.01) percent = 0.01;
  411. if (percent > 100.0) percent = 100.0;
  412. SLsmg_set_color(SCROLLBAR);
  413. for (i = 0; i < width; i++) {
  414. SLsmg_gotorc(row, col+i);
  415. if (((double)i)/width < percent &&
  416. ((double)i+1)/width >= percent) {
  417. SLsmg_write_char('#');
  418. } else {
  419. SLsmg_set_char_set(1);
  420. SLsmg_write_char(SLSMG_CKBRD_CHAR);
  421. SLsmg_set_char_set(0);
  422. }
  423. }
  424. }
  425. void ui_button(int row, int col, char *txt, int selected)
  426. {
  427. char *p;
  428. if (selected)
  429. SLsmg_set_color(SELBUTTONOBJ);
  430. else
  431. SLsmg_set_color(BUTTONOBJ);
  432. SLsmg_gotorc(row, col);
  433. SLsmg_write_char('<');
  434. /* Anything following a ^ in txt is highlighted, and the ^ removed. */
  435. p = strchr(txt, '^');
  436. if (p) {
  437. if (p > txt) {
  438. SLsmg_write_nstring(txt, p - txt);
  439. }
  440. p++;
  441. if (selected)
  442. SLsmg_set_color(SELHIGHLIGHT);
  443. else
  444. SLsmg_set_color(HIGHLIGHT);
  445. SLsmg_write_char(p[0]);
  446. p++;
  447. if (selected)
  448. SLsmg_set_color(SELBUTTONOBJ);
  449. else
  450. SLsmg_set_color(BUTTONOBJ);
  451. SLsmg_write_string(p);
  452. }
  453. else
  454. SLsmg_write_string(txt);
  455. SLsmg_write_char('>');
  456. }
  457. void ui_title(int row, int col, int width, char *title)
  458. {
  459. int pos = col + (width - strlen(title))/2;
  460. SLsmg_gotorc(row, pos - 1);
  461. SLsmg_set_char_set(1);
  462. SLsmg_write_char(SLSMG_RTEE_CHAR);
  463. SLsmg_set_char_set(0);
  464. SLsmg_write_char(' ');
  465. SLsmg_write_string(title);
  466. SLsmg_write_char(' ');
  467. SLsmg_set_char_set(1);
  468. SLsmg_write_char(SLSMG_LTEE_CHAR);
  469. SLsmg_set_char_set(0);
  470. }
  471. static void ui_dialog_drawlines(int row, int col, int height, int width,
  472. char **buf, int topline, int leftcol,
  473. int numlines, int scroll)
  474. {
  475. /* helper function for ui_dialog */
  476. int ri;
  477. int hoffset = ((scroll & SCROLLBAR_HORIZ) ? 6 : 4);
  478. int woffset = ((scroll & SCROLLBAR_VERT) ? 5 : 3);
  479. VERIFY(buf != NULL);
  480. SLsmg_set_color(DIALOGOBJ);
  481. SLsmg_fill_region(row+1, col+1, height-2, width-2, ' ');
  482. for (ri = topline; ri < numlines && ri - topline < height - hoffset; ri++) {
  483. SLsmg_gotorc(row + 1 + ri-topline, col + 1);
  484. if (strlen(buf[ri]) > leftcol)
  485. SLsmg_write_nstring(buf[ri]+leftcol, width - woffset);
  486. }
  487. if (scroll & SCROLLBAR_VERT && numlines > height-hoffset)
  488. ui_vscrollbar(row+1, col+width-2, height-hoffset,
  489. ((double)topline+1)/numlines);
  490. if (scroll & SCROLLBAR_HORIZ)
  491. ui_hscrollbar(row+height-4, col+1, width-woffset,
  492. ((double)leftcol+1)/(width-woffset));
  493. ui_button(row+height-2, col+(width-4)/2, _("Ok"), 1);
  494. SLsmg_refresh();
  495. }
  496. void ui_dialog(int row, int col, int height, int width, char *title,
  497. char *msg, int reflow, int scroll)
  498. {
  499. char *reflowbuf;
  500. int ri, c, topline = 0, leftcol = 0, numlines = 0, done = 0, redraw;
  501. char *line, *txt = NULL, **buf = NULL;
  502. if (reflow)
  503. reflowbuf = reflowtext(width - 6, msg);
  504. else
  505. reflowbuf = msg;
  506. SLsmg_set_color(DIALOGOBJ);
  507. ui_drawbox(DIALOGOBJ, row, col, height, width, 1);
  508. if (title)
  509. ui_title(row, col, width, title);
  510. if (reflowbuf != NULL) {
  511. txt = reflowbuf;
  512. while ((line = strchr(txt, '\n'))) {
  513. numlines++;
  514. txt = line+1;
  515. }
  516. numlines++;
  517. buf = MALLOC(numlines * sizeof(char *));
  518. ri = 0;
  519. txt = reflowbuf;
  520. while ((line = strsep(&txt, "\n"))) {
  521. buf[ri++] = line;
  522. }
  523. }
  524. ui_dialog_drawlines(row, col, height, width, buf, topline, leftcol, numlines, scroll);
  525. /* local event loop */
  526. while (!done) {
  527. redraw = 0;
  528. c = SLkp_getkey();
  529. switch (c) {
  530. case '\r': case '\n':
  531. case SL_KEY_ENTER:
  532. done = 1;
  533. break;
  534. case SL_KEY_UP:
  535. if (topline > 0) {
  536. topline--;
  537. redraw = 1;
  538. }
  539. break;
  540. case SL_KEY_DOWN:
  541. if (topline < numlines - 1) {
  542. topline++;
  543. redraw = 1;
  544. }
  545. break;
  546. case SL_KEY_PPAGE:
  547. topline -= (height-5);
  548. if (topline < 0) topline = 0;
  549. redraw = 1;
  550. break;
  551. case SL_KEY_NPAGE:
  552. topline += (height-5);
  553. if (topline > numlines - 1) topline = numlines - 1;
  554. redraw = 1;
  555. break;
  556. }
  557. if (redraw) {
  558. ui_dialog_drawlines(row, col, height, width, buf, topline, leftcol,
  559. numlines, scroll);
  560. }
  561. }
  562. if (buf) FREE(buf);
  563. if (reflow) FREE(reflowbuf);
  564. }
  565. void ui_drawsection(int row, int index)
  566. {
  567. char buf[1024];
  568. int spot;
  569. ASSERT(_tasks != NULL);
  570. if (index >= _tasks->count)
  571. DIE("Index out of bounds: %d >= %d", index, _tasks->count);
  572. SLsmg_set_color(CHOOSEROBJ);
  573. SLsmg_gotorc(row, _chooserinfo.coloffset + 1);
  574. SLsmg_draw_hline( 2 );
  575. SLsmg_gotorc(row, _chooserinfo.coloffset + 1 + 2);
  576. snprintf(buf, 1024, " %s ", getsectiondesc(TASK_SECTION(_tasksary[index])));
  577. SLsmg_write_nstring(buf, _chooserinfo.width - 1 - 2);
  578. spot = 1 + 2 + strlen(buf);
  579. if (spot > _chooserinfo.width / 2 - 3) spot = _chooserinfo.width / 2 - 3;
  580. SLsmg_gotorc(row, _chooserinfo.coloffset + spot);
  581. SLsmg_draw_hline( _chooserinfo.width / 2 - spot );
  582. }
  583. void ui_drawtask(int row, int index)
  584. {
  585. char buf[1024];
  586. ASSERT(_tasks != NULL);
  587. if (index >= _tasks->count)
  588. DIE(_("Index out of bounds: %d >= %d"), index, _tasks->count);
  589. SLsmg_set_color(CHOOSEROBJ);
  590. SLsmg_gotorc(row, _chooserinfo.coloffset + 1);
  591. snprintf(buf, 1024, "[%c] %s", (_tasksary[index]->selected == 0 ? ' ' : '*'),
  592. TASK_SHORTDESC(_tasksary[index]));
  593. SLsmg_write_nstring(buf, _chooserinfo.width - 1);
  594. }
  595. void ui_toggletask(int row, int index)
  596. {
  597. ASSERT(_tasks != NULL);
  598. if (index >= _tasks->count)
  599. DIE(_("Index out of bounds: %d >= %d"), index, _tasks->count);
  600. if (_tasksary[index]->selected == 0)
  601. _tasksary[index]->selected = 1;
  602. else
  603. _tasksary[index]->selected = 0;
  604. if (row >= _chooserinfo.rowoffset + _chooserinfo.height) {
  605. return;
  606. }
  607. SLsmg_set_color(CHOOSEROBJ);
  608. SLsmg_gotorc(row, _chooserinfo.coloffset + 1);
  609. if (_tasksary[index]->selected == 0)
  610. SLsmg_write_string("[ ]");
  611. else
  612. SLsmg_write_string("[*]");
  613. SLsmg_gotorc(row, _chooserinfo.coloffset + 3);
  614. SLsmg_refresh();
  615. }
  616. void ui_redrawchooser(void)
  617. {
  618. int i;
  619. for (i = _chooserinfo.topindex; i < _chooserinfo.topindex + _chooserinfo.height; i++)
  620. ui_drawchooseritem(i);
  621. }
  622. void ui_redrawcursor(int index)
  623. {
  624. /* Check to see if we have to scroll the selection */
  625. if (index + 1 - _chooserinfo.height > _chooserinfo.topindex) {
  626. _chooserinfo.topindex = index + 1 - _chooserinfo.height;
  627. ui_redrawchooser();
  628. } else if (index < _chooserinfo.topindex) {
  629. _chooserinfo.topindex = index;
  630. ui_redrawchooser();
  631. }
  632. ui_vscrollbar(_chooserinfo.rowoffset, _chooserinfo.coloffset +
  633. _chooserinfo.width - 1, _chooserinfo.height,
  634. ((double)index+1)/_displaylines);
  635. if (_displayhint[index] >= 0) {
  636. SLsmg_gotorc(_chooserinfo.rowoffset + index - _chooserinfo.topindex, _chooserinfo.coloffset + 2);
  637. SLsmg_set_color(CURSOROBJ);
  638. if (_tasksary[_displayhint[index]]->selected) {
  639. SLsmg_write_string("*");
  640. SLsmg_gotorc(_chooserinfo.rowoffset + index - _chooserinfo.topindex, _chooserinfo.coloffset + 2);
  641. } else {
  642. SLsmg_write_string("#");
  643. SLsmg_gotorc(_chooserinfo.rowoffset + index - _chooserinfo.topindex, _chooserinfo.coloffset + 2);
  644. SLsmg_write_string(" ");
  645. SLsmg_gotorc(_chooserinfo.rowoffset + index - _chooserinfo.topindex, _chooserinfo.coloffset + 2);
  646. }
  647. } else {
  648. SLsmg_gotorc(_chooserinfo.rowoffset + index - _chooserinfo.topindex, _chooserinfo.coloffset + 4);
  649. }
  650. SLsmg_refresh();
  651. }
  652. void ui_clearcursor(int index)
  653. {
  654. if (_displayhint[index] >= 0) {
  655. SLsmg_set_color(DIALOGOBJ);
  656. SLsmg_gotorc(_chooserinfo.rowoffset + index - _chooserinfo.topindex, _chooserinfo.coloffset + 2);
  657. SLsmg_write_string(_tasksary[_displayhint[index]]->selected == 0 ? " " : "*");
  658. }
  659. }
  660. void ui_showhelp(void)
  661. {
  662. _chooserinfo.whichwindow = HELPWINDOW;
  663. ui_dialog(3, 3, ROWS - 7, COLUMNS - 10, _("Help"),
  664. _("Tasks allow you to quickly install " \
  665. "a selection of packages that performs a given task.\n\nThe main " \
  666. "chooser list shows a list of tasks that you can choose to " \
  667. "install. The arrow keys moves the cursor. Pressing ENTER or the " \
  668. "SPACEBAR toggles the selection of the task at the cursor. You can " \
  669. "also press A to select all tasks, or N to deselect all tasks. " \
  670. "Pressing Q will exit this program and begin installation of your " \
  671. "selected tasks.\n\n" \
  672. "Thank you for using Debian.\n\n" \
  673. "Press enter to return to the task selection screen"
  674. /* TRANS: don't wrap lines because of different screen sizes! */),
  675. 1, SCROLLBAR_VERT);
  676. _chooserinfo.whichwindow = CHOOSERWINDOW;
  677. ui_drawscreen();
  678. }
  679. void ui_showpackageinfo(void)
  680. {
  681. struct package_t *deppkg;
  682. struct task_t *tsk;
  683. int i;
  684. int width = COLUMNS - 10;
  685. char buf[4096];
  686. char shortbuf[256];
  687. char *desc = NULL;
  688. int bufleft;
  689. int index = _displayhint[_chooserinfo.index];
  690. if (index < 0) return;
  691. ASSERT(_tasks != NULL);
  692. _chooserinfo.whichwindow = DESCWINDOW;
  693. if (index >= _tasks->count)
  694. DIE(_("Index out of bounds: %d >= %d"), index, _tasks->count);
  695. tsk = _tasksary[index];
  696. ASSERT(tsk != NULL);
  697. desc = reflowtext(width, TASK_LONGDESC(tsk));
  698. /* pack buf with package info */
  699. snprintf(buf, sizeof(buf), _("Description:\n%s\n\nIncluded packages:\n"), desc);
  700. FREE(desc);
  701. bufleft = sizeof(buf) - strlen(buf) - 1;
  702. ASSERT(width < sizeof(shortbuf));
  703. for (i = 0; i < tsk->packagescount; i++) {
  704. deppkg = packages_find(_packages, tsk->packages[i]);
  705. snprintf(shortbuf, sizeof(shortbuf), "%s - %s\n", tsk->packages[i],
  706. ((deppkg && deppkg->shortdesc) ? deppkg->shortdesc : _("(no description available)")));
  707. strncat(buf, shortbuf, bufleft);
  708. bufleft = sizeof(buf) - strlen(buf) - 1;
  709. }
  710. ui_dialog(2, 2, ROWS-4, COLUMNS-4, tsk->name, buf, 0, SCROLLBAR_VERT);
  711. _chooserinfo.whichwindow = CHOOSERWINDOW;
  712. ui_drawscreen();
  713. }
  714. void ui_drawchooseritem(int index)
  715. {
  716. int realrow = _chooserinfo.rowoffset + index - _chooserinfo.topindex;
  717. int task;
  718. if (index >= _displaylines) return;
  719. task = _displayhint[index];
  720. if (task == -1) {
  721. task = _displayhint[index+1];
  722. ui_drawsection(realrow, task);
  723. } else {
  724. ui_drawtask(realrow, task);
  725. }
  726. }
  727. void ui_toggleselection(int index)
  728. {
  729. int task = _displayhint[index];
  730. if (task >= 0) {
  731. ui_toggletask(_chooserinfo.rowoffset + index - _chooserinfo.topindex, task);
  732. } else {
  733. int first = index+1, last, setto = 0;
  734. for(;;) {
  735. index++;
  736. if (index >= _displaylines) break;
  737. task = _displayhint[index];
  738. if (task == -1) break;
  739. setto = setto || _tasksary[task]->selected == 0;
  740. }
  741. last = index;
  742. for (index = first; index < last; index++) {
  743. task = _displayhint[index];
  744. if ((!_tasksary[task]->selected) ^ (!setto)) {
  745. ui_toggletask(_chooserinfo.rowoffset + index - _chooserinfo.topindex, task);
  746. }
  747. }
  748. }
  749. }