Home | History | Annotate | Download | only in ui
      1 #include "libslang.h"
      2 #include "ui.h"
      3 #include <linux/compiler.h>
      4 #include <linux/list.h>
      5 #include <linux/rbtree.h>
      6 #include <stdlib.h>
      7 #include <sys/ttydefaults.h>
      8 #include "browser.h"
      9 #include "helpline.h"
     10 #include "../color.h"
     11 #include "../util.h"
     12 #include <stdio.h>
     13 
     14 static int ui_browser__percent_color(double percent, bool current)
     15 {
     16 	if (current)
     17 		return HE_COLORSET_SELECTED;
     18 	if (percent >= MIN_RED)
     19 		return HE_COLORSET_TOP;
     20 	if (percent >= MIN_GREEN)
     21 		return HE_COLORSET_MEDIUM;
     22 	return HE_COLORSET_NORMAL;
     23 }
     24 
     25 void ui_browser__set_color(struct ui_browser *self __used, int color)
     26 {
     27 	SLsmg_set_color(color);
     28 }
     29 
     30 void ui_browser__set_percent_color(struct ui_browser *self,
     31 				   double percent, bool current)
     32 {
     33 	 int color = ui_browser__percent_color(percent, current);
     34 	 ui_browser__set_color(self, color);
     35 }
     36 
     37 void ui_browser__gotorc(struct ui_browser *self, int y, int x)
     38 {
     39 	SLsmg_gotorc(self->y + y, self->x + x);
     40 }
     41 
     42 void ui_browser__list_head_seek(struct ui_browser *self, off_t offset, int whence)
     43 {
     44 	struct list_head *head = self->entries;
     45 	struct list_head *pos;
     46 
     47 	switch (whence) {
     48 	case SEEK_SET:
     49 		pos = head->next;
     50 		break;
     51 	case SEEK_CUR:
     52 		pos = self->top;
     53 		break;
     54 	case SEEK_END:
     55 		pos = head->prev;
     56 		break;
     57 	default:
     58 		return;
     59 	}
     60 
     61 	if (offset > 0) {
     62 		while (offset-- != 0)
     63 			pos = pos->next;
     64 	} else {
     65 		while (offset++ != 0)
     66 			pos = pos->prev;
     67 	}
     68 
     69 	self->top = pos;
     70 }
     71 
     72 void ui_browser__rb_tree_seek(struct ui_browser *self, off_t offset, int whence)
     73 {
     74 	struct rb_root *root = self->entries;
     75 	struct rb_node *nd;
     76 
     77 	switch (whence) {
     78 	case SEEK_SET:
     79 		nd = rb_first(root);
     80 		break;
     81 	case SEEK_CUR:
     82 		nd = self->top;
     83 		break;
     84 	case SEEK_END:
     85 		nd = rb_last(root);
     86 		break;
     87 	default:
     88 		return;
     89 	}
     90 
     91 	if (offset > 0) {
     92 		while (offset-- != 0)
     93 			nd = rb_next(nd);
     94 	} else {
     95 		while (offset++ != 0)
     96 			nd = rb_prev(nd);
     97 	}
     98 
     99 	self->top = nd;
    100 }
    101 
    102 unsigned int ui_browser__rb_tree_refresh(struct ui_browser *self)
    103 {
    104 	struct rb_node *nd;
    105 	int row = 0;
    106 
    107 	if (self->top == NULL)
    108                 self->top = rb_first(self->entries);
    109 
    110 	nd = self->top;
    111 
    112 	while (nd != NULL) {
    113 		ui_browser__gotorc(self, row, 0);
    114 		self->write(self, nd, row);
    115 		if (++row == self->height)
    116 			break;
    117 		nd = rb_next(nd);
    118 	}
    119 
    120 	return row;
    121 }
    122 
    123 bool ui_browser__is_current_entry(struct ui_browser *self, unsigned row)
    124 {
    125 	return self->top_idx + row == self->index;
    126 }
    127 
    128 void ui_browser__refresh_dimensions(struct ui_browser *self)
    129 {
    130 	int cols, rows;
    131 	newtGetScreenSize(&cols, &rows);
    132 
    133 	self->width = cols - 1;
    134 	self->height = rows - 2;
    135 	self->y = 1;
    136 	self->x = 0;
    137 }
    138 
    139 void ui_browser__reset_index(struct ui_browser *self)
    140 {
    141 	self->index = self->top_idx = 0;
    142 	self->seek(self, 0, SEEK_SET);
    143 }
    144 
    145 void ui_browser__add_exit_key(struct ui_browser *self, int key)
    146 {
    147 	newtFormAddHotKey(self->form, key);
    148 }
    149 
    150 void ui_browser__add_exit_keys(struct ui_browser *self, int keys[])
    151 {
    152 	int i = 0;
    153 
    154 	while (keys[i] && i < 64) {
    155 		ui_browser__add_exit_key(self, keys[i]);
    156 		++i;
    157 	}
    158 }
    159 
    160 void __ui_browser__show_title(struct ui_browser *browser, const char *title)
    161 {
    162 	SLsmg_gotorc(0, 0);
    163 	ui_browser__set_color(browser, NEWT_COLORSET_ROOT);
    164 	slsmg_write_nstring(title, browser->width);
    165 }
    166 
    167 void ui_browser__show_title(struct ui_browser *browser, const char *title)
    168 {
    169 	pthread_mutex_lock(&ui__lock);
    170 	__ui_browser__show_title(browser, title);
    171 	pthread_mutex_unlock(&ui__lock);
    172 }
    173 
    174 int ui_browser__show(struct ui_browser *self, const char *title,
    175 		     const char *helpline, ...)
    176 {
    177 	va_list ap;
    178 	int keys[] = { NEWT_KEY_UP, NEWT_KEY_DOWN, NEWT_KEY_PGUP,
    179 		       NEWT_KEY_PGDN, NEWT_KEY_HOME, NEWT_KEY_END, ' ',
    180 		       NEWT_KEY_LEFT, NEWT_KEY_ESCAPE, 'q', CTRL('c'), 0 };
    181 
    182 	if (self->form != NULL)
    183 		newtFormDestroy(self->form);
    184 
    185 	ui_browser__refresh_dimensions(self);
    186 	self->form = newtForm(NULL, NULL, 0);
    187 	if (self->form == NULL)
    188 		return -1;
    189 
    190 	self->sb = newtVerticalScrollbar(self->width, 1, self->height,
    191 					 HE_COLORSET_NORMAL,
    192 					 HE_COLORSET_SELECTED);
    193 	if (self->sb == NULL)
    194 		return -1;
    195 
    196 	pthread_mutex_lock(&ui__lock);
    197 	__ui_browser__show_title(self, title);
    198 
    199 	ui_browser__add_exit_keys(self, keys);
    200 	newtFormAddComponent(self->form, self->sb);
    201 
    202 	va_start(ap, helpline);
    203 	ui_helpline__vpush(helpline, ap);
    204 	va_end(ap);
    205 	pthread_mutex_unlock(&ui__lock);
    206 	return 0;
    207 }
    208 
    209 void ui_browser__hide(struct ui_browser *self)
    210 {
    211 	pthread_mutex_lock(&ui__lock);
    212 	newtFormDestroy(self->form);
    213 	self->form = NULL;
    214 	ui_helpline__pop();
    215 	pthread_mutex_unlock(&ui__lock);
    216 }
    217 
    218 int ui_browser__refresh(struct ui_browser *self)
    219 {
    220 	int row;
    221 
    222 	pthread_mutex_lock(&ui__lock);
    223 	newtScrollbarSet(self->sb, self->index, self->nr_entries - 1);
    224 	row = self->refresh(self);
    225 	ui_browser__set_color(self, HE_COLORSET_NORMAL);
    226 	SLsmg_fill_region(self->y + row, self->x,
    227 			  self->height - row, self->width, ' ');
    228 	pthread_mutex_unlock(&ui__lock);
    229 
    230 	return 0;
    231 }
    232 
    233 int ui_browser__run(struct ui_browser *self)
    234 {
    235 	struct newtExitStruct es;
    236 
    237 	if (ui_browser__refresh(self) < 0)
    238 		return -1;
    239 
    240 	while (1) {
    241 		off_t offset;
    242 
    243 		newtFormRun(self->form, &es);
    244 
    245 		if (es.reason != NEWT_EXIT_HOTKEY)
    246 			break;
    247 		switch (es.u.key) {
    248 		case NEWT_KEY_DOWN:
    249 			if (self->index == self->nr_entries - 1)
    250 				break;
    251 			++self->index;
    252 			if (self->index == self->top_idx + self->height) {
    253 				++self->top_idx;
    254 				self->seek(self, +1, SEEK_CUR);
    255 			}
    256 			break;
    257 		case NEWT_KEY_UP:
    258 			if (self->index == 0)
    259 				break;
    260 			--self->index;
    261 			if (self->index < self->top_idx) {
    262 				--self->top_idx;
    263 				self->seek(self, -1, SEEK_CUR);
    264 			}
    265 			break;
    266 		case NEWT_KEY_PGDN:
    267 		case ' ':
    268 			if (self->top_idx + self->height > self->nr_entries - 1)
    269 				break;
    270 
    271 			offset = self->height;
    272 			if (self->index + offset > self->nr_entries - 1)
    273 				offset = self->nr_entries - 1 - self->index;
    274 			self->index += offset;
    275 			self->top_idx += offset;
    276 			self->seek(self, +offset, SEEK_CUR);
    277 			break;
    278 		case NEWT_KEY_PGUP:
    279 			if (self->top_idx == 0)
    280 				break;
    281 
    282 			if (self->top_idx < self->height)
    283 				offset = self->top_idx;
    284 			else
    285 				offset = self->height;
    286 
    287 			self->index -= offset;
    288 			self->top_idx -= offset;
    289 			self->seek(self, -offset, SEEK_CUR);
    290 			break;
    291 		case NEWT_KEY_HOME:
    292 			ui_browser__reset_index(self);
    293 			break;
    294 		case NEWT_KEY_END:
    295 			offset = self->height - 1;
    296 			if (offset >= self->nr_entries)
    297 				offset = self->nr_entries - 1;
    298 
    299 			self->index = self->nr_entries - 1;
    300 			self->top_idx = self->index - offset;
    301 			self->seek(self, -offset, SEEK_END);
    302 			break;
    303 		default:
    304 			return es.u.key;
    305 		}
    306 		if (ui_browser__refresh(self) < 0)
    307 			return -1;
    308 	}
    309 	return -1;
    310 }
    311 
    312 unsigned int ui_browser__list_head_refresh(struct ui_browser *self)
    313 {
    314 	struct list_head *pos;
    315 	struct list_head *head = self->entries;
    316 	int row = 0;
    317 
    318 	if (self->top == NULL || self->top == self->entries)
    319                 self->top = head->next;
    320 
    321 	pos = self->top;
    322 
    323 	list_for_each_from(pos, head) {
    324 		ui_browser__gotorc(self, row, 0);
    325 		self->write(self, pos, row);
    326 		if (++row == self->height)
    327 			break;
    328 	}
    329 
    330 	return row;
    331 }
    332 
    333 static struct newtPercentTreeColors {
    334 	const char *topColorFg, *topColorBg;
    335 	const char *mediumColorFg, *mediumColorBg;
    336 	const char *normalColorFg, *normalColorBg;
    337 	const char *selColorFg, *selColorBg;
    338 	const char *codeColorFg, *codeColorBg;
    339 } defaultPercentTreeColors = {
    340 	"red",       "lightgray",
    341 	"green",     "lightgray",
    342 	"black",     "lightgray",
    343 	"lightgray", "magenta",
    344 	"blue",	     "lightgray",
    345 };
    346 
    347 void ui_browser__init(void)
    348 {
    349 	struct newtPercentTreeColors *c = &defaultPercentTreeColors;
    350 
    351 	sltt_set_color(HE_COLORSET_TOP, NULL, c->topColorFg, c->topColorBg);
    352 	sltt_set_color(HE_COLORSET_MEDIUM, NULL, c->mediumColorFg, c->mediumColorBg);
    353 	sltt_set_color(HE_COLORSET_NORMAL, NULL, c->normalColorFg, c->normalColorBg);
    354 	sltt_set_color(HE_COLORSET_SELECTED, NULL, c->selColorFg, c->selColorBg);
    355 	sltt_set_color(HE_COLORSET_CODE, NULL, c->codeColorFg, c->codeColorBg);
    356 }
    357