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