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