1 | // SPDX-License-Identifier: GPL-2.0 |
---|---|
2 | #include "../util/string2.h" |
3 | #include "../util/config.h" |
4 | #include "libslang.h" |
5 | #include "ui.h" |
6 | #include "util.h" |
7 | #include <linux/compiler.h> |
8 | #include <linux/list.h> |
9 | #include <linux/rbtree.h> |
10 | #include <linux/string.h> |
11 | #include <stdlib.h> |
12 | #include <sys/ttydefaults.h> |
13 | #include "browser.h" |
14 | #include "helpline.h" |
15 | #include "keysyms.h" |
16 | #include "../util/color.h" |
17 | #include <linux/ctype.h> |
18 | #include <linux/zalloc.h> |
19 | |
20 | static int ui_browser__percent_color(struct ui_browser *browser, |
21 | double percent, bool current) |
22 | { |
23 | if (current && (!browser->use_navkeypressed || browser->navkeypressed)) |
24 | return HE_COLORSET_SELECTED; |
25 | if (percent >= MIN_RED) |
26 | return HE_COLORSET_TOP; |
27 | if (percent >= MIN_GREEN) |
28 | return HE_COLORSET_MEDIUM; |
29 | return HE_COLORSET_NORMAL; |
30 | } |
31 | |
32 | int ui_browser__set_color(struct ui_browser *browser, int color) |
33 | { |
34 | int ret = browser->current_color; |
35 | browser->current_color = color; |
36 | SLsmg_set_color(color); |
37 | return ret; |
38 | } |
39 | |
40 | void ui_browser__set_percent_color(struct ui_browser *browser, |
41 | double percent, bool current) |
42 | { |
43 | int color = ui_browser__percent_color(browser, percent, current); |
44 | ui_browser__set_color(browser, color); |
45 | } |
46 | |
47 | void ui_browser__gotorc_title(struct ui_browser *browser, int y, int x) |
48 | { |
49 | SLsmg_gotorc(browser->y + y, browser->x + x); |
50 | } |
51 | |
52 | void ui_browser__gotorc(struct ui_browser *browser, int y, int x) |
53 | { |
54 | SLsmg_gotorc(browser->y + y + browser->extra_title_lines, browser->x + x); |
55 | } |
56 | |
57 | void ui_browser__write_nstring(struct ui_browser *browser __maybe_unused, const char *msg, |
58 | unsigned int width) |
59 | { |
60 | SLsmg_write_nstring(msg, width); |
61 | } |
62 | |
63 | void ui_browser__vprintf(struct ui_browser *browser __maybe_unused, const char *fmt, va_list args) |
64 | { |
65 | SLsmg_vprintf(fmt, args); |
66 | } |
67 | |
68 | void ui_browser__printf(struct ui_browser *browser __maybe_unused, const char *fmt, ...) |
69 | { |
70 | va_list args; |
71 | |
72 | va_start(args, fmt); |
73 | ui_browser__vprintf(browser, fmt, args); |
74 | va_end(args); |
75 | } |
76 | |
77 | static struct list_head * |
78 | ui_browser__list_head_filter_entries(struct ui_browser *browser, |
79 | struct list_head *pos) |
80 | { |
81 | do { |
82 | if (!browser->filter || !browser->filter(browser, pos)) |
83 | return pos; |
84 | pos = pos->next; |
85 | } while (pos != browser->entries); |
86 | |
87 | return NULL; |
88 | } |
89 | |
90 | static struct list_head * |
91 | ui_browser__list_head_filter_prev_entries(struct ui_browser *browser, |
92 | struct list_head *pos) |
93 | { |
94 | do { |
95 | if (!browser->filter || !browser->filter(browser, pos)) |
96 | return pos; |
97 | pos = pos->prev; |
98 | } while (pos != browser->entries); |
99 | |
100 | return NULL; |
101 | } |
102 | |
103 | void ui_browser__list_head_seek(struct ui_browser *browser, off_t offset, int whence) |
104 | { |
105 | struct list_head *head = browser->entries; |
106 | struct list_head *pos; |
107 | |
108 | if (browser->nr_entries == 0) |
109 | return; |
110 | |
111 | switch (whence) { |
112 | case SEEK_SET: |
113 | pos = ui_browser__list_head_filter_entries(browser, pos: head->next); |
114 | break; |
115 | case SEEK_CUR: |
116 | pos = browser->top; |
117 | break; |
118 | case SEEK_END: |
119 | pos = ui_browser__list_head_filter_prev_entries(browser, pos: head->prev); |
120 | break; |
121 | default: |
122 | return; |
123 | } |
124 | |
125 | assert(pos != NULL); |
126 | |
127 | if (offset > 0) { |
128 | while (offset-- != 0) |
129 | pos = ui_browser__list_head_filter_entries(browser, pos: pos->next); |
130 | } else { |
131 | while (offset++ != 0) |
132 | pos = ui_browser__list_head_filter_prev_entries(browser, pos: pos->prev); |
133 | } |
134 | |
135 | browser->top = pos; |
136 | } |
137 | |
138 | void ui_browser__rb_tree_seek(struct ui_browser *browser, off_t offset, int whence) |
139 | { |
140 | struct rb_root *root = browser->entries; |
141 | struct rb_node *nd; |
142 | |
143 | switch (whence) { |
144 | case SEEK_SET: |
145 | nd = rb_first(root); |
146 | break; |
147 | case SEEK_CUR: |
148 | nd = browser->top; |
149 | break; |
150 | case SEEK_END: |
151 | nd = rb_last(root); |
152 | break; |
153 | default: |
154 | return; |
155 | } |
156 | |
157 | if (offset > 0) { |
158 | while (offset-- != 0) |
159 | nd = rb_next(nd); |
160 | } else { |
161 | while (offset++ != 0) |
162 | nd = rb_prev(nd); |
163 | } |
164 | |
165 | browser->top = nd; |
166 | } |
167 | |
168 | unsigned int ui_browser__rb_tree_refresh(struct ui_browser *browser) |
169 | { |
170 | struct rb_node *nd; |
171 | int row = 0; |
172 | |
173 | if (browser->top == NULL) |
174 | browser->top = rb_first(browser->entries); |
175 | |
176 | nd = browser->top; |
177 | |
178 | while (nd != NULL) { |
179 | ui_browser__gotorc(browser, y: row, x: 0); |
180 | browser->write(browser, nd, row); |
181 | if (++row == browser->rows) |
182 | break; |
183 | nd = rb_next(nd); |
184 | } |
185 | |
186 | return row; |
187 | } |
188 | |
189 | bool ui_browser__is_current_entry(struct ui_browser *browser, unsigned row) |
190 | { |
191 | return browser->top_idx + row == browser->index; |
192 | } |
193 | |
194 | void ui_browser__refresh_dimensions(struct ui_browser *browser) |
195 | { |
196 | browser->width = SLtt_Screen_Cols - 1; |
197 | browser->height = browser->rows = SLtt_Screen_Rows - 2; |
198 | browser->rows -= browser->extra_title_lines; |
199 | browser->y = 1; |
200 | browser->x = 0; |
201 | } |
202 | |
203 | void ui_browser__handle_resize(struct ui_browser *browser) |
204 | { |
205 | ui__refresh_dimensions(force: false); |
206 | ui_browser__show(browser, title: browser->title, helpline: ui_helpline__current); |
207 | ui_browser__refresh(browser); |
208 | } |
209 | |
210 | int ui_browser__warning(struct ui_browser *browser, int timeout, |
211 | const char *format, ...) |
212 | { |
213 | va_list args; |
214 | char *text; |
215 | int key = 0, err; |
216 | |
217 | va_start(args, format); |
218 | err = vasprintf(&text, format, args); |
219 | va_end(args); |
220 | |
221 | if (err < 0) { |
222 | va_start(args, format); |
223 | ui_helpline__vpush(fmt: format, ap: args); |
224 | va_end(args); |
225 | } else { |
226 | while ((key = ui__question_window(title: "Warning!", text, |
227 | exit_msg: "Press any key...", |
228 | delay_secs: timeout)) == K_RESIZE) |
229 | ui_browser__handle_resize(browser); |
230 | free(text); |
231 | } |
232 | |
233 | return key; |
234 | } |
235 | |
236 | int ui_browser__help_window(struct ui_browser *browser, const char *text) |
237 | { |
238 | int key; |
239 | |
240 | while ((key = ui__help_window(text)) == K_RESIZE) |
241 | ui_browser__handle_resize(browser); |
242 | |
243 | return key; |
244 | } |
245 | |
246 | bool ui_browser__dialog_yesno(struct ui_browser *browser, const char *text) |
247 | { |
248 | int key; |
249 | |
250 | while ((key = ui__dialog_yesno(msg: text)) == K_RESIZE) |
251 | ui_browser__handle_resize(browser); |
252 | |
253 | return key == K_ENTER || toupper(key) == 'Y'; |
254 | } |
255 | |
256 | void ui_browser__reset_index(struct ui_browser *browser) |
257 | { |
258 | browser->index = browser->top_idx = 0; |
259 | browser->seek(browser, 0, SEEK_SET); |
260 | } |
261 | |
262 | void __ui_browser__show_title(struct ui_browser *browser, const char *title) |
263 | { |
264 | SLsmg_gotorc(0, 0); |
265 | ui_browser__set_color(browser, HE_COLORSET_ROOT); |
266 | ui_browser__write_nstring(browser, msg: title, width: browser->width + 1); |
267 | } |
268 | |
269 | void ui_browser__show_title(struct ui_browser *browser, const char *title) |
270 | { |
271 | mutex_lock(mtx: &ui__lock); |
272 | __ui_browser__show_title(browser, title); |
273 | mutex_unlock(mtx: &ui__lock); |
274 | } |
275 | |
276 | int ui_browser__show(struct ui_browser *browser, const char *title, |
277 | const char *helpline, ...) |
278 | { |
279 | int err; |
280 | va_list ap; |
281 | |
282 | if (browser->refresh_dimensions == NULL) |
283 | browser->refresh_dimensions = ui_browser__refresh_dimensions; |
284 | |
285 | browser->refresh_dimensions(browser); |
286 | |
287 | mutex_lock(mtx: &ui__lock); |
288 | __ui_browser__show_title(browser, title); |
289 | |
290 | browser->title = title; |
291 | zfree(&browser->helpline); |
292 | |
293 | va_start(ap, helpline); |
294 | err = vasprintf(&browser->helpline, helpline, ap); |
295 | va_end(ap); |
296 | if (err > 0) |
297 | ui_helpline__push(msg: browser->helpline); |
298 | mutex_unlock(mtx: &ui__lock); |
299 | return err ? 0 : -1; |
300 | } |
301 | |
302 | void ui_browser__hide(struct ui_browser *browser) |
303 | { |
304 | mutex_lock(mtx: &ui__lock); |
305 | ui_helpline__pop(); |
306 | zfree(&browser->helpline); |
307 | mutex_unlock(mtx: &ui__lock); |
308 | } |
309 | |
310 | static void ui_browser__scrollbar_set(struct ui_browser *browser) |
311 | { |
312 | int height = browser->height, h = 0, pct = 0, |
313 | col = browser->width, |
314 | row = 0; |
315 | |
316 | if (browser->nr_entries > 1) { |
317 | pct = ((browser->index * (browser->height - 1)) / |
318 | (browser->nr_entries - 1)); |
319 | } |
320 | |
321 | SLsmg_set_char_set(1); |
322 | |
323 | while (h < height) { |
324 | ui_browser__gotorc(browser, y: row++, x: col); |
325 | SLsmg_write_char(h == pct ? SLSMG_DIAMOND_CHAR : SLSMG_CKBRD_CHAR); |
326 | ++h; |
327 | } |
328 | |
329 | SLsmg_set_char_set(0); |
330 | } |
331 | |
332 | static int __ui_browser__refresh(struct ui_browser *browser) |
333 | { |
334 | int row; |
335 | int width = browser->width; |
336 | |
337 | row = browser->refresh(browser); |
338 | ui_browser__set_color(browser, HE_COLORSET_NORMAL); |
339 | |
340 | if (!browser->use_navkeypressed || browser->navkeypressed) |
341 | ui_browser__scrollbar_set(browser); |
342 | else |
343 | width += 1; |
344 | |
345 | SLsmg_fill_region(browser->y + row + browser->extra_title_lines, browser->x, |
346 | browser->rows - row, width, ' '); |
347 | |
348 | if (browser->nr_entries == 0 && browser->no_samples_msg) |
349 | __ui__info_window(NULL, text: browser->no_samples_msg, NULL); |
350 | return 0; |
351 | } |
352 | |
353 | int ui_browser__refresh(struct ui_browser *browser) |
354 | { |
355 | mutex_lock(mtx: &ui__lock); |
356 | __ui_browser__refresh(browser); |
357 | mutex_unlock(mtx: &ui__lock); |
358 | |
359 | return 0; |
360 | } |
361 | |
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 | |
382 | browser->top = NULL; |
383 | browser->seek(browser, browser->top_idx, SEEK_SET); |
384 | } |
385 | |
386 | int ui_browser__run(struct ui_browser *browser, int delay_secs) |
387 | { |
388 | int err, key; |
389 | |
390 | while (1) { |
391 | off_t offset; |
392 | |
393 | mutex_lock(mtx: &ui__lock); |
394 | err = __ui_browser__refresh(browser); |
395 | SLsmg_refresh(); |
396 | mutex_unlock(mtx: &ui__lock); |
397 | if (err < 0) |
398 | break; |
399 | |
400 | key = ui__getch(delay_secs); |
401 | |
402 | if (key == K_RESIZE) { |
403 | ui__refresh_dimensions(force: false); |
404 | browser->refresh_dimensions(browser); |
405 | __ui_browser__show_title(browser, title: browser->title); |
406 | ui_helpline__puts(msg: browser->helpline); |
407 | continue; |
408 | } |
409 | |
410 | if (browser->use_navkeypressed && !browser->navkeypressed) { |
411 | if (key == K_DOWN || key == K_UP || |
412 | (browser->columns && (key == K_LEFT || key == K_RIGHT)) || |
413 | key == K_PGDN || key == K_PGUP || |
414 | key == K_HOME || key == K_END || |
415 | key == ' ') { |
416 | browser->navkeypressed = true; |
417 | continue; |
418 | } else |
419 | return key; |
420 | } |
421 | |
422 | switch (key) { |
423 | case K_DOWN: |
424 | if (browser->index == browser->nr_entries - 1) |
425 | break; |
426 | ++browser->index; |
427 | if (browser->index == browser->top_idx + browser->rows) { |
428 | ++browser->top_idx; |
429 | browser->seek(browser, +1, SEEK_CUR); |
430 | } |
431 | break; |
432 | case K_UP: |
433 | if (browser->index == 0) |
434 | break; |
435 | --browser->index; |
436 | if (browser->index < browser->top_idx) { |
437 | --browser->top_idx; |
438 | browser->seek(browser, -1, SEEK_CUR); |
439 | } |
440 | break; |
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; |
453 | case K_PGDN: |
454 | case ' ': |
455 | if (browser->top_idx + browser->rows > browser->nr_entries - 1) |
456 | break; |
457 | |
458 | offset = browser->rows; |
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); |
464 | break; |
465 | case K_PGUP: |
466 | if (browser->top_idx == 0) |
467 | break; |
468 | |
469 | if (browser->top_idx < browser->rows) |
470 | offset = browser->top_idx; |
471 | else |
472 | offset = browser->rows; |
473 | |
474 | browser->index -= offset; |
475 | browser->top_idx -= offset; |
476 | browser->seek(browser, -offset, SEEK_CUR); |
477 | break; |
478 | case K_HOME: |
479 | ui_browser__reset_index(browser); |
480 | break; |
481 | case K_END: |
482 | offset = browser->rows - 1; |
483 | if (offset >= browser->nr_entries) |
484 | offset = browser->nr_entries - 1; |
485 | |
486 | browser->index = browser->nr_entries - 1; |
487 | browser->top_idx = browser->index - offset; |
488 | browser->seek(browser, -offset, SEEK_END); |
489 | break; |
490 | default: |
491 | out: |
492 | return key; |
493 | } |
494 | } |
495 | return -1; |
496 | } |
497 | |
498 | unsigned int ui_browser__list_head_refresh(struct ui_browser *browser) |
499 | { |
500 | struct list_head *pos; |
501 | struct list_head *head = browser->entries; |
502 | int row = 0; |
503 | |
504 | if (browser->top == NULL || browser->top == browser->entries) |
505 | browser->top = ui_browser__list_head_filter_entries(browser, pos: head->next); |
506 | |
507 | pos = browser->top; |
508 | |
509 | list_for_each_from(pos, head) { |
510 | if (!browser->filter || !browser->filter(browser, pos)) { |
511 | ui_browser__gotorc(browser, y: row, x: 0); |
512 | browser->write(browser, pos, row); |
513 | if (++row == browser->rows) |
514 | break; |
515 | } |
516 | } |
517 | |
518 | return row; |
519 | } |
520 | |
521 | static struct ui_browser_colorset { |
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", |
529 | .bg = "default", |
530 | }, |
531 | { |
532 | .colorset = HE_COLORSET_MEDIUM, |
533 | .name = "medium", |
534 | .fg = "green", |
535 | .bg = "default", |
536 | }, |
537 | { |
538 | .colorset = HE_COLORSET_NORMAL, |
539 | .name = "normal", |
540 | .fg = "default", |
541 | .bg = "default", |
542 | }, |
543 | { |
544 | .colorset = HE_COLORSET_SELECTED, |
545 | .name = "selected", |
546 | .fg = "black", |
547 | .bg = "yellow", |
548 | }, |
549 | { |
550 | .colorset = HE_COLORSET_JUMP_ARROWS, |
551 | .name = "jump_arrows", |
552 | .fg = "blue", |
553 | .bg = "default", |
554 | }, |
555 | { |
556 | .colorset = HE_COLORSET_ADDR, |
557 | .name = "addr", |
558 | .fg = "magenta", |
559 | .bg = "default", |
560 | }, |
561 | { |
562 | .colorset = HE_COLORSET_ROOT, |
563 | .name = "root", |
564 | .fg = "white", |
565 | .bg = "blue", |
566 | }, |
567 | { |
568 | .name = NULL, |
569 | } |
570 | }; |
571 | |
572 | |
573 | static int ui_browser__color_config(const char *var, const char *value, |
574 | void *data __maybe_unused) |
575 | { |
576 | char *fg = NULL, *bg; |
577 | int i; |
578 | |
579 | /* same dir for all commands */ |
580 | if (!strstarts(str: var, prefix: "colors.") != 0) |
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'; |
598 | bg = skip_spaces(bg + 1); |
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 | |
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: |
615 | browser->top = (char **)browser->top + offset; |
616 | break; |
617 | case SEEK_END: |
618 | browser->top = (char **)browser->entries + browser->nr_entries - 1 + offset; |
619 | break; |
620 | default: |
621 | return; |
622 | } |
623 | assert((char **)browser->top < (char **)browser->entries + browser->nr_entries); |
624 | assert((char **)browser->top >= (char **)browser->entries); |
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; |
636 | while (idx < browser->nr_entries && |
637 | row < (unsigned)SLtt_Screen_Rows - 1) { |
638 | assert(pos < (char **)browser->entries + browser->nr_entries); |
639 | if (!browser->filter || !browser->filter(browser, *pos)) { |
640 | ui_browser__gotorc(browser, y: row, x: 0); |
641 | browser->write(browser, pos, row); |
642 | if (++row == browser->rows) |
643 | break; |
644 | } |
645 | |
646 | ++idx; |
647 | ++pos; |
648 | } |
649 | |
650 | return row; |
651 | } |
652 | |
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, y: start, x: column); |
658 | SLsmg_draw_vline(end - start + 1); |
659 | SLsmg_set_char_set(0); |
660 | } |
661 | |
662 | void ui_browser__write_graph(struct ui_browser *browser __maybe_unused, |
663 | int graph) |
664 | { |
665 | SLsmg_set_char_set(1); |
666 | SLsmg_write_char(graph); |
667 | SLsmg_set_char_set(0); |
668 | } |
669 | |
670 | static void __ui_browser__line_arrow_up(struct ui_browser *browser, |
671 | unsigned int column, |
672 | u64 start, u64 end) |
673 | { |
674 | unsigned int row, end_row; |
675 | |
676 | SLsmg_set_char_set(1); |
677 | |
678 | if (start < browser->top_idx + browser->rows) { |
679 | row = start - browser->top_idx; |
680 | ui_browser__gotorc(browser, y: row, x: column); |
681 | SLsmg_write_char(SLSMG_LLCORN_CHAR); |
682 | ui_browser__gotorc(browser, y: row, x: column + 1); |
683 | SLsmg_draw_hline(2); |
684 | |
685 | if (row-- == 0) |
686 | goto out; |
687 | } else |
688 | row = browser->rows - 1; |
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, y: end_row, x: column); |
696 | SLsmg_draw_vline(row - end_row + 1); |
697 | |
698 | ui_browser__gotorc(browser, y: end_row, x: column); |
699 | if (end >= browser->top_idx) { |
700 | SLsmg_write_char(SLSMG_ULCORN_CHAR); |
701 | ui_browser__gotorc(browser, y: end_row, x: column + 1); |
702 | SLsmg_write_char(SLSMG_HLINE_CHAR); |
703 | ui_browser__gotorc(browser, y: end_row, x: column + 2); |
704 | SLsmg_write_char(SLSMG_RARROW_CHAR); |
705 | } |
706 | out: |
707 | SLsmg_set_char_set(0); |
708 | } |
709 | |
710 | static void __ui_browser__line_arrow_down(struct ui_browser *browser, |
711 | unsigned int column, |
712 | u64 start, u64 end) |
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, y: row, x: column); |
721 | SLsmg_write_char(SLSMG_ULCORN_CHAR); |
722 | ui_browser__gotorc(browser, y: row, x: column + 1); |
723 | SLsmg_draw_hline(2); |
724 | |
725 | if (++row == 0) |
726 | goto out; |
727 | } else |
728 | row = 0; |
729 | |
730 | if (end >= browser->top_idx + browser->rows) |
731 | end_row = browser->rows - 1; |
732 | else |
733 | end_row = end - browser->top_idx; |
734 | |
735 | ui_browser__gotorc(browser, y: row, x: column); |
736 | SLsmg_draw_vline(end_row - row + 1); |
737 | |
738 | ui_browser__gotorc(browser, y: end_row, x: column); |
739 | if (end < browser->top_idx + browser->rows) { |
740 | SLsmg_write_char(SLSMG_LLCORN_CHAR); |
741 | ui_browser__gotorc(browser, y: end_row, x: column + 1); |
742 | SLsmg_write_char(SLSMG_HLINE_CHAR); |
743 | ui_browser__gotorc(browser, y: end_row, x: 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, |
751 | u64 start, u64 end) |
752 | { |
753 | if (start > end) |
754 | __ui_browser__line_arrow_up(browser, column, start, end); |
755 | else |
756 | __ui_browser__line_arrow_down(browser, column, start, end); |
757 | } |
758 | |
759 | void ui_browser__mark_fused(struct ui_browser *browser, unsigned int column, |
760 | unsigned int row, int diff, bool arrow_down) |
761 | { |
762 | int end_row; |
763 | |
764 | if (diff <= 0) |
765 | return; |
766 | |
767 | SLsmg_set_char_set(1); |
768 | |
769 | if (arrow_down) { |
770 | if (row + diff <= browser->top_idx) |
771 | return; |
772 | |
773 | end_row = row + diff - browser->top_idx; |
774 | ui_browser__gotorc(browser, y: end_row, x: column - 1); |
775 | SLsmg_write_char(SLSMG_LTEE_CHAR); |
776 | |
777 | while (--end_row >= 0 && end_row > (int)(row - browser->top_idx)) { |
778 | ui_browser__gotorc(browser, y: end_row, x: column - 1); |
779 | SLsmg_draw_vline(1); |
780 | } |
781 | |
782 | end_row = (int)(row - browser->top_idx); |
783 | if (end_row >= 0) { |
784 | ui_browser__gotorc(browser, y: end_row, x: column - 1); |
785 | SLsmg_write_char(SLSMG_ULCORN_CHAR); |
786 | ui_browser__gotorc(browser, y: end_row, x: column); |
787 | SLsmg_draw_hline(2); |
788 | } |
789 | } else { |
790 | if (row < browser->top_idx) |
791 | return; |
792 | |
793 | end_row = row - browser->top_idx; |
794 | ui_browser__gotorc(browser, y: end_row, x: column - 1); |
795 | SLsmg_write_char(SLSMG_LTEE_CHAR); |
796 | ui_browser__gotorc(browser, y: end_row, x: column); |
797 | SLsmg_draw_hline(2); |
798 | } |
799 | |
800 | SLsmg_set_char_set(0); |
801 | } |
802 | |
803 | void ui_browser__init(void) |
804 | { |
805 | int i = 0; |
806 | |
807 | perf_config(fn: ui_browser__color_config, NULL); |
808 | |
809 | while (ui_browser__colorsets[i].name) { |
810 | struct ui_browser_colorset *c = &ui_browser__colorsets[i++]; |
811 | SLtt_set_color(c->colorset, c->name, c->fg, c->bg); |
812 | } |
813 | } |
814 |
Definitions
- ui_browser__percent_color
- ui_browser__set_color
- ui_browser__set_percent_color
- ui_browser__gotorc_title
- ui_browser__gotorc
- ui_browser__write_nstring
- ui_browser__vprintf
- ui_browser__printf
- ui_browser__list_head_filter_entries
- ui_browser__list_head_filter_prev_entries
- ui_browser__list_head_seek
- ui_browser__rb_tree_seek
- ui_browser__rb_tree_refresh
- ui_browser__is_current_entry
- ui_browser__refresh_dimensions
- ui_browser__handle_resize
- ui_browser__warning
- ui_browser__help_window
- ui_browser__dialog_yesno
- ui_browser__reset_index
- __ui_browser__show_title
- ui_browser__show_title
- ui_browser__show
- ui_browser__hide
- ui_browser__scrollbar_set
- __ui_browser__refresh
- ui_browser__refresh
- ui_browser__update_nr_entries
- ui_browser__run
- ui_browser__list_head_refresh
- ui_browser_colorset
- ui_browser__colorsets
- ui_browser__color_config
- ui_browser__argv_seek
- ui_browser__argv_refresh
- __ui_browser__vline
- ui_browser__write_graph
- __ui_browser__line_arrow_up
- __ui_browser__line_arrow_down
- __ui_browser__line_arrow
- ui_browser__mark_fused
Improve your Profiling and Debugging skills
Find out more