root/tools/perf/ui/browser.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ui_browser__percent_color
  2. ui_browser__set_color
  3. ui_browser__set_percent_color
  4. ui_browser__gotorc_title
  5. ui_browser__gotorc
  6. ui_browser__write_nstring
  7. ui_browser__vprintf
  8. ui_browser__printf
  9. ui_browser__list_head_filter_entries
  10. ui_browser__list_head_filter_prev_entries
  11. ui_browser__list_head_seek
  12. ui_browser__rb_tree_seek
  13. ui_browser__rb_tree_refresh
  14. ui_browser__is_current_entry
  15. ui_browser__refresh_dimensions
  16. ui_browser__handle_resize
  17. ui_browser__warning
  18. ui_browser__help_window
  19. ui_browser__dialog_yesno
  20. ui_browser__reset_index
  21. __ui_browser__show_title
  22. ui_browser__show_title
  23. ui_browser__show
  24. ui_browser__hide
  25. ui_browser__scrollbar_set
  26. __ui_browser__refresh
  27. ui_browser__refresh
  28. ui_browser__update_nr_entries
  29. ui_browser__run
  30. ui_browser__list_head_refresh
  31. ui_browser__color_config
  32. ui_browser__argv_seek
  33. ui_browser__argv_refresh
  34. __ui_browser__vline
  35. ui_browser__write_graph
  36. __ui_browser__line_arrow_up
  37. __ui_browser__line_arrow_down
  38. __ui_browser__line_arrow
  39. ui_browser__mark_fused
  40. ui_browser__init

   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, 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, 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->next);
 130         } else {
 131                 while (offset++ != 0)
 132                         pos = ui_browser__list_head_filter_prev_entries(browser, 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, row, 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(false);
 206         ui_browser__show(browser, browser->title, 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(format, args);
 224                 va_end(args);
 225         } else {
 226                 while ((key = ui__question_window("Warning!", text,
 227                                                    "Press any key...",
 228                                                    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(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, title, browser->width + 1);
 267 }
 268 
 269 void ui_browser__show_title(struct ui_browser *browser, const char *title)
 270 {
 271         pthread_mutex_lock(&ui__lock);
 272         __ui_browser__show_title(browser, title);
 273         pthread_mutex_unlock(&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         pthread_mutex_lock(&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(browser->helpline);
 298         pthread_mutex_unlock(&ui__lock);
 299         return err ? 0 : -1;
 300 }
 301 
 302 void ui_browser__hide(struct ui_browser *browser)
 303 {
 304         pthread_mutex_lock(&ui__lock);
 305         ui_helpline__pop();
 306         zfree(&browser->helpline);
 307         pthread_mutex_unlock(&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, row++, 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, browser->no_samples_msg, NULL);
 350         return 0;
 351 }
 352 
 353 int ui_browser__refresh(struct ui_browser *browser)
 354 {
 355         pthread_mutex_lock(&ui__lock);
 356         __ui_browser__refresh(browser);
 357         pthread_mutex_unlock(&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                 pthread_mutex_lock(&ui__lock);
 394                 err = __ui_browser__refresh(browser);
 395                 SLsmg_refresh();
 396                 pthread_mutex_unlock(&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(false);
 404                         browser->refresh_dimensions(browser);
 405                         __ui_browser__show_title(browser, browser->title);
 406                         ui_helpline__puts(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, 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, row, 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(var, "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, row, 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, start, 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, row, column);
 681                 SLsmg_write_char(SLSMG_LLCORN_CHAR);
 682                 ui_browser__gotorc(browser, row, 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, 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 
 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, row, column);
 721                 SLsmg_write_char(SLSMG_ULCORN_CHAR);
 722                 ui_browser__gotorc(browser, row, 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, row, column);
 736         SLsmg_draw_vline(end_row - row + 1);
 737 
 738         ui_browser__gotorc(browser, end_row, column);
 739         if (end < browser->top_idx + browser->rows) {
 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,
 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, 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 
 788 void ui_browser__init(void)
 789 {
 790         int i = 0;
 791 
 792         perf_config(ui_browser__color_config, NULL);
 793 
 794         while (ui_browser__colorsets[i].name) {
 795                 struct ui_browser_colorset *c = &ui_browser__colorsets[i++];
 796                 sltt_set_color(c->colorset, c->name, c->fg, c->bg);
 797         }
 798 }

/* [<][>][^][v][top][bottom][index][help] */