2011-10-13 15:52:46 +04:00
# include "../util.h"
2011-10-18 21:50:51 +04:00
# include "../cache.h"
2011-10-13 15:52:46 +04:00
# include "../../perf.h"
2010-08-11 21:51:47 +04:00
# include "libslang.h"
2011-10-13 15:52:46 +04:00
# include <newt.h>
2011-02-09 16:38:43 +03:00
# include "ui.h"
2011-10-25 19:45:16 +04:00
# include "util.h"
2010-08-11 21:51:47 +04:00
# include <linux/compiler.h>
2010-08-07 00:35:02 +04:00
# include <linux/list.h>
# include <linux/rbtree.h>
# include <stdlib.h>
# include <sys/ttydefaults.h>
# include "browser.h"
2010-08-10 22:44:20 +04:00
# include "helpline.h"
2011-10-20 22:59:15 +04:00
# include "keysyms.h"
2010-08-07 00:35:02 +04:00
# include "../color.h"
2011-10-13 15:52:46 +04:00
2011-10-18 20:31:35 +04:00
static int ui_browser__percent_color ( struct ui_browser * browser ,
double percent , bool current )
2010-08-07 00:35:02 +04:00
{
2011-10-18 20:31:35 +04:00
if ( current & & ( ! browser - > use_navkeypressed | | browser - > navkeypressed ) )
2010-08-07 00:35:02 +04:00
return HE_COLORSET_SELECTED ;
if ( percent > = MIN_RED )
return HE_COLORSET_TOP ;
if ( percent > = MIN_GREEN )
return HE_COLORSET_MEDIUM ;
return HE_COLORSET_NORMAL ;
}
2010-08-11 21:51:47 +04:00
void ui_browser__set_color ( struct ui_browser * self __used , int color )
{
SLsmg_set_color ( color ) ;
}
void ui_browser__set_percent_color ( struct ui_browser * self ,
double percent , bool current )
{
2011-10-18 20:31:35 +04:00
int color = ui_browser__percent_color ( self , percent , current ) ;
2010-08-11 21:51:47 +04:00
ui_browser__set_color ( self , color ) ;
}
void ui_browser__gotorc ( struct ui_browser * self , int y , int x )
{
SLsmg_gotorc ( self - > y + y , self - > x + x ) ;
}
2011-10-14 19:27:54 +04:00
static struct list_head *
ui_browser__list_head_filter_entries ( struct ui_browser * browser ,
struct list_head * pos )
{
do {
if ( ! browser - > filter | | ! browser - > filter ( browser , pos ) )
return pos ;
pos = pos - > next ;
} while ( pos ! = browser - > entries ) ;
return NULL ;
}
static struct list_head *
ui_browser__list_head_filter_prev_entries ( struct ui_browser * browser ,
struct list_head * pos )
{
do {
if ( ! browser - > filter | | ! browser - > filter ( browser , pos ) )
return pos ;
pos = pos - > prev ;
} while ( pos ! = browser - > entries ) ;
return NULL ;
}
2010-08-07 00:35:02 +04:00
void ui_browser__list_head_seek ( struct ui_browser * self , off_t offset , int whence )
{
struct list_head * head = self - > entries ;
struct list_head * pos ;
2011-10-14 19:27:54 +04:00
if ( self - > nr_entries = = 0 )
return ;
2010-08-07 00:35:02 +04:00
switch ( whence ) {
case SEEK_SET :
2011-10-14 19:27:54 +04:00
pos = ui_browser__list_head_filter_entries ( self , head - > next ) ;
2010-08-07 00:35:02 +04:00
break ;
case SEEK_CUR :
2010-08-07 20:56:04 +04:00
pos = self - > top ;
2010-08-07 00:35:02 +04:00
break ;
case SEEK_END :
2011-10-14 19:27:54 +04:00
pos = ui_browser__list_head_filter_prev_entries ( self , head - > prev ) ;
2010-08-07 00:35:02 +04:00
break ;
default :
return ;
}
2011-10-14 19:27:54 +04:00
assert ( pos ! = NULL ) ;
2010-08-07 00:35:02 +04:00
if ( offset > 0 ) {
while ( offset - - ! = 0 )
2011-10-14 19:27:54 +04:00
pos = ui_browser__list_head_filter_entries ( self , pos - > next ) ;
2010-08-07 00:35:02 +04:00
} else {
while ( offset + + ! = 0 )
2011-10-14 19:27:54 +04:00
pos = ui_browser__list_head_filter_prev_entries ( self , pos - > prev ) ;
2010-08-07 00:35:02 +04:00
}
2010-08-07 20:56:04 +04:00
self - > top = pos ;
2010-08-07 00:35:02 +04:00
}
void ui_browser__rb_tree_seek ( struct ui_browser * self , off_t offset , int whence )
{
struct rb_root * root = self - > entries ;
struct rb_node * nd ;
switch ( whence ) {
case SEEK_SET :
nd = rb_first ( root ) ;
break ;
case SEEK_CUR :
2010-08-07 20:56:04 +04:00
nd = self - > top ;
2010-08-07 00:35:02 +04:00
break ;
case SEEK_END :
nd = rb_last ( root ) ;
break ;
default :
return ;
}
if ( offset > 0 ) {
while ( offset - - ! = 0 )
nd = rb_next ( nd ) ;
} else {
while ( offset + + ! = 0 )
nd = rb_prev ( nd ) ;
}
2010-08-07 20:56:04 +04:00
self - > top = nd ;
2010-08-07 00:35:02 +04:00
}
unsigned int ui_browser__rb_tree_refresh ( struct ui_browser * self )
{
struct rb_node * nd ;
int row = 0 ;
2010-08-07 20:56:04 +04:00
if ( self - > top = = NULL )
self - > top = rb_first ( self - > entries ) ;
2010-08-07 00:35:02 +04:00
2010-08-07 20:56:04 +04:00
nd = self - > top ;
2010-08-07 00:35:02 +04:00
while ( nd ! = NULL ) {
2010-08-11 21:51:47 +04:00
ui_browser__gotorc ( self , row , 0 ) ;
2010-08-07 00:35:02 +04:00
self - > write ( self , nd , row ) ;
if ( + + row = = self - > height )
break ;
nd = rb_next ( nd ) ;
}
return row ;
}
bool ui_browser__is_current_entry ( struct ui_browser * self , unsigned row )
{
2010-08-07 20:56:04 +04:00
return self - > top_idx + row = = self - > index ;
2010-08-07 00:35:02 +04:00
}
void ui_browser__refresh_dimensions ( struct ui_browser * self )
{
2011-10-13 15:52:46 +04:00
self - > width = SLtt_Screen_Cols - 1 ;
self - > height = SLtt_Screen_Rows - 2 ;
2010-09-13 17:25:04 +04:00
self - > y = 1 ;
self - > x = 0 ;
2010-08-07 00:35:02 +04:00
}
void ui_browser__reset_index ( struct ui_browser * self )
{
2010-08-07 20:56:04 +04:00
self - > index = self - > top_idx = 0 ;
2010-08-07 00:35:02 +04:00
self - > seek ( self , 0 , SEEK_SET ) ;
}
2011-02-25 17:33:31 +03:00
void __ui_browser__show_title ( struct ui_browser * browser , const char * title )
{
SLsmg_gotorc ( 0 , 0 ) ;
ui_browser__set_color ( browser , NEWT_COLORSET_ROOT ) ;
2011-10-13 15:52:46 +04:00
slsmg_write_nstring ( title , browser - > width + 1 ) ;
2011-02-25 17:33:31 +03:00
}
void ui_browser__show_title ( struct ui_browser * browser , const char * title )
{
pthread_mutex_lock ( & ui__lock ) ;
__ui_browser__show_title ( browser , title ) ;
pthread_mutex_unlock ( & ui__lock ) ;
}
2010-08-10 22:44:20 +04:00
int ui_browser__show ( struct ui_browser * self , const char * title ,
const char * helpline , . . . )
2010-08-07 00:35:02 +04:00
{
2011-10-13 15:52:46 +04:00
int err ;
2010-08-10 22:44:20 +04:00
va_list ap ;
2010-08-07 00:35:02 +04:00
ui_browser__refresh_dimensions ( self ) ;
2011-02-09 16:38:43 +03:00
pthread_mutex_lock ( & ui__lock ) ;
2011-02-25 17:33:31 +03:00
__ui_browser__show_title ( self , title ) ;
2010-09-13 17:25:04 +04:00
2011-10-13 15:52:46 +04:00
self - > title = title ;
free ( self - > helpline ) ;
self - > helpline = NULL ;
2010-08-10 22:44:20 +04:00
va_start ( ap , helpline ) ;
2011-10-13 15:52:46 +04:00
err = vasprintf ( & self - > helpline , helpline , ap ) ;
2010-08-10 22:44:20 +04:00
va_end ( ap ) ;
2011-10-13 15:52:46 +04:00
if ( err > 0 )
ui_helpline__push ( self - > helpline ) ;
2011-02-09 16:38:43 +03:00
pthread_mutex_unlock ( & ui__lock ) ;
2011-10-13 15:52:46 +04:00
return err ? 0 : - 1 ;
2010-08-07 00:35:02 +04:00
}
2011-10-13 15:52:46 +04:00
void ui_browser__hide ( struct ui_browser * browser __used )
2010-08-10 22:44:20 +04:00
{
2011-02-09 16:38:43 +03:00
pthread_mutex_lock ( & ui__lock ) ;
2010-08-10 22:44:20 +04:00
ui_helpline__pop ( ) ;
2011-02-09 16:38:43 +03:00
pthread_mutex_unlock ( & ui__lock ) ;
2010-08-10 22:44:20 +04:00
}
2011-10-13 15:52:46 +04:00
static void ui_browser__scrollbar_set ( struct ui_browser * browser )
{
int height = browser - > height , h = 0 , pct = 0 ,
col = browser - > width ,
row = browser - > y - 1 ;
if ( browser - > nr_entries > 1 ) {
pct = ( ( browser - > index * ( browser - > height - 1 ) ) /
( browser - > nr_entries - 1 ) ) ;
}
while ( h < height ) {
ui_browser__gotorc ( browser , row + + , col ) ;
SLsmg_set_char_set ( 1 ) ;
SLsmg_write_char ( h = = pct ? SLSMG_DIAMOND_CHAR : SLSMG_BOARD_CHAR ) ;
SLsmg_set_char_set ( 0 ) ;
+ + h ;
}
}
static int __ui_browser__refresh ( struct ui_browser * browser )
2010-08-07 00:35:02 +04:00
{
int row ;
2011-10-18 20:31:35 +04:00
int width = browser - > width ;
2010-08-07 00:35:02 +04:00
2011-10-13 15:52:46 +04:00
row = browser - > refresh ( browser ) ;
ui_browser__set_color ( browser , HE_COLORSET_NORMAL ) ;
2011-10-18 20:31:35 +04:00
if ( ! browser - > use_navkeypressed | | browser - > navkeypressed )
ui_browser__scrollbar_set ( browser ) ;
else
width + = 1 ;
2011-10-13 15:52:46 +04:00
SLsmg_fill_region ( browser - > y + row , browser - > x ,
2011-10-18 20:31:35 +04:00
browser - > height - row , width , ' ' ) ;
2011-10-13 15:52:46 +04:00
return 0 ;
}
int ui_browser__refresh ( struct ui_browser * browser )
{
2011-02-09 16:38:43 +03:00
pthread_mutex_lock ( & ui__lock ) ;
2011-10-13 15:52:46 +04:00
__ui_browser__refresh ( browser ) ;
2011-02-09 16:38:43 +03:00
pthread_mutex_unlock ( & ui__lock ) ;
2010-08-07 00:35:02 +04:00
return 0 ;
}
2011-10-11 23:15:39 +04:00
/*
* Here we ' re updating nr_entries _after_ we started browsing , i . e . we have to
* forget about any reference to any entry in the underlying data structure ,
* that is why we do a SEEK_SET . Think about ' perf top ' in the hists browser
* after an output_resort and hist decay .
*/
void ui_browser__update_nr_entries ( struct ui_browser * browser , u32 nr_entries )
{
off_t offset = nr_entries - browser - > nr_entries ;
browser - > nr_entries = nr_entries ;
if ( offset < 0 ) {
if ( browser - > top_idx < ( u64 ) - offset )
offset = - browser - > top_idx ;
browser - > index + = offset ;
browser - > top_idx + = offset ;
}
2011-10-14 16:31:53 +04:00
browser - > top = NULL ;
2011-10-11 23:15:39 +04:00
browser - > seek ( browser , browser - > top_idx , SEEK_SET ) ;
}
2011-10-13 15:52:46 +04:00
int ui_browser__run ( struct ui_browser * self , int delay_secs )
2010-08-07 00:35:02 +04:00
{
2011-10-13 15:52:46 +04:00
int err , key ;
2010-08-11 17:07:43 +04:00
2010-08-07 00:35:02 +04:00
while ( 1 ) {
off_t offset ;
2011-10-13 15:52:46 +04:00
pthread_mutex_lock ( & ui__lock ) ;
err = __ui_browser__refresh ( self ) ;
SLsmg_refresh ( ) ;
pthread_mutex_unlock ( & ui__lock ) ;
if ( err < 0 )
break ;
2011-10-20 22:59:15 +04:00
key = ui__getch ( delay_secs ) ;
2011-10-13 15:52:46 +04:00
2011-10-20 22:59:15 +04:00
if ( key = = K_RESIZE ) {
2011-10-25 19:45:16 +04:00
ui__refresh_dimensions ( false ) ;
2011-10-13 15:52:46 +04:00
ui_browser__refresh_dimensions ( self ) ;
__ui_browser__show_title ( self , self - > title ) ;
ui_helpline__puts ( self - > helpline ) ;
continue ;
}
2011-10-18 20:31:35 +04:00
if ( self - > use_navkeypressed & & ! self - > navkeypressed ) {
2011-10-20 22:59:15 +04:00
if ( key = = K_DOWN | | key = = K_UP | |
key = = K_PGDN | | key = = K_PGUP | |
key = = K_HOME | | key = = K_END | |
2011-10-18 20:31:35 +04:00
key = = ' ' ) {
self - > navkeypressed = true ;
continue ;
} else
return key ;
}
2011-10-13 15:52:46 +04:00
switch ( key ) {
2011-10-20 22:59:15 +04:00
case K_DOWN :
2010-08-07 00:35:02 +04:00
if ( self - > index = = self - > nr_entries - 1 )
break ;
+ + self - > index ;
2010-08-07 20:56:04 +04:00
if ( self - > index = = self - > top_idx + self - > height ) {
+ + self - > top_idx ;
2010-08-07 00:35:02 +04:00
self - > seek ( self , + 1 , SEEK_CUR ) ;
}
break ;
2011-10-20 22:59:15 +04:00
case K_UP :
2010-08-07 00:35:02 +04:00
if ( self - > index = = 0 )
break ;
- - self - > index ;
2010-08-07 20:56:04 +04:00
if ( self - > index < self - > top_idx ) {
- - self - > top_idx ;
2010-08-07 00:35:02 +04:00
self - > seek ( self , - 1 , SEEK_CUR ) ;
}
break ;
2011-10-20 22:59:15 +04:00
case K_PGDN :
2010-08-07 00:35:02 +04:00
case ' ' :
2010-08-07 20:56:04 +04:00
if ( self - > top_idx + self - > height > self - > nr_entries - 1 )
2010-08-07 00:35:02 +04:00
break ;
offset = self - > height ;
if ( self - > index + offset > self - > nr_entries - 1 )
offset = self - > nr_entries - 1 - self - > index ;
self - > index + = offset ;
2010-08-07 20:56:04 +04:00
self - > top_idx + = offset ;
2010-08-07 00:35:02 +04:00
self - > seek ( self , + offset , SEEK_CUR ) ;
break ;
2011-10-20 22:59:15 +04:00
case K_PGUP :
2010-08-07 20:56:04 +04:00
if ( self - > top_idx = = 0 )
2010-08-07 00:35:02 +04:00
break ;
2010-08-07 20:56:04 +04:00
if ( self - > top_idx < self - > height )
offset = self - > top_idx ;
2010-08-07 00:35:02 +04:00
else
offset = self - > height ;
self - > index - = offset ;
2010-08-07 20:56:04 +04:00
self - > top_idx - = offset ;
2010-08-07 00:35:02 +04:00
self - > seek ( self , - offset , SEEK_CUR ) ;
break ;
2011-10-20 22:59:15 +04:00
case K_HOME :
2010-08-07 00:35:02 +04:00
ui_browser__reset_index ( self ) ;
break ;
2011-10-20 22:59:15 +04:00
case K_END :
2010-08-07 00:35:02 +04:00
offset = self - > height - 1 ;
if ( offset > = self - > nr_entries )
offset = self - > nr_entries - 1 ;
self - > index = self - > nr_entries - 1 ;
2010-08-07 20:56:04 +04:00
self - > top_idx = self - > index - offset ;
2010-08-07 00:35:02 +04:00
self - > seek ( self , - offset , SEEK_END ) ;
break ;
default :
2011-10-13 15:52:46 +04:00
return key ;
2010-08-07 00:35:02 +04:00
}
}
2010-08-11 17:07:43 +04:00
return - 1 ;
2010-08-07 00:35:02 +04:00
}
unsigned int ui_browser__list_head_refresh ( struct ui_browser * self )
{
struct list_head * pos ;
struct list_head * head = self - > entries ;
int row = 0 ;
2010-08-07 20:56:04 +04:00
if ( self - > top = = NULL | | self - > top = = self - > entries )
2011-10-14 19:27:54 +04:00
self - > top = ui_browser__list_head_filter_entries ( self , head - > next ) ;
2010-08-07 00:35:02 +04:00
2010-08-07 20:56:04 +04:00
pos = self - > top ;
2010-08-07 00:35:02 +04:00
list_for_each_from ( pos , head ) {
2011-10-14 19:27:54 +04:00
if ( ! self - > filter | | ! self - > filter ( self , pos ) ) {
ui_browser__gotorc ( self , row , 0 ) ;
self - > write ( self , pos , row ) ;
if ( + + row = = self - > height )
break ;
}
2010-08-07 00:35:02 +04:00
}
return row ;
}
2011-10-18 21:50:51 +04:00
static struct ui_browser__colorset {
const char * name , * fg , * bg ;
int colorset ;
} ui_browser__colorsets [ ] = {
{
. colorset = HE_COLORSET_TOP ,
. name = " top " ,
. fg = " red " ,
2011-10-19 06:30:32 +04:00
. bg = " default " ,
2011-10-18 21:50:51 +04:00
} ,
{
. colorset = HE_COLORSET_MEDIUM ,
. name = " medium " ,
. fg = " green " ,
2011-10-19 06:30:32 +04:00
. bg = " default " ,
2011-10-18 21:50:51 +04:00
} ,
{
. colorset = HE_COLORSET_NORMAL ,
. name = " normal " ,
2011-10-19 06:30:32 +04:00
. fg = " default " ,
. bg = " default " ,
2011-10-18 21:50:51 +04:00
} ,
{
. colorset = HE_COLORSET_SELECTED ,
. name = " selected " ,
. fg = " black " ,
. bg = " lightgray " ,
} ,
{
. colorset = HE_COLORSET_CODE ,
. name = " code " ,
. fg = " blue " ,
2011-10-19 06:30:32 +04:00
. bg = " default " ,
2011-10-18 21:50:51 +04:00
} ,
{
. name = NULL ,
}
2010-08-07 00:35:02 +04:00
} ;
2011-10-18 21:50:51 +04:00
static int ui_browser__color_config ( const char * var , const char * value ,
void * data __used )
{
char * fg = NULL , * bg ;
int i ;
/* same dir for all commands */
if ( prefixcmp ( var , " colors. " ) ! = 0 )
return 0 ;
for ( i = 0 ; ui_browser__colorsets [ i ] . name ! = NULL ; + + i ) {
const char * name = var + 7 ;
if ( strcmp ( ui_browser__colorsets [ i ] . name , name ) ! = 0 )
continue ;
fg = strdup ( value ) ;
if ( fg = = NULL )
break ;
bg = strchr ( fg , ' , ' ) ;
if ( bg = = NULL )
break ;
* bg = ' \0 ' ;
while ( isspace ( * + + bg ) ) ;
ui_browser__colorsets [ i ] . bg = bg ;
ui_browser__colorsets [ i ] . fg = fg ;
return 0 ;
}
free ( fg ) ;
return - 1 ;
}
2010-08-07 00:35:02 +04:00
void ui_browser__init ( void )
{
2011-10-18 21:50:51 +04:00
int i = 0 ;
2010-08-07 00:35:02 +04:00
2011-10-18 21:50:51 +04:00
perf_config ( ui_browser__color_config , NULL ) ;
while ( ui_browser__colorsets [ i ] . name ) {
struct ui_browser__colorset * c = & ui_browser__colorsets [ i + + ] ;
sltt_set_color ( c - > colorset , c - > name , c - > fg , c - > bg ) ;
}
2010-08-07 00:35:02 +04:00
}