162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci#include "../util/string2.h"
362306a36Sopenharmony_ci#include "../util/config.h"
462306a36Sopenharmony_ci#include "libslang.h"
562306a36Sopenharmony_ci#include "ui.h"
662306a36Sopenharmony_ci#include "util.h"
762306a36Sopenharmony_ci#include <linux/compiler.h>
862306a36Sopenharmony_ci#include <linux/list.h>
962306a36Sopenharmony_ci#include <linux/rbtree.h>
1062306a36Sopenharmony_ci#include <linux/string.h>
1162306a36Sopenharmony_ci#include <stdlib.h>
1262306a36Sopenharmony_ci#include <sys/ttydefaults.h>
1362306a36Sopenharmony_ci#include "browser.h"
1462306a36Sopenharmony_ci#include "helpline.h"
1562306a36Sopenharmony_ci#include "keysyms.h"
1662306a36Sopenharmony_ci#include "../util/color.h"
1762306a36Sopenharmony_ci#include <linux/ctype.h>
1862306a36Sopenharmony_ci#include <linux/zalloc.h>
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_cistatic int ui_browser__percent_color(struct ui_browser *browser,
2162306a36Sopenharmony_ci				     double percent, bool current)
2262306a36Sopenharmony_ci{
2362306a36Sopenharmony_ci	if (current && (!browser->use_navkeypressed || browser->navkeypressed))
2462306a36Sopenharmony_ci		return HE_COLORSET_SELECTED;
2562306a36Sopenharmony_ci	if (percent >= MIN_RED)
2662306a36Sopenharmony_ci		return HE_COLORSET_TOP;
2762306a36Sopenharmony_ci	if (percent >= MIN_GREEN)
2862306a36Sopenharmony_ci		return HE_COLORSET_MEDIUM;
2962306a36Sopenharmony_ci	return HE_COLORSET_NORMAL;
3062306a36Sopenharmony_ci}
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ciint ui_browser__set_color(struct ui_browser *browser, int color)
3362306a36Sopenharmony_ci{
3462306a36Sopenharmony_ci	int ret = browser->current_color;
3562306a36Sopenharmony_ci	browser->current_color = color;
3662306a36Sopenharmony_ci	SLsmg_set_color(color);
3762306a36Sopenharmony_ci	return ret;
3862306a36Sopenharmony_ci}
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_civoid ui_browser__set_percent_color(struct ui_browser *browser,
4162306a36Sopenharmony_ci				   double percent, bool current)
4262306a36Sopenharmony_ci{
4362306a36Sopenharmony_ci	 int color = ui_browser__percent_color(browser, percent, current);
4462306a36Sopenharmony_ci	 ui_browser__set_color(browser, color);
4562306a36Sopenharmony_ci}
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_civoid ui_browser__gotorc_title(struct ui_browser *browser, int y, int x)
4862306a36Sopenharmony_ci{
4962306a36Sopenharmony_ci	SLsmg_gotorc(browser->y + y, browser->x + x);
5062306a36Sopenharmony_ci}
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_civoid ui_browser__gotorc(struct ui_browser *browser, int y, int x)
5362306a36Sopenharmony_ci{
5462306a36Sopenharmony_ci	SLsmg_gotorc(browser->y + y + browser->extra_title_lines, browser->x + x);
5562306a36Sopenharmony_ci}
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_civoid ui_browser__write_nstring(struct ui_browser *browser __maybe_unused, const char *msg,
5862306a36Sopenharmony_ci			       unsigned int width)
5962306a36Sopenharmony_ci{
6062306a36Sopenharmony_ci	SLsmg_write_nstring(msg, width);
6162306a36Sopenharmony_ci}
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_civoid ui_browser__vprintf(struct ui_browser *browser __maybe_unused, const char *fmt, va_list args)
6462306a36Sopenharmony_ci{
6562306a36Sopenharmony_ci	SLsmg_vprintf(fmt, args);
6662306a36Sopenharmony_ci}
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_civoid ui_browser__printf(struct ui_browser *browser __maybe_unused, const char *fmt, ...)
6962306a36Sopenharmony_ci{
7062306a36Sopenharmony_ci	va_list args;
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	va_start(args, fmt);
7362306a36Sopenharmony_ci	ui_browser__vprintf(browser, fmt, args);
7462306a36Sopenharmony_ci	va_end(args);
7562306a36Sopenharmony_ci}
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_cistatic struct list_head *
7862306a36Sopenharmony_ciui_browser__list_head_filter_entries(struct ui_browser *browser,
7962306a36Sopenharmony_ci				     struct list_head *pos)
8062306a36Sopenharmony_ci{
8162306a36Sopenharmony_ci	do {
8262306a36Sopenharmony_ci		if (!browser->filter || !browser->filter(browser, pos))
8362306a36Sopenharmony_ci			return pos;
8462306a36Sopenharmony_ci		pos = pos->next;
8562306a36Sopenharmony_ci	} while (pos != browser->entries);
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	return NULL;
8862306a36Sopenharmony_ci}
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_cistatic struct list_head *
9162306a36Sopenharmony_ciui_browser__list_head_filter_prev_entries(struct ui_browser *browser,
9262306a36Sopenharmony_ci					  struct list_head *pos)
9362306a36Sopenharmony_ci{
9462306a36Sopenharmony_ci	do {
9562306a36Sopenharmony_ci		if (!browser->filter || !browser->filter(browser, pos))
9662306a36Sopenharmony_ci			return pos;
9762306a36Sopenharmony_ci		pos = pos->prev;
9862306a36Sopenharmony_ci	} while (pos != browser->entries);
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci	return NULL;
10162306a36Sopenharmony_ci}
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_civoid ui_browser__list_head_seek(struct ui_browser *browser, off_t offset, int whence)
10462306a36Sopenharmony_ci{
10562306a36Sopenharmony_ci	struct list_head *head = browser->entries;
10662306a36Sopenharmony_ci	struct list_head *pos;
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	if (browser->nr_entries == 0)
10962306a36Sopenharmony_ci		return;
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	switch (whence) {
11262306a36Sopenharmony_ci	case SEEK_SET:
11362306a36Sopenharmony_ci		pos = ui_browser__list_head_filter_entries(browser, head->next);
11462306a36Sopenharmony_ci		break;
11562306a36Sopenharmony_ci	case SEEK_CUR:
11662306a36Sopenharmony_ci		pos = browser->top;
11762306a36Sopenharmony_ci		break;
11862306a36Sopenharmony_ci	case SEEK_END:
11962306a36Sopenharmony_ci		pos = ui_browser__list_head_filter_prev_entries(browser, head->prev);
12062306a36Sopenharmony_ci		break;
12162306a36Sopenharmony_ci	default:
12262306a36Sopenharmony_ci		return;
12362306a36Sopenharmony_ci	}
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci	assert(pos != NULL);
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	if (offset > 0) {
12862306a36Sopenharmony_ci		while (offset-- != 0)
12962306a36Sopenharmony_ci			pos = ui_browser__list_head_filter_entries(browser, pos->next);
13062306a36Sopenharmony_ci	} else {
13162306a36Sopenharmony_ci		while (offset++ != 0)
13262306a36Sopenharmony_ci			pos = ui_browser__list_head_filter_prev_entries(browser, pos->prev);
13362306a36Sopenharmony_ci	}
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci	browser->top = pos;
13662306a36Sopenharmony_ci}
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_civoid ui_browser__rb_tree_seek(struct ui_browser *browser, off_t offset, int whence)
13962306a36Sopenharmony_ci{
14062306a36Sopenharmony_ci	struct rb_root *root = browser->entries;
14162306a36Sopenharmony_ci	struct rb_node *nd;
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	switch (whence) {
14462306a36Sopenharmony_ci	case SEEK_SET:
14562306a36Sopenharmony_ci		nd = rb_first(root);
14662306a36Sopenharmony_ci		break;
14762306a36Sopenharmony_ci	case SEEK_CUR:
14862306a36Sopenharmony_ci		nd = browser->top;
14962306a36Sopenharmony_ci		break;
15062306a36Sopenharmony_ci	case SEEK_END:
15162306a36Sopenharmony_ci		nd = rb_last(root);
15262306a36Sopenharmony_ci		break;
15362306a36Sopenharmony_ci	default:
15462306a36Sopenharmony_ci		return;
15562306a36Sopenharmony_ci	}
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci	if (offset > 0) {
15862306a36Sopenharmony_ci		while (offset-- != 0)
15962306a36Sopenharmony_ci			nd = rb_next(nd);
16062306a36Sopenharmony_ci	} else {
16162306a36Sopenharmony_ci		while (offset++ != 0)
16262306a36Sopenharmony_ci			nd = rb_prev(nd);
16362306a36Sopenharmony_ci	}
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	browser->top = nd;
16662306a36Sopenharmony_ci}
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ciunsigned int ui_browser__rb_tree_refresh(struct ui_browser *browser)
16962306a36Sopenharmony_ci{
17062306a36Sopenharmony_ci	struct rb_node *nd;
17162306a36Sopenharmony_ci	int row = 0;
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	if (browser->top == NULL)
17462306a36Sopenharmony_ci                browser->top = rb_first(browser->entries);
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci	nd = browser->top;
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci	while (nd != NULL) {
17962306a36Sopenharmony_ci		ui_browser__gotorc(browser, row, 0);
18062306a36Sopenharmony_ci		browser->write(browser, nd, row);
18162306a36Sopenharmony_ci		if (++row == browser->rows)
18262306a36Sopenharmony_ci			break;
18362306a36Sopenharmony_ci		nd = rb_next(nd);
18462306a36Sopenharmony_ci	}
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci	return row;
18762306a36Sopenharmony_ci}
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_cibool ui_browser__is_current_entry(struct ui_browser *browser, unsigned row)
19062306a36Sopenharmony_ci{
19162306a36Sopenharmony_ci	return browser->top_idx + row == browser->index;
19262306a36Sopenharmony_ci}
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_civoid ui_browser__refresh_dimensions(struct ui_browser *browser)
19562306a36Sopenharmony_ci{
19662306a36Sopenharmony_ci	browser->width = SLtt_Screen_Cols - 1;
19762306a36Sopenharmony_ci	browser->height = browser->rows = SLtt_Screen_Rows - 2;
19862306a36Sopenharmony_ci	browser->rows -= browser->extra_title_lines;
19962306a36Sopenharmony_ci	browser->y = 1;
20062306a36Sopenharmony_ci	browser->x = 0;
20162306a36Sopenharmony_ci}
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_civoid ui_browser__handle_resize(struct ui_browser *browser)
20462306a36Sopenharmony_ci{
20562306a36Sopenharmony_ci	ui__refresh_dimensions(false);
20662306a36Sopenharmony_ci	ui_browser__show(browser, browser->title, ui_helpline__current);
20762306a36Sopenharmony_ci	ui_browser__refresh(browser);
20862306a36Sopenharmony_ci}
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ciint ui_browser__warning(struct ui_browser *browser, int timeout,
21162306a36Sopenharmony_ci			const char *format, ...)
21262306a36Sopenharmony_ci{
21362306a36Sopenharmony_ci	va_list args;
21462306a36Sopenharmony_ci	char *text;
21562306a36Sopenharmony_ci	int key = 0, err;
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci	va_start(args, format);
21862306a36Sopenharmony_ci	err = vasprintf(&text, format, args);
21962306a36Sopenharmony_ci	va_end(args);
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci	if (err < 0) {
22262306a36Sopenharmony_ci		va_start(args, format);
22362306a36Sopenharmony_ci		ui_helpline__vpush(format, args);
22462306a36Sopenharmony_ci		va_end(args);
22562306a36Sopenharmony_ci	} else {
22662306a36Sopenharmony_ci		while ((key = ui__question_window("Warning!", text,
22762306a36Sopenharmony_ci						   "Press any key...",
22862306a36Sopenharmony_ci						   timeout)) == K_RESIZE)
22962306a36Sopenharmony_ci			ui_browser__handle_resize(browser);
23062306a36Sopenharmony_ci		free(text);
23162306a36Sopenharmony_ci	}
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci	return key;
23462306a36Sopenharmony_ci}
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ciint ui_browser__help_window(struct ui_browser *browser, const char *text)
23762306a36Sopenharmony_ci{
23862306a36Sopenharmony_ci	int key;
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci	while ((key = ui__help_window(text)) == K_RESIZE)
24162306a36Sopenharmony_ci		ui_browser__handle_resize(browser);
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci	return key;
24462306a36Sopenharmony_ci}
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_cibool ui_browser__dialog_yesno(struct ui_browser *browser, const char *text)
24762306a36Sopenharmony_ci{
24862306a36Sopenharmony_ci	int key;
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci	while ((key = ui__dialog_yesno(text)) == K_RESIZE)
25162306a36Sopenharmony_ci		ui_browser__handle_resize(browser);
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	return key == K_ENTER || toupper(key) == 'Y';
25462306a36Sopenharmony_ci}
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_civoid ui_browser__reset_index(struct ui_browser *browser)
25762306a36Sopenharmony_ci{
25862306a36Sopenharmony_ci	browser->index = browser->top_idx = 0;
25962306a36Sopenharmony_ci	browser->seek(browser, 0, SEEK_SET);
26062306a36Sopenharmony_ci}
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_civoid __ui_browser__show_title(struct ui_browser *browser, const char *title)
26362306a36Sopenharmony_ci{
26462306a36Sopenharmony_ci	SLsmg_gotorc(0, 0);
26562306a36Sopenharmony_ci	ui_browser__set_color(browser, HE_COLORSET_ROOT);
26662306a36Sopenharmony_ci	ui_browser__write_nstring(browser, title, browser->width + 1);
26762306a36Sopenharmony_ci}
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_civoid ui_browser__show_title(struct ui_browser *browser, const char *title)
27062306a36Sopenharmony_ci{
27162306a36Sopenharmony_ci	mutex_lock(&ui__lock);
27262306a36Sopenharmony_ci	__ui_browser__show_title(browser, title);
27362306a36Sopenharmony_ci	mutex_unlock(&ui__lock);
27462306a36Sopenharmony_ci}
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ciint ui_browser__show(struct ui_browser *browser, const char *title,
27762306a36Sopenharmony_ci		     const char *helpline, ...)
27862306a36Sopenharmony_ci{
27962306a36Sopenharmony_ci	int err;
28062306a36Sopenharmony_ci	va_list ap;
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci	if (browser->refresh_dimensions == NULL)
28362306a36Sopenharmony_ci		browser->refresh_dimensions = ui_browser__refresh_dimensions;
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci	browser->refresh_dimensions(browser);
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci	mutex_lock(&ui__lock);
28862306a36Sopenharmony_ci	__ui_browser__show_title(browser, title);
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci	browser->title = title;
29162306a36Sopenharmony_ci	zfree(&browser->helpline);
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci	va_start(ap, helpline);
29462306a36Sopenharmony_ci	err = vasprintf(&browser->helpline, helpline, ap);
29562306a36Sopenharmony_ci	va_end(ap);
29662306a36Sopenharmony_ci	if (err > 0)
29762306a36Sopenharmony_ci		ui_helpline__push(browser->helpline);
29862306a36Sopenharmony_ci	mutex_unlock(&ui__lock);
29962306a36Sopenharmony_ci	return err ? 0 : -1;
30062306a36Sopenharmony_ci}
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_civoid ui_browser__hide(struct ui_browser *browser)
30362306a36Sopenharmony_ci{
30462306a36Sopenharmony_ci	mutex_lock(&ui__lock);
30562306a36Sopenharmony_ci	ui_helpline__pop();
30662306a36Sopenharmony_ci	zfree(&browser->helpline);
30762306a36Sopenharmony_ci	mutex_unlock(&ui__lock);
30862306a36Sopenharmony_ci}
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_cistatic void ui_browser__scrollbar_set(struct ui_browser *browser)
31162306a36Sopenharmony_ci{
31262306a36Sopenharmony_ci	int height = browser->height, h = 0, pct = 0,
31362306a36Sopenharmony_ci	    col = browser->width,
31462306a36Sopenharmony_ci	    row = 0;
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci	if (browser->nr_entries > 1) {
31762306a36Sopenharmony_ci		pct = ((browser->index * (browser->height - 1)) /
31862306a36Sopenharmony_ci		       (browser->nr_entries - 1));
31962306a36Sopenharmony_ci	}
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci	SLsmg_set_char_set(1);
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci	while (h < height) {
32462306a36Sopenharmony_ci	        ui_browser__gotorc(browser, row++, col);
32562306a36Sopenharmony_ci		SLsmg_write_char(h == pct ? SLSMG_DIAMOND_CHAR : SLSMG_CKBRD_CHAR);
32662306a36Sopenharmony_ci		++h;
32762306a36Sopenharmony_ci	}
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci	SLsmg_set_char_set(0);
33062306a36Sopenharmony_ci}
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_cistatic int __ui_browser__refresh(struct ui_browser *browser)
33362306a36Sopenharmony_ci{
33462306a36Sopenharmony_ci	int row;
33562306a36Sopenharmony_ci	int width = browser->width;
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci	row = browser->refresh(browser);
33862306a36Sopenharmony_ci	ui_browser__set_color(browser, HE_COLORSET_NORMAL);
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci	if (!browser->use_navkeypressed || browser->navkeypressed)
34162306a36Sopenharmony_ci		ui_browser__scrollbar_set(browser);
34262306a36Sopenharmony_ci	else
34362306a36Sopenharmony_ci		width += 1;
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	SLsmg_fill_region(browser->y + row + browser->extra_title_lines, browser->x,
34662306a36Sopenharmony_ci			  browser->rows - row, width, ' ');
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci	if (browser->nr_entries == 0 && browser->no_samples_msg)
34962306a36Sopenharmony_ci		__ui__info_window(NULL, browser->no_samples_msg, NULL);
35062306a36Sopenharmony_ci	return 0;
35162306a36Sopenharmony_ci}
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ciint ui_browser__refresh(struct ui_browser *browser)
35462306a36Sopenharmony_ci{
35562306a36Sopenharmony_ci	mutex_lock(&ui__lock);
35662306a36Sopenharmony_ci	__ui_browser__refresh(browser);
35762306a36Sopenharmony_ci	mutex_unlock(&ui__lock);
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	return 0;
36062306a36Sopenharmony_ci}
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci/*
36362306a36Sopenharmony_ci * Here we're updating nr_entries _after_ we started browsing, i.e.  we have to
36462306a36Sopenharmony_ci * forget about any reference to any entry in the underlying data structure,
36562306a36Sopenharmony_ci * that is why we do a SEEK_SET. Think about 'perf top' in the hists browser
36662306a36Sopenharmony_ci * after an output_resort and hist decay.
36762306a36Sopenharmony_ci */
36862306a36Sopenharmony_civoid ui_browser__update_nr_entries(struct ui_browser *browser, u32 nr_entries)
36962306a36Sopenharmony_ci{
37062306a36Sopenharmony_ci	off_t offset = nr_entries - browser->nr_entries;
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci	browser->nr_entries = nr_entries;
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci	if (offset < 0) {
37562306a36Sopenharmony_ci		if (browser->top_idx < (u64)-offset)
37662306a36Sopenharmony_ci			offset = -browser->top_idx;
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci		browser->index += offset;
37962306a36Sopenharmony_ci		browser->top_idx += offset;
38062306a36Sopenharmony_ci	}
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ci	browser->top = NULL;
38362306a36Sopenharmony_ci	browser->seek(browser, browser->top_idx, SEEK_SET);
38462306a36Sopenharmony_ci}
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ciint ui_browser__run(struct ui_browser *browser, int delay_secs)
38762306a36Sopenharmony_ci{
38862306a36Sopenharmony_ci	int err, key;
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci	while (1) {
39162306a36Sopenharmony_ci		off_t offset;
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci		mutex_lock(&ui__lock);
39462306a36Sopenharmony_ci		err = __ui_browser__refresh(browser);
39562306a36Sopenharmony_ci		SLsmg_refresh();
39662306a36Sopenharmony_ci		mutex_unlock(&ui__lock);
39762306a36Sopenharmony_ci		if (err < 0)
39862306a36Sopenharmony_ci			break;
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci		key = ui__getch(delay_secs);
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci		if (key == K_RESIZE) {
40362306a36Sopenharmony_ci			ui__refresh_dimensions(false);
40462306a36Sopenharmony_ci			browser->refresh_dimensions(browser);
40562306a36Sopenharmony_ci			__ui_browser__show_title(browser, browser->title);
40662306a36Sopenharmony_ci			ui_helpline__puts(browser->helpline);
40762306a36Sopenharmony_ci			continue;
40862306a36Sopenharmony_ci		}
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci		if (browser->use_navkeypressed && !browser->navkeypressed) {
41162306a36Sopenharmony_ci			if (key == K_DOWN || key == K_UP ||
41262306a36Sopenharmony_ci			    (browser->columns && (key == K_LEFT || key == K_RIGHT)) ||
41362306a36Sopenharmony_ci			    key == K_PGDN || key == K_PGUP ||
41462306a36Sopenharmony_ci			    key == K_HOME || key == K_END ||
41562306a36Sopenharmony_ci			    key == ' ') {
41662306a36Sopenharmony_ci				browser->navkeypressed = true;
41762306a36Sopenharmony_ci				continue;
41862306a36Sopenharmony_ci			} else
41962306a36Sopenharmony_ci				return key;
42062306a36Sopenharmony_ci		}
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci		switch (key) {
42362306a36Sopenharmony_ci		case K_DOWN:
42462306a36Sopenharmony_ci			if (browser->index == browser->nr_entries - 1)
42562306a36Sopenharmony_ci				break;
42662306a36Sopenharmony_ci			++browser->index;
42762306a36Sopenharmony_ci			if (browser->index == browser->top_idx + browser->rows) {
42862306a36Sopenharmony_ci				++browser->top_idx;
42962306a36Sopenharmony_ci				browser->seek(browser, +1, SEEK_CUR);
43062306a36Sopenharmony_ci			}
43162306a36Sopenharmony_ci			break;
43262306a36Sopenharmony_ci		case K_UP:
43362306a36Sopenharmony_ci			if (browser->index == 0)
43462306a36Sopenharmony_ci				break;
43562306a36Sopenharmony_ci			--browser->index;
43662306a36Sopenharmony_ci			if (browser->index < browser->top_idx) {
43762306a36Sopenharmony_ci				--browser->top_idx;
43862306a36Sopenharmony_ci				browser->seek(browser, -1, SEEK_CUR);
43962306a36Sopenharmony_ci			}
44062306a36Sopenharmony_ci			break;
44162306a36Sopenharmony_ci		case K_RIGHT:
44262306a36Sopenharmony_ci			if (!browser->columns)
44362306a36Sopenharmony_ci				goto out;
44462306a36Sopenharmony_ci			if (browser->horiz_scroll < browser->columns - 1)
44562306a36Sopenharmony_ci				++browser->horiz_scroll;
44662306a36Sopenharmony_ci			break;
44762306a36Sopenharmony_ci		case K_LEFT:
44862306a36Sopenharmony_ci			if (!browser->columns)
44962306a36Sopenharmony_ci				goto out;
45062306a36Sopenharmony_ci			if (browser->horiz_scroll != 0)
45162306a36Sopenharmony_ci				--browser->horiz_scroll;
45262306a36Sopenharmony_ci			break;
45362306a36Sopenharmony_ci		case K_PGDN:
45462306a36Sopenharmony_ci		case ' ':
45562306a36Sopenharmony_ci			if (browser->top_idx + browser->rows > browser->nr_entries - 1)
45662306a36Sopenharmony_ci				break;
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ci			offset = browser->rows;
45962306a36Sopenharmony_ci			if (browser->index + offset > browser->nr_entries - 1)
46062306a36Sopenharmony_ci				offset = browser->nr_entries - 1 - browser->index;
46162306a36Sopenharmony_ci			browser->index += offset;
46262306a36Sopenharmony_ci			browser->top_idx += offset;
46362306a36Sopenharmony_ci			browser->seek(browser, +offset, SEEK_CUR);
46462306a36Sopenharmony_ci			break;
46562306a36Sopenharmony_ci		case K_PGUP:
46662306a36Sopenharmony_ci			if (browser->top_idx == 0)
46762306a36Sopenharmony_ci				break;
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci			if (browser->top_idx < browser->rows)
47062306a36Sopenharmony_ci				offset = browser->top_idx;
47162306a36Sopenharmony_ci			else
47262306a36Sopenharmony_ci				offset = browser->rows;
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci			browser->index -= offset;
47562306a36Sopenharmony_ci			browser->top_idx -= offset;
47662306a36Sopenharmony_ci			browser->seek(browser, -offset, SEEK_CUR);
47762306a36Sopenharmony_ci			break;
47862306a36Sopenharmony_ci		case K_HOME:
47962306a36Sopenharmony_ci			ui_browser__reset_index(browser);
48062306a36Sopenharmony_ci			break;
48162306a36Sopenharmony_ci		case K_END:
48262306a36Sopenharmony_ci			offset = browser->rows - 1;
48362306a36Sopenharmony_ci			if (offset >= browser->nr_entries)
48462306a36Sopenharmony_ci				offset = browser->nr_entries - 1;
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci			browser->index = browser->nr_entries - 1;
48762306a36Sopenharmony_ci			browser->top_idx = browser->index - offset;
48862306a36Sopenharmony_ci			browser->seek(browser, -offset, SEEK_END);
48962306a36Sopenharmony_ci			break;
49062306a36Sopenharmony_ci		default:
49162306a36Sopenharmony_ci		out:
49262306a36Sopenharmony_ci			return key;
49362306a36Sopenharmony_ci		}
49462306a36Sopenharmony_ci	}
49562306a36Sopenharmony_ci	return -1;
49662306a36Sopenharmony_ci}
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ciunsigned int ui_browser__list_head_refresh(struct ui_browser *browser)
49962306a36Sopenharmony_ci{
50062306a36Sopenharmony_ci	struct list_head *pos;
50162306a36Sopenharmony_ci	struct list_head *head = browser->entries;
50262306a36Sopenharmony_ci	int row = 0;
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci	if (browser->top == NULL || browser->top == browser->entries)
50562306a36Sopenharmony_ci                browser->top = ui_browser__list_head_filter_entries(browser, head->next);
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci	pos = browser->top;
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci	list_for_each_from(pos, head) {
51062306a36Sopenharmony_ci		if (!browser->filter || !browser->filter(browser, pos)) {
51162306a36Sopenharmony_ci			ui_browser__gotorc(browser, row, 0);
51262306a36Sopenharmony_ci			browser->write(browser, pos, row);
51362306a36Sopenharmony_ci			if (++row == browser->rows)
51462306a36Sopenharmony_ci				break;
51562306a36Sopenharmony_ci		}
51662306a36Sopenharmony_ci	}
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci	return row;
51962306a36Sopenharmony_ci}
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_cistatic struct ui_browser_colorset {
52262306a36Sopenharmony_ci	const char *name, *fg, *bg;
52362306a36Sopenharmony_ci	int colorset;
52462306a36Sopenharmony_ci} ui_browser__colorsets[] = {
52562306a36Sopenharmony_ci	{
52662306a36Sopenharmony_ci		.colorset = HE_COLORSET_TOP,
52762306a36Sopenharmony_ci		.name	  = "top",
52862306a36Sopenharmony_ci		.fg	  = "red",
52962306a36Sopenharmony_ci		.bg	  = "default",
53062306a36Sopenharmony_ci	},
53162306a36Sopenharmony_ci	{
53262306a36Sopenharmony_ci		.colorset = HE_COLORSET_MEDIUM,
53362306a36Sopenharmony_ci		.name	  = "medium",
53462306a36Sopenharmony_ci		.fg	  = "green",
53562306a36Sopenharmony_ci		.bg	  = "default",
53662306a36Sopenharmony_ci	},
53762306a36Sopenharmony_ci	{
53862306a36Sopenharmony_ci		.colorset = HE_COLORSET_NORMAL,
53962306a36Sopenharmony_ci		.name	  = "normal",
54062306a36Sopenharmony_ci		.fg	  = "default",
54162306a36Sopenharmony_ci		.bg	  = "default",
54262306a36Sopenharmony_ci	},
54362306a36Sopenharmony_ci	{
54462306a36Sopenharmony_ci		.colorset = HE_COLORSET_SELECTED,
54562306a36Sopenharmony_ci		.name	  = "selected",
54662306a36Sopenharmony_ci		.fg	  = "black",
54762306a36Sopenharmony_ci		.bg	  = "yellow",
54862306a36Sopenharmony_ci	},
54962306a36Sopenharmony_ci	{
55062306a36Sopenharmony_ci		.colorset = HE_COLORSET_JUMP_ARROWS,
55162306a36Sopenharmony_ci		.name	  = "jump_arrows",
55262306a36Sopenharmony_ci		.fg	  = "blue",
55362306a36Sopenharmony_ci		.bg	  = "default",
55462306a36Sopenharmony_ci	},
55562306a36Sopenharmony_ci	{
55662306a36Sopenharmony_ci		.colorset = HE_COLORSET_ADDR,
55762306a36Sopenharmony_ci		.name	  = "addr",
55862306a36Sopenharmony_ci		.fg	  = "magenta",
55962306a36Sopenharmony_ci		.bg	  = "default",
56062306a36Sopenharmony_ci	},
56162306a36Sopenharmony_ci	{
56262306a36Sopenharmony_ci		.colorset = HE_COLORSET_ROOT,
56362306a36Sopenharmony_ci		.name	  = "root",
56462306a36Sopenharmony_ci		.fg	  = "white",
56562306a36Sopenharmony_ci		.bg	  = "blue",
56662306a36Sopenharmony_ci	},
56762306a36Sopenharmony_ci	{
56862306a36Sopenharmony_ci		.name = NULL,
56962306a36Sopenharmony_ci	}
57062306a36Sopenharmony_ci};
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_cistatic int ui_browser__color_config(const char *var, const char *value,
57462306a36Sopenharmony_ci				    void *data __maybe_unused)
57562306a36Sopenharmony_ci{
57662306a36Sopenharmony_ci	char *fg = NULL, *bg;
57762306a36Sopenharmony_ci	int i;
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_ci	/* same dir for all commands */
58062306a36Sopenharmony_ci	if (!strstarts(var, "colors.") != 0)
58162306a36Sopenharmony_ci		return 0;
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_ci	for (i = 0; ui_browser__colorsets[i].name != NULL; ++i) {
58462306a36Sopenharmony_ci		const char *name = var + 7;
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_ci		if (strcmp(ui_browser__colorsets[i].name, name) != 0)
58762306a36Sopenharmony_ci			continue;
58862306a36Sopenharmony_ci
58962306a36Sopenharmony_ci		fg = strdup(value);
59062306a36Sopenharmony_ci		if (fg == NULL)
59162306a36Sopenharmony_ci			break;
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_ci		bg = strchr(fg, ',');
59462306a36Sopenharmony_ci		if (bg == NULL)
59562306a36Sopenharmony_ci			break;
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_ci		*bg = '\0';
59862306a36Sopenharmony_ci		bg = skip_spaces(bg + 1);
59962306a36Sopenharmony_ci		ui_browser__colorsets[i].bg = bg;
60062306a36Sopenharmony_ci		ui_browser__colorsets[i].fg = fg;
60162306a36Sopenharmony_ci		return 0;
60262306a36Sopenharmony_ci	}
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_ci	free(fg);
60562306a36Sopenharmony_ci	return -1;
60662306a36Sopenharmony_ci}
60762306a36Sopenharmony_ci
60862306a36Sopenharmony_civoid ui_browser__argv_seek(struct ui_browser *browser, off_t offset, int whence)
60962306a36Sopenharmony_ci{
61062306a36Sopenharmony_ci	switch (whence) {
61162306a36Sopenharmony_ci	case SEEK_SET:
61262306a36Sopenharmony_ci		browser->top = browser->entries;
61362306a36Sopenharmony_ci		break;
61462306a36Sopenharmony_ci	case SEEK_CUR:
61562306a36Sopenharmony_ci		browser->top = (char **)browser->top + offset;
61662306a36Sopenharmony_ci		break;
61762306a36Sopenharmony_ci	case SEEK_END:
61862306a36Sopenharmony_ci		browser->top = (char **)browser->entries + browser->nr_entries - 1 + offset;
61962306a36Sopenharmony_ci		break;
62062306a36Sopenharmony_ci	default:
62162306a36Sopenharmony_ci		return;
62262306a36Sopenharmony_ci	}
62362306a36Sopenharmony_ci	assert((char **)browser->top < (char **)browser->entries + browser->nr_entries);
62462306a36Sopenharmony_ci	assert((char **)browser->top >= (char **)browser->entries);
62562306a36Sopenharmony_ci}
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_ciunsigned int ui_browser__argv_refresh(struct ui_browser *browser)
62862306a36Sopenharmony_ci{
62962306a36Sopenharmony_ci	unsigned int row = 0, idx = browser->top_idx;
63062306a36Sopenharmony_ci	char **pos;
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_ci	if (browser->top == NULL)
63362306a36Sopenharmony_ci		browser->top = browser->entries;
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_ci	pos = (char **)browser->top;
63662306a36Sopenharmony_ci	while (idx < browser->nr_entries &&
63762306a36Sopenharmony_ci	       row < (unsigned)SLtt_Screen_Rows - 1) {
63862306a36Sopenharmony_ci		assert(pos < (char **)browser->entries + browser->nr_entries);
63962306a36Sopenharmony_ci		if (!browser->filter || !browser->filter(browser, *pos)) {
64062306a36Sopenharmony_ci			ui_browser__gotorc(browser, row, 0);
64162306a36Sopenharmony_ci			browser->write(browser, pos, row);
64262306a36Sopenharmony_ci			if (++row == browser->rows)
64362306a36Sopenharmony_ci				break;
64462306a36Sopenharmony_ci		}
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_ci		++idx;
64762306a36Sopenharmony_ci		++pos;
64862306a36Sopenharmony_ci	}
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_ci	return row;
65162306a36Sopenharmony_ci}
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_civoid __ui_browser__vline(struct ui_browser *browser, unsigned int column,
65462306a36Sopenharmony_ci			 u16 start, u16 end)
65562306a36Sopenharmony_ci{
65662306a36Sopenharmony_ci	SLsmg_set_char_set(1);
65762306a36Sopenharmony_ci	ui_browser__gotorc(browser, start, column);
65862306a36Sopenharmony_ci	SLsmg_draw_vline(end - start + 1);
65962306a36Sopenharmony_ci	SLsmg_set_char_set(0);
66062306a36Sopenharmony_ci}
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_civoid ui_browser__write_graph(struct ui_browser *browser __maybe_unused,
66362306a36Sopenharmony_ci			     int graph)
66462306a36Sopenharmony_ci{
66562306a36Sopenharmony_ci	SLsmg_set_char_set(1);
66662306a36Sopenharmony_ci	SLsmg_write_char(graph);
66762306a36Sopenharmony_ci	SLsmg_set_char_set(0);
66862306a36Sopenharmony_ci}
66962306a36Sopenharmony_ci
67062306a36Sopenharmony_cistatic void __ui_browser__line_arrow_up(struct ui_browser *browser,
67162306a36Sopenharmony_ci					unsigned int column,
67262306a36Sopenharmony_ci					u64 start, u64 end)
67362306a36Sopenharmony_ci{
67462306a36Sopenharmony_ci	unsigned int row, end_row;
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ci	SLsmg_set_char_set(1);
67762306a36Sopenharmony_ci
67862306a36Sopenharmony_ci	if (start < browser->top_idx + browser->rows) {
67962306a36Sopenharmony_ci		row = start - browser->top_idx;
68062306a36Sopenharmony_ci		ui_browser__gotorc(browser, row, column);
68162306a36Sopenharmony_ci		SLsmg_write_char(SLSMG_LLCORN_CHAR);
68262306a36Sopenharmony_ci		ui_browser__gotorc(browser, row, column + 1);
68362306a36Sopenharmony_ci		SLsmg_draw_hline(2);
68462306a36Sopenharmony_ci
68562306a36Sopenharmony_ci		if (row-- == 0)
68662306a36Sopenharmony_ci			goto out;
68762306a36Sopenharmony_ci	} else
68862306a36Sopenharmony_ci		row = browser->rows - 1;
68962306a36Sopenharmony_ci
69062306a36Sopenharmony_ci	if (end > browser->top_idx)
69162306a36Sopenharmony_ci		end_row = end - browser->top_idx;
69262306a36Sopenharmony_ci	else
69362306a36Sopenharmony_ci		end_row = 0;
69462306a36Sopenharmony_ci
69562306a36Sopenharmony_ci	ui_browser__gotorc(browser, end_row, column);
69662306a36Sopenharmony_ci	SLsmg_draw_vline(row - end_row + 1);
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_ci	ui_browser__gotorc(browser, end_row, column);
69962306a36Sopenharmony_ci	if (end >= browser->top_idx) {
70062306a36Sopenharmony_ci		SLsmg_write_char(SLSMG_ULCORN_CHAR);
70162306a36Sopenharmony_ci		ui_browser__gotorc(browser, end_row, column + 1);
70262306a36Sopenharmony_ci		SLsmg_write_char(SLSMG_HLINE_CHAR);
70362306a36Sopenharmony_ci		ui_browser__gotorc(browser, end_row, column + 2);
70462306a36Sopenharmony_ci		SLsmg_write_char(SLSMG_RARROW_CHAR);
70562306a36Sopenharmony_ci	}
70662306a36Sopenharmony_ciout:
70762306a36Sopenharmony_ci	SLsmg_set_char_set(0);
70862306a36Sopenharmony_ci}
70962306a36Sopenharmony_ci
71062306a36Sopenharmony_cistatic void __ui_browser__line_arrow_down(struct ui_browser *browser,
71162306a36Sopenharmony_ci					  unsigned int column,
71262306a36Sopenharmony_ci					  u64 start, u64 end)
71362306a36Sopenharmony_ci{
71462306a36Sopenharmony_ci	unsigned int row, end_row;
71562306a36Sopenharmony_ci
71662306a36Sopenharmony_ci	SLsmg_set_char_set(1);
71762306a36Sopenharmony_ci
71862306a36Sopenharmony_ci	if (start >= browser->top_idx) {
71962306a36Sopenharmony_ci		row = start - browser->top_idx;
72062306a36Sopenharmony_ci		ui_browser__gotorc(browser, row, column);
72162306a36Sopenharmony_ci		SLsmg_write_char(SLSMG_ULCORN_CHAR);
72262306a36Sopenharmony_ci		ui_browser__gotorc(browser, row, column + 1);
72362306a36Sopenharmony_ci		SLsmg_draw_hline(2);
72462306a36Sopenharmony_ci
72562306a36Sopenharmony_ci		if (++row == 0)
72662306a36Sopenharmony_ci			goto out;
72762306a36Sopenharmony_ci	} else
72862306a36Sopenharmony_ci		row = 0;
72962306a36Sopenharmony_ci
73062306a36Sopenharmony_ci	if (end >= browser->top_idx + browser->rows)
73162306a36Sopenharmony_ci		end_row = browser->rows - 1;
73262306a36Sopenharmony_ci	else
73362306a36Sopenharmony_ci		end_row = end - browser->top_idx;
73462306a36Sopenharmony_ci
73562306a36Sopenharmony_ci	ui_browser__gotorc(browser, row, column);
73662306a36Sopenharmony_ci	SLsmg_draw_vline(end_row - row + 1);
73762306a36Sopenharmony_ci
73862306a36Sopenharmony_ci	ui_browser__gotorc(browser, end_row, column);
73962306a36Sopenharmony_ci	if (end < browser->top_idx + browser->rows) {
74062306a36Sopenharmony_ci		SLsmg_write_char(SLSMG_LLCORN_CHAR);
74162306a36Sopenharmony_ci		ui_browser__gotorc(browser, end_row, column + 1);
74262306a36Sopenharmony_ci		SLsmg_write_char(SLSMG_HLINE_CHAR);
74362306a36Sopenharmony_ci		ui_browser__gotorc(browser, end_row, column + 2);
74462306a36Sopenharmony_ci		SLsmg_write_char(SLSMG_RARROW_CHAR);
74562306a36Sopenharmony_ci	}
74662306a36Sopenharmony_ciout:
74762306a36Sopenharmony_ci	SLsmg_set_char_set(0);
74862306a36Sopenharmony_ci}
74962306a36Sopenharmony_ci
75062306a36Sopenharmony_civoid __ui_browser__line_arrow(struct ui_browser *browser, unsigned int column,
75162306a36Sopenharmony_ci			      u64 start, u64 end)
75262306a36Sopenharmony_ci{
75362306a36Sopenharmony_ci	if (start > end)
75462306a36Sopenharmony_ci		__ui_browser__line_arrow_up(browser, column, start, end);
75562306a36Sopenharmony_ci	else
75662306a36Sopenharmony_ci		__ui_browser__line_arrow_down(browser, column, start, end);
75762306a36Sopenharmony_ci}
75862306a36Sopenharmony_ci
75962306a36Sopenharmony_civoid ui_browser__mark_fused(struct ui_browser *browser, unsigned int column,
76062306a36Sopenharmony_ci			    unsigned int row, int diff, bool arrow_down)
76162306a36Sopenharmony_ci{
76262306a36Sopenharmony_ci	int end_row;
76362306a36Sopenharmony_ci
76462306a36Sopenharmony_ci	if (diff <= 0)
76562306a36Sopenharmony_ci		return;
76662306a36Sopenharmony_ci
76762306a36Sopenharmony_ci	SLsmg_set_char_set(1);
76862306a36Sopenharmony_ci
76962306a36Sopenharmony_ci	if (arrow_down) {
77062306a36Sopenharmony_ci		if (row + diff <= browser->top_idx)
77162306a36Sopenharmony_ci			return;
77262306a36Sopenharmony_ci
77362306a36Sopenharmony_ci		end_row = row + diff - browser->top_idx;
77462306a36Sopenharmony_ci		ui_browser__gotorc(browser, end_row, column - 1);
77562306a36Sopenharmony_ci		SLsmg_write_char(SLSMG_LTEE_CHAR);
77662306a36Sopenharmony_ci
77762306a36Sopenharmony_ci		while (--end_row >= 0 && end_row > (int)(row - browser->top_idx)) {
77862306a36Sopenharmony_ci			ui_browser__gotorc(browser, end_row, column - 1);
77962306a36Sopenharmony_ci			SLsmg_draw_vline(1);
78062306a36Sopenharmony_ci		}
78162306a36Sopenharmony_ci
78262306a36Sopenharmony_ci		end_row = (int)(row - browser->top_idx);
78362306a36Sopenharmony_ci		if (end_row >= 0) {
78462306a36Sopenharmony_ci			ui_browser__gotorc(browser, end_row, column - 1);
78562306a36Sopenharmony_ci			SLsmg_write_char(SLSMG_ULCORN_CHAR);
78662306a36Sopenharmony_ci			ui_browser__gotorc(browser, end_row, column);
78762306a36Sopenharmony_ci			SLsmg_draw_hline(2);
78862306a36Sopenharmony_ci		}
78962306a36Sopenharmony_ci	} else {
79062306a36Sopenharmony_ci		if (row < browser->top_idx)
79162306a36Sopenharmony_ci			return;
79262306a36Sopenharmony_ci
79362306a36Sopenharmony_ci		end_row = row - browser->top_idx;
79462306a36Sopenharmony_ci		ui_browser__gotorc(browser, end_row, column - 1);
79562306a36Sopenharmony_ci		SLsmg_write_char(SLSMG_LTEE_CHAR);
79662306a36Sopenharmony_ci		ui_browser__gotorc(browser, end_row, column);
79762306a36Sopenharmony_ci		SLsmg_draw_hline(2);
79862306a36Sopenharmony_ci	}
79962306a36Sopenharmony_ci
80062306a36Sopenharmony_ci	SLsmg_set_char_set(0);
80162306a36Sopenharmony_ci}
80262306a36Sopenharmony_ci
80362306a36Sopenharmony_civoid ui_browser__init(void)
80462306a36Sopenharmony_ci{
80562306a36Sopenharmony_ci	int i = 0;
80662306a36Sopenharmony_ci
80762306a36Sopenharmony_ci	perf_config(ui_browser__color_config, NULL);
80862306a36Sopenharmony_ci
80962306a36Sopenharmony_ci	while (ui_browser__colorsets[i].name) {
81062306a36Sopenharmony_ci		struct ui_browser_colorset *c = &ui_browser__colorsets[i++];
81162306a36Sopenharmony_ci		SLtt_set_color(c->colorset, c->name, c->fg, c->bg);
81262306a36Sopenharmony_ci	}
81362306a36Sopenharmony_ci}
814