Commit 0eee7621 authored by yoann's avatar yoann
Browse files

* modules/gui/ncurses.c: support for tree playlist in ncurses interface

  use 'v' to toggle view
parent 16faa457
......@@ -75,6 +75,12 @@ static void Eject ( intf_thread_t * );
static int HandleKey ( intf_thread_t *, int );
static void Redraw ( intf_thread_t *, time_t * );
static void PlaylistRebuild( intf_thread_t * );
static void PlaylistAddNode( intf_thread_t *, playlist_item_t *, int, char *);
static void PlaylistDestroy( intf_thread_t * );
static int PlaylistChanged( vlc_object_t *, const char *, vlc_value_t,
vlc_value_t, void * );
static void FindIndex ( intf_thread_t * );
static void SearchPlaylist ( intf_thread_t *, char * );
static void ManageSlider ( intf_thread_t * );
static void ReadDir ( intf_thread_t * );
......@@ -117,6 +123,11 @@ struct dir_entry_t
vlc_bool_t b_file;
char *psz_path;
};
struct pl_item_t
{
playlist_item_t *p_item;
char *psz_display;
};
struct intf_sys_t
{
playlist_t *p_playlist;
......@@ -135,7 +146,8 @@ struct intf_sys_t
int i_box_plidx; /* Playlist index */
int b_box_plidx_follow;
int i_box_bidx; /* browser index */
playlist_item_t *p_plnode; /* Playlist node */
int i_box_bidx; /* browser index */
int b_box_cleared;
......@@ -146,10 +158,15 @@ struct intf_sys_t
int i_before_search;
char *psz_open_chain;
char *psz_current_dir;
int i_dir_entries;
struct dir_entry_t **pp_dir_entries;
int i_current_view; /* playlist view */
struct pl_item_t **pp_plist;
int i_plist_entries;
vlc_bool_t b_need_update; /* for playlist view */
};
static void DrawBox( WINDOW *win, int y, int x, int h, int w, char *title );
......@@ -178,6 +195,7 @@ static int Open( vlc_object_t *p_this )
p_sys->b_box_plidx_follow = VLC_TRUE;
p_sys->b_box_cleared = VLC_FALSE;
p_sys->i_box_plidx = 0;
p_sys->p_plnode = NULL;
p_sys->i_box_bidx = 0;
p_sys->p_sub = msg_Subscribe( p_intf );
......@@ -203,6 +221,12 @@ static int Open( vlc_object_t *p_this )
val.i_int = -1;
var_Set( p_intf->p_vlc, "verbose", val );
/* Set defaul playlist view */
p_sys->i_current_view = VIEW_SIMPLE;
p_sys->pp_plist = NULL;
p_sys->i_plist_entries = 0;
p_sys->b_need_update = VLC_FALSE;
/* Initialize search chain */
p_sys->psz_search_chain = (char *)malloc( SEARCH_CHAIN_SIZE + 1 );
p_sys->psz_old_search = NULL;
......@@ -210,11 +234,11 @@ static int Open( vlc_object_t *p_this )
/* Initialize open chain */
p_sys->psz_open_chain = (char *)malloc( OPEN_CHAIN_SIZE + 1 );
/* Initialize browser options */
var_Create( p_intf, "browse-dir", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
var_Get( p_intf, "browse-dir", &val);
if( val.psz_string && *val.psz_string )
{
p_sys->psz_current_dir = strdup( val.psz_string);
......@@ -224,9 +248,9 @@ static int Open( vlc_object_t *p_this )
{
p_sys->psz_current_dir = strdup( p_intf->p_vlc->psz_homedir );
}
p_sys->i_dir_entries = 0;
p_sys->pp_dir_entries = NULL;
p_sys->pp_dir_entries = NULL;
ReadDir( p_intf );
return VLC_SUCCESS;
......@@ -241,6 +265,13 @@ static void Close( vlc_object_t *p_this )
intf_sys_t *p_sys = p_intf->p_sys;
int i;
var_DelCallback( p_sys->p_playlist, "intf-change", PlaylistChanged,
p_intf );
var_DelCallback( p_sys->p_playlist, "item-append", PlaylistChanged,
p_intf );
PlaylistDestroy( p_intf );
for( i = 0; i < p_sys->i_dir_entries; i++ )
{
struct dir_entry_t *p_dir_entry = p_sys->pp_dir_entries[i];
......@@ -249,7 +280,7 @@ static void Close( vlc_object_t *p_this )
if( p_dir_entry ) free( p_dir_entry );
}
p_sys->pp_dir_entries = NULL;
if( p_sys->psz_current_dir ) free( p_sys->psz_current_dir );
if( p_sys->psz_search_chain ) free( p_sys->psz_search_chain );
if( p_sys->psz_old_search ) free( p_sys->psz_old_search );
......@@ -295,7 +326,15 @@ static void Run( intf_thread_t *p_intf )
/* Update the input */
if( p_sys->p_playlist == NULL )
{
p_sys->p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE );
p_sys->p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
FIND_ANYWHERE );
if( p_sys->p_playlist )
{
var_AddCallback( p_sys->p_playlist, "intf-change",
PlaylistChanged, p_intf );
var_AddCallback( p_sys->p_playlist, "item-append",
PlaylistChanged, p_intf );
}
}
if( p_sys->p_playlist )
{
......@@ -323,7 +362,7 @@ static void Run( intf_thread_t *p_intf )
if( p_sys->b_box_plidx_follow && p_sys->p_playlist->i_index >= 0 )
{
p_sys->i_box_plidx = p_sys->p_playlist->i_index;
FindIndex( p_intf );
}
while( ( i_key = getch()) != -1 )
......@@ -331,7 +370,7 @@ static void Run( intf_thread_t *p_intf )
/*
* HandleKey returns 1 if the screen needs to be redrawn
*/
if ( HandleKey( p_intf, i_key ) )
if( HandleKey( p_intf, i_key ) )
{
Redraw( p_intf, &t_last_refresh );
}
......@@ -347,9 +386,9 @@ static void Run( intf_thread_t *p_intf )
/*
* redraw the screen every second
*/
if ( (time(0) - t_last_refresh) >= 1 )
if( (time(0) - t_last_refresh) >= 1 )
{
ManageSlider ( p_intf );
ManageSlider( p_intf );
Redraw( p_intf, &t_last_refresh );
}
}
......@@ -394,6 +433,23 @@ static int HandleKey( intf_thread_t *p_intf, int i_key )
playlist_Sort( p_sys->p_playlist, SORT_TITLE, ORDER_REVERSE );
return 1;
/* Playlist view */
case 'v':
switch( p_sys->i_current_view )
{
case VIEW_SIMPLE:
p_sys->i_current_view = VIEW_CATEGORY;
break;
case VIEW_CATEGORY:
p_sys->i_current_view = VIEW_ALL;
break;
default:
p_sys->i_current_view = VIEW_SIMPLE;
}
PlaylistRebuild( p_intf );
FindIndex( p_intf );
return 1;
/* Playlist navigation */
case KEY_HOME:
p_sys->i_box_plidx = 0;
......@@ -430,7 +486,27 @@ static int HandleKey( intf_thread_t *p_intf, int i_key )
case KEY_ENTER:
case 0x0d:
playlist_Goto( p_sys->p_playlist, p_sys->i_box_plidx );
if( p_sys->i_current_view == VIEW_ALL )
{
playlist_Goto( p_sys->p_playlist, p_sys->i_box_plidx );
}
else
{
if( p_sys->pp_plist[p_sys->i_box_plidx]->p_item->i_children
== -1 )
{
playlist_Control( p_sys->p_playlist, PLAYLIST_ITEMPLAY,
p_sys->pp_plist[p_sys->i_box_plidx]->p_item );
}
else
{
playlist_Control( p_sys->p_playlist, PLAYLIST_VIEWPLAY,
p_sys->i_current_view,
p_sys->pp_plist[p_sys->i_box_plidx]->p_item,
NULL );
}
}
p_sys->b_box_plidx_follow = VLC_TRUE;
break;
default:
b_ret = VLC_FALSE;
......@@ -439,12 +515,26 @@ static int HandleKey( intf_thread_t *p_intf, int i_key )
if( b_ret )
{
if( p_sys->i_box_plidx >= p_sys->p_playlist->i_size ) p_sys->i_box_plidx = p_sys->p_playlist->i_size - 1;
int i_max = p_sys->i_plist_entries;
if( p_sys->i_current_view == VIEW_ALL )
i_max = p_sys->p_playlist->i_size;
if( p_sys->i_box_plidx >= i_max ) p_sys->i_box_plidx = i_max - 1;
if( p_sys->i_box_plidx < 0 ) p_sys->i_box_plidx = 0;
if( p_sys->i_box_plidx == p_sys->p_playlist->i_index )
p_sys->b_box_plidx_follow = VLC_TRUE;
if( p_sys->i_current_view == VIEW_ALL )
{
if( p_sys->i_box_plidx == p_sys->p_playlist->i_index )
p_sys->b_box_plidx_follow = VLC_TRUE;
else
p_sys->b_box_plidx_follow = VLC_FALSE;
}
else
p_sys->b_box_plidx_follow = VLC_FALSE;
{
if( p_sys->pp_plist[p_sys->i_box_plidx]->p_item ==
p_sys->p_playlist->status.p_item )
p_sys->b_box_plidx_follow = VLC_TRUE;
else
p_sys->b_box_plidx_follow = VLC_FALSE;
}
return 1;
}
}
......@@ -495,7 +585,7 @@ static int HandleKey( intf_thread_t *p_intf, int i_key )
char *psz_uri = (char *)malloc( sizeof(char)*i_size_entry);
sprintf( psz_uri, "%s/%s", p_sys->psz_current_dir, p_sys->pp_dir_entries[p_sys->i_box_bidx]->psz_path );
p_sys->psz_current_dir = strdup( psz_uri );
ReadDir( p_intf );
free( psz_uri );
......@@ -552,21 +642,21 @@ static int HandleKey( intf_thread_t *p_intf, int i_key )
{
case KEY_HOME:
p_sys->f_slider = 0;
ManageSlider ( p_intf );
ManageSlider( p_intf );
return 1;
case KEY_END:
p_sys->f_slider = 99.9;
ManageSlider ( p_intf );
ManageSlider( p_intf );
return 1;
case KEY_UP:
p_sys->f_slider += 5.0;
if( p_sys->f_slider >= 99.0 ) p_sys->f_slider = 99.0;
ManageSlider ( p_intf );
ManageSlider( p_intf );
return 1;
case KEY_DOWN:
p_sys->f_slider -= 5.0;
if( p_sys->f_slider < 0.0 ) p_sys->f_slider = 0.0;
ManageSlider ( p_intf );
ManageSlider( p_intf );
return 1;
default:
......@@ -734,13 +824,13 @@ static int HandleKey( intf_thread_t *p_intf, int i_key )
case KEY_RIGHT:
p_sys->f_slider += 1.0;
if( p_sys->f_slider > 99.9 ) p_sys->f_slider = 99.9;
ManageSlider ( p_intf );
ManageSlider( p_intf );
return 1;
case KEY_LEFT:
p_sys->f_slider -= 1.0;
if( p_sys->f_slider < 0.0 ) p_sys->f_slider = 0.0;
ManageSlider ( p_intf );
ManageSlider( p_intf );
return 1;
/* Common control */
......@@ -845,7 +935,7 @@ static int HandleKey( intf_thread_t *p_intf, int i_key )
}
}
static void ManageSlider ( intf_thread_t *p_intf )
static void ManageSlider( intf_thread_t *p_intf )
{
intf_sys_t *p_sys = p_intf->p_sys;
input_thread_t *p_input = p_sys->p_input;
......@@ -935,11 +1025,11 @@ static void mvnprintw( int y, int x, int w, const char *p_fmt, ... )
char *p_buf = NULL;
int i_len;
va_start ( vl_args, p_fmt );
vasprintf ( &p_buf, p_fmt, vl_args );
va_end ( vl_args );
va_start( vl_args, p_fmt );
vasprintf( &p_buf, p_fmt, vl_args );
va_end( vl_args );
if ( p_buf == NULL )
if( p_buf == NULL )
{
return;
}
......@@ -983,9 +1073,9 @@ static void MainBoxWrite( intf_thread_t *p_intf, int l, int x, const char *p_fmt
return;
}
va_start ( vl_args, p_fmt );
vasprintf ( &p_buf, p_fmt, vl_args );
va_end ( vl_args );
va_start( vl_args, p_fmt );
vasprintf( &p_buf, p_fmt, vl_args );
va_end( vl_args );
if( p_buf == NULL )
{
......@@ -995,7 +1085,7 @@ static void MainBoxWrite( intf_thread_t *p_intf, int l, int x, const char *p_fmt
mvnprintw( p_sys->i_box_y + l - p_sys->i_box_start, x, COLS - x - 1, "%s", p_buf );
}
static void Redraw ( intf_thread_t *p_intf, time_t *t_last_refresh )
static void Redraw( intf_thread_t *p_intf, time_t *t_last_refresh )
{
intf_sys_t *p_sys = p_intf->p_sys;
input_thread_t *p_input = p_sys->p_input;
......@@ -1006,9 +1096,9 @@ static void Redraw ( intf_thread_t *p_intf, time_t *t_last_refresh )
//clear();
/* Title */
attrset ( A_REVERSE );
attrset( A_REVERSE );
mvnprintw( y, 0, COLS, "VLC media player" " (ncurses interface) [ h for help ]" );
attroff ( A_REVERSE );
attroff( A_REVERSE );
y += 2;
/* Infos */
......@@ -1078,7 +1168,7 @@ static void Redraw ( intf_thread_t *p_intf, time_t *t_last_refresh )
}
else
{
y++;
y += 2;
}
}
else
......@@ -1177,12 +1267,12 @@ static void Redraw ( intf_thread_t *p_intf, time_t *t_last_refresh )
{
int i,j;
vlc_mutex_lock( &p_input->input.p_item->lock );
for ( i = 0; i < p_input->input.p_item->i_categories; i++ )
for( i = 0; i < p_input->input.p_item->i_categories; i++ )
{
info_category_t *p_category = p_input->input.p_item->pp_categories[i];
if( y >= y_end ) break;
MainBoxWrite( p_intf, l++, 1, " [%s]", p_category->psz_name );
for ( j = 0; j < p_category->i_infos; j++ )
for( j = 0; j < p_category->i_infos; j++ )
{
info_t *p_info = p_category->pp_infos[j];
if( y >= y_end ) break;
......@@ -1250,7 +1340,7 @@ static void Redraw ( intf_thread_t *p_intf, time_t *t_last_refresh )
}
else if( p_sys->i_box_type == BOX_BROWSE )
{
/* Playlist box */
/* Filebrowser box */
int i_start, i_stop;
int i_item;
DrawBox( p_sys->w, y++, 0, h, COLS, " Browse " );
......@@ -1295,7 +1385,7 @@ static void Redraw ( intf_thread_t *p_intf, time_t *t_last_refresh )
p_sys->pp_dir_entries[i_item]->psz_path );
if( b_selected )
{
attroff ( A_REVERSE );
attroff( A_REVERSE );
}
}
......@@ -1306,11 +1396,37 @@ static void Redraw ( intf_thread_t *p_intf, time_t *t_last_refresh )
{
/* Playlist box */
playlist_t *p_playlist = p_sys->p_playlist;
int i_start, i_stop;
int i_start, i_stop, i_max = p_sys->i_plist_entries;
int i_item;
DrawBox( p_sys->w, y++, 0, h, COLS, " Playlist " );
char *psz_title;
switch( p_sys->i_current_view )
{
case VIEW_ALL:
psz_title = strdup( " Playlist (All, unsorted) " );
i_max = p_playlist->i_size;
break;
case VIEW_CATEGORY:
psz_title = strdup( " Playlist (By category) " );
break;
default:
psz_title = strdup( " Playlist (Manually added) " );
}
DrawBox( p_sys->w, y++, 0, h, COLS, psz_title );
if( p_sys->i_current_view != VIEW_ALL &&
( p_sys->b_need_update || p_sys->pp_plist == NULL ) )
{
PlaylistRebuild( p_intf );
}
if( p_sys->b_box_plidx_follow &&
( p_sys->pp_plist[p_sys->i_box_plidx]->p_item !=
p_sys->p_playlist->status.p_item ) )
{
FindIndex( p_intf );
}
if( p_sys->i_box_plidx >= p_playlist->i_size ) p_sys->i_box_plidx = p_playlist->i_size - 1;
if( p_sys->i_box_plidx < 0 ) p_sys->i_box_plidx = 0;
if( p_sys->i_box_plidx < (h - 2)/2 )
......@@ -1318,25 +1434,28 @@ static void Redraw ( intf_thread_t *p_intf, time_t *t_last_refresh )
i_start = 0;
i_stop = h - 2;
}
else if( p_playlist->i_size - p_sys->i_box_plidx > (h - 2)/2 )
else if( i_max - p_sys->i_box_plidx > (h - 2)/2 )
{
i_start = p_sys->i_box_plidx - (h - 2)/2;
i_stop = i_start + h - 2;
}
else
{
i_stop = p_playlist->i_size;
i_start = p_playlist->i_size - (h - 2);
i_stop = i_max;
i_start = i_max - (h - 2);
}
if( i_start < 0 )
{
i_start = 0;
}
if( i_stop > p_playlist->i_size )
if( i_stop > i_max )
{
i_stop = p_playlist->i_size;
i_stop = i_max;
}
if( p_sys->i_current_view == VIEW_ALL )
{
for( i_item = i_start; i_item < i_stop; i_item++ )
{
vlc_bool_t b_selected = ( p_sys->i_box_plidx == i_item );
......@@ -1365,9 +1484,34 @@ static void Redraw ( intf_thread_t *p_intf, time_t *t_last_refresh )
}
if( b_selected )
{
attroff ( A_REVERSE );
attroff( A_REVERSE );
}
}
}
else
{
for( i_item = i_start; i_item < i_stop; i_item++ )
{
vlc_bool_t b_selected = ( p_sys->i_box_plidx == i_item );
int c = ( p_playlist->status.p_item ==
p_sys->pp_plist[i_item]->p_item ) ? '>' : ' ';
if( y >= y_end ) break;
if( b_selected )
{
attrset( A_REVERSE );
}
mvnprintw( y++, 1, COLS - 2, "%c%s", c,
p_sys->pp_plist[i_item]->psz_display );
if( b_selected )
{
attroff( A_REVERSE );
}
}
}
}
else
{
......@@ -1409,7 +1553,129 @@ static void Redraw ( intf_thread_t *p_intf, time_t *t_last_refresh )
*t_last_refresh = time( 0 );
}
static void Eject ( intf_thread_t *p_intf )
static void PlaylistRebuild( intf_thread_t *p_intf )
{
intf_sys_t *p_sys = p_intf->p_sys;
playlist_view_t *p_view;
playlist_t *p_playlist = p_sys->p_playlist;
if( p_playlist == NULL )
{
return;
}
vlc_mutex_lock( &p_playlist->object_lock );
p_view = playlist_ViewFind( p_playlist, p_intf->p_sys->i_current_view );
/* First clear the old one */
PlaylistDestroy( p_intf );
/* Build the new one */
PlaylistAddNode( p_intf, p_view->p_root, 0, "" );
p_sys->b_need_update = VLC_FALSE;
vlc_mutex_unlock( &p_playlist->object_lock );
}
static void PlaylistAddNode( intf_thread_t *p_intf, playlist_item_t *p_node,
int i, char *c )
{
intf_sys_t *p_sys = p_intf->p_sys;
playlist_item_t *p_child;
char *psz_tmp;
int k;
psz_tmp = (char *)malloc( strlen( c ) + 4 );
if( psz_tmp == NULL ) return;
for( k = 0; k < p_node->i_children; k++ )
{
struct pl_item_t *p_pl_item;
char *buff;
int i_size;
p_child = p_node->pp_children[k];
i_size = strlen( c ) + strlen( p_child->input.psz_name ) + 4;
buff = (char *)malloc( sizeof( char ) * i_size );
p_pl_item = (struct pl_item_t *)malloc( sizeof( struct pl_item_t ) );
if( p_pl_item == NULL || buff == NULL ) return;
if( strlen( c ) )
{
sprintf( buff, "%s%c-%s", c, k == p_node->i_children - 1 ?
'`' : '|', p_child->input.psz_name );
}
else
{
sprintf( buff, " %s", p_child->input.psz_name );
}
p_pl_item->psz_display = strdup( buff );
p_pl_item->p_item = p_child;
INSERT_ELEM( p_sys->pp_plist, p_sys->i_plist_entries,
p_sys->i_plist_entries, p_pl_item );
free( buff );
i++;
if( p_child->i_children > 0 )
{
sprintf( psz_tmp, "%s%c ", c,
k == p_node->i_children - 1 ? ' ' : '|' );
PlaylistAddNode( p_intf, p_child, i,
strlen( c ) ? psz_tmp : " " );
}
}
free( psz_tmp );
}
static int PlaylistChanged( vlc_object_t *p_this, const char *psz_variable,
vlc_value_t oval, vlc_value_t nval, void *param )
{
intf_thread_t *p_intf = (intf_thread_t *)param;
p_intf->p_sys->b_need_update = VLC_TRUE;
return VLC_SUCCESS;
}
static void FindIndex( intf_thread_t *p_intf )
{
intf_sys_t *p_sys = p_intf->p_sys;
int i;
if( p_sys->i_current_view == VIEW_ALL )
{
p_sys->i_box_plidx = p_sys->p_playlist->i_index;
}
else
{
for( i = 0; i < p_sys->i_plist_entries; i++ )
{
if( p_sys->pp_plist[i]->p_item ==
p_sys->p_playlist->status.p_item )
{
p_sys->i_box_plidx = i;
break;
}
}
}
}
static void PlaylistDestroy( intf_thread_t *p_intf )
{
intf_sys_t *p_sys = p_intf->p_sys;
int i;
for( i = 0; i < p_sys->i_plist_entries; i++ )
{
struct pl_item_t *p_pl_item = p_sys->pp_plist[i];
free( p_pl_item->psz_display );
REMOVE_ELEM( p_sys->pp_plist, p_sys->i_plist_entries, i );
free( p_pl_item );
}