browser.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794
  1. // SPDX-License-Identifier: GPL-2.0
  2. #include "../util.h"
  3. #include "../string2.h"
  4. #include "../config.h"
  5. #include "../../perf.h"
  6. #include "libslang.h"
  7. #include "ui.h"
  8. #include "util.h"
  9. #include <linux/compiler.h>
  10. #include <linux/list.h>
  11. #include <linux/rbtree.h>
  12. #include <linux/string.h>
  13. #include <stdlib.h>
  14. #include <sys/ttydefaults.h>
  15. #include "browser.h"
  16. #include "helpline.h"
  17. #include "keysyms.h"
  18. #include "../color.h"
  19. #include "sane_ctype.h"
  20. static int ui_browser__percent_color(struct ui_browser *browser,
  21. double percent, bool current)
  22. {
  23. if (current && (!browser->use_navkeypressed || browser->navkeypressed))
  24. return HE_COLORSET_SELECTED;
  25. if (percent >= MIN_RED)
  26. return HE_COLORSET_TOP;
  27. if (percent >= MIN_GREEN)
  28. return HE_COLORSET_MEDIUM;
  29. return HE_COLORSET_NORMAL;
  30. }
  31. int ui_browser__set_color(struct ui_browser *browser, int color)
  32. {
  33. int ret = browser->current_color;
  34. browser->current_color = color;
  35. SLsmg_set_color(color);
  36. return ret;
  37. }
  38. void ui_browser__set_percent_color(struct ui_browser *browser,
  39. double percent, bool current)
  40. {
  41. int color = ui_browser__percent_color(browser, percent, current);
  42. ui_browser__set_color(browser, color);
  43. }
  44. void ui_browser__gotorc_title(struct ui_browser *browser, int y, int x)
  45. {
  46. SLsmg_gotorc(browser->y + y, browser->x + x);
  47. }
  48. void ui_browser__gotorc(struct ui_browser *browser, int y, int x)
  49. {
  50. SLsmg_gotorc(browser->y + y + browser->extra_title_lines, browser->x + x);
  51. }
  52. void ui_browser__write_nstring(struct ui_browser *browser __maybe_unused, const char *msg,
  53. unsigned int width)
  54. {
  55. slsmg_write_nstring(msg, width);
  56. }
  57. void ui_browser__vprintf(struct ui_browser *browser __maybe_unused, const char *fmt, va_list args)
  58. {
  59. slsmg_vprintf(fmt, args);
  60. }
  61. void ui_browser__printf(struct ui_browser *browser __maybe_unused, const char *fmt, ...)
  62. {
  63. va_list args;
  64. va_start(args, fmt);
  65. ui_browser__vprintf(browser, fmt, args);
  66. va_end(args);
  67. }
  68. static struct list_head *
  69. ui_browser__list_head_filter_entries(struct ui_browser *browser,
  70. struct list_head *pos)
  71. {
  72. do {
  73. if (!browser->filter || !browser->filter(browser, pos))
  74. return pos;
  75. pos = pos->next;
  76. } while (pos != browser->entries);
  77. return NULL;
  78. }
  79. static struct list_head *
  80. ui_browser__list_head_filter_prev_entries(struct ui_browser *browser,
  81. struct list_head *pos)
  82. {
  83. do {
  84. if (!browser->filter || !browser->filter(browser, pos))
  85. return pos;
  86. pos = pos->prev;
  87. } while (pos != browser->entries);
  88. return NULL;
  89. }
  90. void ui_browser__list_head_seek(struct ui_browser *browser, off_t offset, int whence)
  91. {
  92. struct list_head *head = browser->entries;
  93. struct list_head *pos;
  94. if (browser->nr_entries == 0)
  95. return;
  96. switch (whence) {
  97. case SEEK_SET:
  98. pos = ui_browser__list_head_filter_entries(browser, head->next);
  99. break;
  100. case SEEK_CUR:
  101. pos = browser->top;
  102. break;
  103. case SEEK_END:
  104. pos = ui_browser__list_head_filter_prev_entries(browser, head->prev);
  105. break;
  106. default:
  107. return;
  108. }
  109. assert(pos != NULL);
  110. if (offset > 0) {
  111. while (offset-- != 0)
  112. pos = ui_browser__list_head_filter_entries(browser, pos->next);
  113. } else {
  114. while (offset++ != 0)
  115. pos = ui_browser__list_head_filter_prev_entries(browser, pos->prev);
  116. }
  117. browser->top = pos;
  118. }
  119. void ui_browser__rb_tree_seek(struct ui_browser *browser, off_t offset, int whence)
  120. {
  121. struct rb_root *root = browser->entries;
  122. struct rb_node *nd;
  123. switch (whence) {
  124. case SEEK_SET:
  125. nd = rb_first(root);
  126. break;
  127. case SEEK_CUR:
  128. nd = browser->top;
  129. break;
  130. case SEEK_END:
  131. nd = rb_last(root);
  132. break;
  133. default:
  134. return;
  135. }
  136. if (offset > 0) {
  137. while (offset-- != 0)
  138. nd = rb_next(nd);
  139. } else {
  140. while (offset++ != 0)
  141. nd = rb_prev(nd);
  142. }
  143. browser->top = nd;
  144. }
  145. unsigned int ui_browser__rb_tree_refresh(struct ui_browser *browser)
  146. {
  147. struct rb_node *nd;
  148. int row = 0;
  149. if (browser->top == NULL)
  150. browser->top = rb_first(browser->entries);
  151. nd = browser->top;
  152. while (nd != NULL) {
  153. ui_browser__gotorc(browser, row, 0);
  154. browser->write(browser, nd, row);
  155. if (++row == browser->rows)
  156. break;
  157. nd = rb_next(nd);
  158. }
  159. return row;
  160. }
  161. bool ui_browser__is_current_entry(struct ui_browser *browser, unsigned row)
  162. {
  163. return browser->top_idx + row == browser->index;
  164. }
  165. void ui_browser__refresh_dimensions(struct ui_browser *browser)
  166. {
  167. browser->width = SLtt_Screen_Cols - 1;
  168. browser->height = browser->rows = SLtt_Screen_Rows - 2;
  169. browser->rows -= browser->extra_title_lines;
  170. browser->y = 1;
  171. browser->x = 0;
  172. }
  173. void ui_browser__handle_resize(struct ui_browser *browser)
  174. {
  175. ui__refresh_dimensions(false);
  176. ui_browser__show(browser, browser->title, ui_helpline__current);
  177. ui_browser__refresh(browser);
  178. }
  179. int ui_browser__warning(struct ui_browser *browser, int timeout,
  180. const char *format, ...)
  181. {
  182. va_list args;
  183. char *text;
  184. int key = 0, err;
  185. va_start(args, format);
  186. err = vasprintf(&text, format, args);
  187. va_end(args);
  188. if (err < 0) {
  189. va_start(args, format);
  190. ui_helpline__vpush(format, args);
  191. va_end(args);
  192. } else {
  193. while ((key = ui__question_window("Warning!", text,
  194. "Press any key...",
  195. timeout)) == K_RESIZE)
  196. ui_browser__handle_resize(browser);
  197. free(text);
  198. }
  199. return key;
  200. }
  201. int ui_browser__help_window(struct ui_browser *browser, const char *text)
  202. {
  203. int key;
  204. while ((key = ui__help_window(text)) == K_RESIZE)
  205. ui_browser__handle_resize(browser);
  206. return key;
  207. }
  208. bool ui_browser__dialog_yesno(struct ui_browser *browser, const char *text)
  209. {
  210. int key;
  211. while ((key = ui__dialog_yesno(text)) == K_RESIZE)
  212. ui_browser__handle_resize(browser);
  213. return key == K_ENTER || toupper(key) == 'Y';
  214. }
  215. void ui_browser__reset_index(struct ui_browser *browser)
  216. {
  217. browser->index = browser->top_idx = 0;
  218. browser->seek(browser, 0, SEEK_SET);
  219. }
  220. void __ui_browser__show_title(struct ui_browser *browser, const char *title)
  221. {
  222. SLsmg_gotorc(0, 0);
  223. ui_browser__set_color(browser, HE_COLORSET_ROOT);
  224. ui_browser__write_nstring(browser, title, browser->width + 1);
  225. }
  226. void ui_browser__show_title(struct ui_browser *browser, const char *title)
  227. {
  228. pthread_mutex_lock(&ui__lock);
  229. __ui_browser__show_title(browser, title);
  230. pthread_mutex_unlock(&ui__lock);
  231. }
  232. int ui_browser__show(struct ui_browser *browser, const char *title,
  233. const char *helpline, ...)
  234. {
  235. int err;
  236. va_list ap;
  237. if (browser->refresh_dimensions == NULL)
  238. browser->refresh_dimensions = ui_browser__refresh_dimensions;
  239. browser->refresh_dimensions(browser);
  240. pthread_mutex_lock(&ui__lock);
  241. __ui_browser__show_title(browser, title);
  242. browser->title = title;
  243. zfree(&browser->helpline);
  244. va_start(ap, helpline);
  245. err = vasprintf(&browser->helpline, helpline, ap);
  246. va_end(ap);
  247. if (err > 0)
  248. ui_helpline__push(browser->helpline);
  249. pthread_mutex_unlock(&ui__lock);
  250. return err ? 0 : -1;
  251. }
  252. void ui_browser__hide(struct ui_browser *browser)
  253. {
  254. pthread_mutex_lock(&ui__lock);
  255. ui_helpline__pop();
  256. zfree(&browser->helpline);
  257. pthread_mutex_unlock(&ui__lock);
  258. }
  259. static void ui_browser__scrollbar_set(struct ui_browser *browser)
  260. {
  261. int height = browser->height, h = 0, pct = 0,
  262. col = browser->width,
  263. row = 0;
  264. if (browser->nr_entries > 1) {
  265. pct = ((browser->index * (browser->height - 1)) /
  266. (browser->nr_entries - 1));
  267. }
  268. SLsmg_set_char_set(1);
  269. while (h < height) {
  270. ui_browser__gotorc(browser, row++, col);
  271. SLsmg_write_char(h == pct ? SLSMG_DIAMOND_CHAR : SLSMG_CKBRD_CHAR);
  272. ++h;
  273. }
  274. SLsmg_set_char_set(0);
  275. }
  276. static int __ui_browser__refresh(struct ui_browser *browser)
  277. {
  278. int row;
  279. int width = browser->width;
  280. row = browser->refresh(browser);
  281. ui_browser__set_color(browser, HE_COLORSET_NORMAL);
  282. if (!browser->use_navkeypressed || browser->navkeypressed)
  283. ui_browser__scrollbar_set(browser);
  284. else
  285. width += 1;
  286. SLsmg_fill_region(browser->y + row + browser->extra_title_lines, browser->x,
  287. browser->rows - row, width, ' ');
  288. return 0;
  289. }
  290. int ui_browser__refresh(struct ui_browser *browser)
  291. {
  292. pthread_mutex_lock(&ui__lock);
  293. __ui_browser__refresh(browser);
  294. pthread_mutex_unlock(&ui__lock);
  295. return 0;
  296. }
  297. /*
  298. * Here we're updating nr_entries _after_ we started browsing, i.e. we have to
  299. * forget about any reference to any entry in the underlying data structure,
  300. * that is why we do a SEEK_SET. Think about 'perf top' in the hists browser
  301. * after an output_resort and hist decay.
  302. */
  303. void ui_browser__update_nr_entries(struct ui_browser *browser, u32 nr_entries)
  304. {
  305. off_t offset = nr_entries - browser->nr_entries;
  306. browser->nr_entries = nr_entries;
  307. if (offset < 0) {
  308. if (browser->top_idx < (u64)-offset)
  309. offset = -browser->top_idx;
  310. browser->index += offset;
  311. browser->top_idx += offset;
  312. }
  313. browser->top = NULL;
  314. browser->seek(browser, browser->top_idx, SEEK_SET);
  315. }
  316. int ui_browser__run(struct ui_browser *browser, int delay_secs)
  317. {
  318. int err, key;
  319. while (1) {
  320. off_t offset;
  321. pthread_mutex_lock(&ui__lock);
  322. err = __ui_browser__refresh(browser);
  323. SLsmg_refresh();
  324. pthread_mutex_unlock(&ui__lock);
  325. if (err < 0)
  326. break;
  327. key = ui__getch(delay_secs);
  328. if (key == K_RESIZE) {
  329. ui__refresh_dimensions(false);
  330. browser->refresh_dimensions(browser);
  331. __ui_browser__show_title(browser, browser->title);
  332. ui_helpline__puts(browser->helpline);
  333. continue;
  334. }
  335. if (browser->use_navkeypressed && !browser->navkeypressed) {
  336. if (key == K_DOWN || key == K_UP ||
  337. (browser->columns && (key == K_LEFT || key == K_RIGHT)) ||
  338. key == K_PGDN || key == K_PGUP ||
  339. key == K_HOME || key == K_END ||
  340. key == ' ') {
  341. browser->navkeypressed = true;
  342. continue;
  343. } else
  344. return key;
  345. }
  346. switch (key) {
  347. case K_DOWN:
  348. if (browser->index == browser->nr_entries - 1)
  349. break;
  350. ++browser->index;
  351. if (browser->index == browser->top_idx + browser->rows) {
  352. ++browser->top_idx;
  353. browser->seek(browser, +1, SEEK_CUR);
  354. }
  355. break;
  356. case K_UP:
  357. if (browser->index == 0)
  358. break;
  359. --browser->index;
  360. if (browser->index < browser->top_idx) {
  361. --browser->top_idx;
  362. browser->seek(browser, -1, SEEK_CUR);
  363. }
  364. break;
  365. case K_RIGHT:
  366. if (!browser->columns)
  367. goto out;
  368. if (browser->horiz_scroll < browser->columns - 1)
  369. ++browser->horiz_scroll;
  370. break;
  371. case K_LEFT:
  372. if (!browser->columns)
  373. goto out;
  374. if (browser->horiz_scroll != 0)
  375. --browser->horiz_scroll;
  376. break;
  377. case K_PGDN:
  378. case ' ':
  379. if (browser->top_idx + browser->rows > browser->nr_entries - 1)
  380. break;
  381. offset = browser->rows;
  382. if (browser->index + offset > browser->nr_entries - 1)
  383. offset = browser->nr_entries - 1 - browser->index;
  384. browser->index += offset;
  385. browser->top_idx += offset;
  386. browser->seek(browser, +offset, SEEK_CUR);
  387. break;
  388. case K_PGUP:
  389. if (browser->top_idx == 0)
  390. break;
  391. if (browser->top_idx < browser->rows)
  392. offset = browser->top_idx;
  393. else
  394. offset = browser->rows;
  395. browser->index -= offset;
  396. browser->top_idx -= offset;
  397. browser->seek(browser, -offset, SEEK_CUR);
  398. break;
  399. case K_HOME:
  400. ui_browser__reset_index(browser);
  401. break;
  402. case K_END:
  403. offset = browser->rows - 1;
  404. if (offset >= browser->nr_entries)
  405. offset = browser->nr_entries - 1;
  406. browser->index = browser->nr_entries - 1;
  407. browser->top_idx = browser->index - offset;
  408. browser->seek(browser, -offset, SEEK_END);
  409. break;
  410. default:
  411. out:
  412. return key;
  413. }
  414. }
  415. return -1;
  416. }
  417. unsigned int ui_browser__list_head_refresh(struct ui_browser *browser)
  418. {
  419. struct list_head *pos;
  420. struct list_head *head = browser->entries;
  421. int row = 0;
  422. if (browser->top == NULL || browser->top == browser->entries)
  423. browser->top = ui_browser__list_head_filter_entries(browser, head->next);
  424. pos = browser->top;
  425. list_for_each_from(pos, head) {
  426. if (!browser->filter || !browser->filter(browser, pos)) {
  427. ui_browser__gotorc(browser, row, 0);
  428. browser->write(browser, pos, row);
  429. if (++row == browser->rows)
  430. break;
  431. }
  432. }
  433. return row;
  434. }
  435. static struct ui_browser_colorset {
  436. const char *name, *fg, *bg;
  437. int colorset;
  438. } ui_browser__colorsets[] = {
  439. {
  440. .colorset = HE_COLORSET_TOP,
  441. .name = "top",
  442. .fg = "red",
  443. .bg = "default",
  444. },
  445. {
  446. .colorset = HE_COLORSET_MEDIUM,
  447. .name = "medium",
  448. .fg = "green",
  449. .bg = "default",
  450. },
  451. {
  452. .colorset = HE_COLORSET_NORMAL,
  453. .name = "normal",
  454. .fg = "default",
  455. .bg = "default",
  456. },
  457. {
  458. .colorset = HE_COLORSET_SELECTED,
  459. .name = "selected",
  460. .fg = "black",
  461. .bg = "yellow",
  462. },
  463. {
  464. .colorset = HE_COLORSET_JUMP_ARROWS,
  465. .name = "jump_arrows",
  466. .fg = "blue",
  467. .bg = "default",
  468. },
  469. {
  470. .colorset = HE_COLORSET_ADDR,
  471. .name = "addr",
  472. .fg = "magenta",
  473. .bg = "default",
  474. },
  475. {
  476. .colorset = HE_COLORSET_ROOT,
  477. .name = "root",
  478. .fg = "white",
  479. .bg = "blue",
  480. },
  481. {
  482. .name = NULL,
  483. }
  484. };
  485. static int ui_browser__color_config(const char *var, const char *value,
  486. void *data __maybe_unused)
  487. {
  488. char *fg = NULL, *bg;
  489. int i;
  490. /* same dir for all commands */
  491. if (!strstarts(var, "colors.") != 0)
  492. return 0;
  493. for (i = 0; ui_browser__colorsets[i].name != NULL; ++i) {
  494. const char *name = var + 7;
  495. if (strcmp(ui_browser__colorsets[i].name, name) != 0)
  496. continue;
  497. fg = strdup(value);
  498. if (fg == NULL)
  499. break;
  500. bg = strchr(fg, ',');
  501. if (bg == NULL)
  502. break;
  503. *bg = '\0';
  504. bg = ltrim(++bg);
  505. ui_browser__colorsets[i].bg = bg;
  506. ui_browser__colorsets[i].fg = fg;
  507. return 0;
  508. }
  509. free(fg);
  510. return -1;
  511. }
  512. void ui_browser__argv_seek(struct ui_browser *browser, off_t offset, int whence)
  513. {
  514. switch (whence) {
  515. case SEEK_SET:
  516. browser->top = browser->entries;
  517. break;
  518. case SEEK_CUR:
  519. browser->top = browser->top + browser->top_idx + offset;
  520. break;
  521. case SEEK_END:
  522. browser->top = browser->top + browser->nr_entries - 1 + offset;
  523. break;
  524. default:
  525. return;
  526. }
  527. }
  528. unsigned int ui_browser__argv_refresh(struct ui_browser *browser)
  529. {
  530. unsigned int row = 0, idx = browser->top_idx;
  531. char **pos;
  532. if (browser->top == NULL)
  533. browser->top = browser->entries;
  534. pos = (char **)browser->top;
  535. while (idx < browser->nr_entries) {
  536. if (!browser->filter || !browser->filter(browser, *pos)) {
  537. ui_browser__gotorc(browser, row, 0);
  538. browser->write(browser, pos, row);
  539. if (++row == browser->rows)
  540. break;
  541. }
  542. ++idx;
  543. ++pos;
  544. }
  545. return row;
  546. }
  547. void __ui_browser__vline(struct ui_browser *browser, unsigned int column,
  548. u16 start, u16 end)
  549. {
  550. SLsmg_set_char_set(1);
  551. ui_browser__gotorc(browser, start, column);
  552. SLsmg_draw_vline(end - start + 1);
  553. SLsmg_set_char_set(0);
  554. }
  555. void ui_browser__write_graph(struct ui_browser *browser __maybe_unused,
  556. int graph)
  557. {
  558. SLsmg_set_char_set(1);
  559. SLsmg_write_char(graph);
  560. SLsmg_set_char_set(0);
  561. }
  562. static void __ui_browser__line_arrow_up(struct ui_browser *browser,
  563. unsigned int column,
  564. u64 start, u64 end)
  565. {
  566. unsigned int row, end_row;
  567. SLsmg_set_char_set(1);
  568. if (start < browser->top_idx + browser->rows) {
  569. row = start - browser->top_idx;
  570. ui_browser__gotorc(browser, row, column);
  571. SLsmg_write_char(SLSMG_LLCORN_CHAR);
  572. ui_browser__gotorc(browser, row, column + 1);
  573. SLsmg_draw_hline(2);
  574. if (row-- == 0)
  575. goto out;
  576. } else
  577. row = browser->rows - 1;
  578. if (end > browser->top_idx)
  579. end_row = end - browser->top_idx;
  580. else
  581. end_row = 0;
  582. ui_browser__gotorc(browser, end_row, column);
  583. SLsmg_draw_vline(row - end_row + 1);
  584. ui_browser__gotorc(browser, end_row, column);
  585. if (end >= browser->top_idx) {
  586. SLsmg_write_char(SLSMG_ULCORN_CHAR);
  587. ui_browser__gotorc(browser, end_row, column + 1);
  588. SLsmg_write_char(SLSMG_HLINE_CHAR);
  589. ui_browser__gotorc(browser, end_row, column + 2);
  590. SLsmg_write_char(SLSMG_RARROW_CHAR);
  591. }
  592. out:
  593. SLsmg_set_char_set(0);
  594. }
  595. static void __ui_browser__line_arrow_down(struct ui_browser *browser,
  596. unsigned int column,
  597. u64 start, u64 end)
  598. {
  599. unsigned int row, end_row;
  600. SLsmg_set_char_set(1);
  601. if (start >= browser->top_idx) {
  602. row = start - browser->top_idx;
  603. ui_browser__gotorc(browser, row, column);
  604. SLsmg_write_char(SLSMG_ULCORN_CHAR);
  605. ui_browser__gotorc(browser, row, column + 1);
  606. SLsmg_draw_hline(2);
  607. if (++row == 0)
  608. goto out;
  609. } else
  610. row = 0;
  611. if (end >= browser->top_idx + browser->rows)
  612. end_row = browser->rows - 1;
  613. else
  614. end_row = end - browser->top_idx;
  615. ui_browser__gotorc(browser, row, column);
  616. SLsmg_draw_vline(end_row - row + 1);
  617. ui_browser__gotorc(browser, end_row, column);
  618. if (end < browser->top_idx + browser->rows) {
  619. SLsmg_write_char(SLSMG_LLCORN_CHAR);
  620. ui_browser__gotorc(browser, end_row, column + 1);
  621. SLsmg_write_char(SLSMG_HLINE_CHAR);
  622. ui_browser__gotorc(browser, end_row, column + 2);
  623. SLsmg_write_char(SLSMG_RARROW_CHAR);
  624. }
  625. out:
  626. SLsmg_set_char_set(0);
  627. }
  628. void __ui_browser__line_arrow(struct ui_browser *browser, unsigned int column,
  629. u64 start, u64 end)
  630. {
  631. if (start > end)
  632. __ui_browser__line_arrow_up(browser, column, start, end);
  633. else
  634. __ui_browser__line_arrow_down(browser, column, start, end);
  635. }
  636. void ui_browser__mark_fused(struct ui_browser *browser, unsigned int column,
  637. unsigned int row, bool arrow_down)
  638. {
  639. unsigned int end_row;
  640. if (row >= browser->top_idx)
  641. end_row = row - browser->top_idx;
  642. else
  643. return;
  644. SLsmg_set_char_set(1);
  645. if (arrow_down) {
  646. ui_browser__gotorc(browser, end_row, column - 1);
  647. SLsmg_write_char(SLSMG_ULCORN_CHAR);
  648. ui_browser__gotorc(browser, end_row, column);
  649. SLsmg_draw_hline(2);
  650. ui_browser__gotorc(browser, end_row + 1, column - 1);
  651. SLsmg_write_char(SLSMG_LTEE_CHAR);
  652. } else {
  653. ui_browser__gotorc(browser, end_row, column - 1);
  654. SLsmg_write_char(SLSMG_LTEE_CHAR);
  655. ui_browser__gotorc(browser, end_row, column);
  656. SLsmg_draw_hline(2);
  657. }
  658. SLsmg_set_char_set(0);
  659. }
  660. void ui_browser__init(void)
  661. {
  662. int i = 0;
  663. perf_config(ui_browser__color_config, NULL);
  664. while (ui_browser__colorsets[i].name) {
  665. struct ui_browser_colorset *c = &ui_browser__colorsets[i++];
  666. sltt_set_color(c->colorset, c->name, c->fg, c->bg);
  667. }
  668. }