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