Commit 1ed6cff4 authored by Sam Hocevar's avatar Sam Hocevar

* ./plugins/text/ncurses.c: ncurses interface improvements by Thomas Graf.

parent 5343b969
......@@ -2,7 +2,7 @@
* ncurses.c : NCurses plugin for vlc
*****************************************************************************
* Copyright (C) 2001 VideoLAN
* $Id: ncurses.c,v 1.14 2002/04/19 13:56:11 sam Exp $
* $Id: ncurses.c,v 1.15 2002/05/13 17:57:46 sam Exp $
*
* Authors: Samuel Hocevar <sam@zoy.org>
*
......@@ -28,6 +28,7 @@
#include <string.h>
#include <errno.h> /* ENOMEM */
#include <stdio.h>
#include <time.h>
#include <curses.h>
......@@ -37,6 +38,11 @@
#include "input_ext-intf.h"
#include "interface.h"
#include "intf_playlist.h"
#include "intf_eject.h"
#include "video.h"
#include "video_output.h"
/*****************************************************************************
* Local prototypes.
......@@ -46,6 +52,23 @@ static int intf_Open ( intf_thread_t *p_intf );
static void intf_Close ( intf_thread_t *p_intf );
static void intf_Run ( intf_thread_t *p_intf );
static void ncurses_Fullscreen ( void );
static void ncurses_Play ( void );
static void ncurses_Stop ( void );
static void ncurses_Next ( void );
static void ncurses_Eject ( void );
static void ncurses_Pause ( void );
static void ncurses_TitlePrev ( void );
static void ncurses_TitleNext ( void );
static void ncurses_ChapterPrev ( void );
static void ncurses_ChapterNext ( void );
static int ncurses_handleKey ( intf_thread_t *p_intf, int i_key );
static void ncurses_draw ( time_t *t_last_refresh,
intf_thread_t *p_intf );
static int ncurses_printFullLine ( const char *p_fmt, ... );
static void ncurses_manageSlider ( intf_thread_t *p_intf );
/*****************************************************************************
* Building configuration tree
*****************************************************************************/
......@@ -74,6 +97,9 @@ typedef struct intf_sys_s
/* special actions */
vlc_mutex_t change_lock; /* the change lock */
float f_slider_state;
float f_slider_state_old;
} intf_sys_t;
/*****************************************************************************
......@@ -100,6 +126,8 @@ static int intf_Open( intf_thread_t *p_intf )
return( 1 );
}
memset ( p_intf->p_sys, 0, sizeof ( intf_sys_t ) );
/* Initialize the curses library */
initscr();
/* Don't do NL -> CR/NL */
......@@ -112,6 +140,8 @@ static int intf_Open( intf_thread_t *p_intf )
curs_set(0);
timeout(0);
clear();
return( 0 );
}
......@@ -133,6 +163,12 @@ static void intf_Close( intf_thread_t *p_intf )
static void intf_Run( intf_thread_t *p_intf )
{
signed char i_key;
time_t t_last_refresh;
/*
* force drawing the interface for the first time
*/
t_last_refresh = ( time( 0 ) - 1);
while( !p_intf->b_die )
{
......@@ -140,26 +176,477 @@ static void intf_Run( intf_thread_t *p_intf )
msleep( INTF_IDLE_SLEEP );
mvaddstr( 1, 2, VOUT_TITLE " (ncurses interface)" );
mvaddstr( 3, 2, "keys:" );
mvaddstr( 4, 2, "Q,q.......quit" );
//mvaddstr( 5, 2, "No other keys are active yet." );
while( (i_key = getch()) != -1 )
{
switch( i_key )
/*
* ncurses_HandleKey returns 1 if the screen needs to be redrawn
*/
if ( ncurses_handleKey( p_intf, i_key ) )
{
case 'q':
case 'Q':
p_intf->b_die = 1;
break;
default:
break;
ncurses_draw( &t_last_refresh, p_intf );
}
}
/*
* redraw the screen every second
*/
if ( (time(0) - t_last_refresh) >= 1 )
{
ncurses_manageSlider ( p_intf );
ncurses_draw( &t_last_refresh, p_intf );
}
}
}
/* following functions are local */
static int
ncurses_handleKey( intf_thread_t *p_intf, int i_key )
{
switch( i_key )
{
case 'q':
case 'Q':
p_intf->b_die = 1;
return 0;
case 'f':
ncurses_Fullscreen();
return 1;
case 'p':
ncurses_Play();
return 1;
case ' ':
ncurses_Pause();
return 1;
case 's':
ncurses_Stop();
return 1;
case 'n':
ncurses_Next();
return 1;
case 'e':
ncurses_Eject();
return 1;
case '[':
ncurses_TitlePrev ();
break;
case ']':
ncurses_TitleNext ();
break;
case '<':
ncurses_ChapterPrev ();
break;
case '>':
ncurses_ChapterNext ();
break;
case KEY_RIGHT:
p_intf->p_sys->f_slider_state += 100;
ncurses_manageSlider ( p_intf );
break;
case KEY_LEFT:
p_intf->p_sys->f_slider_state--;
ncurses_manageSlider ( p_intf );
break;
/*
* ^l should clear and redraw the screen
*/
case 0x0c:
clear();
return 1;
default:
break;
}
return 0;
}
static int
ncurses_printFullLine ( const char *p_fmt, ... )
{
va_list vl_args;
char * p_buf = NULL;
int i_len;
va_start ( vl_args, p_fmt );
vasprintf ( &p_buf, p_fmt, vl_args );
va_end ( vl_args );
if ( p_buf == NULL )
{
intf_ErrMsg ( "intf error: %s", strerror ( ENOMEM ) );
return ( -1 );
}
i_len = strlen( p_buf );
/*
* make sure we don't exceed the border on the right side
*/
if ( i_len > COLS )
{
p_buf[COLS] = '\0';
i_len = COLS;
printw( "%s", p_buf );
}
else
{
printw( "%s", p_buf );
hline( ' ', COLS - i_len );
}
free ( p_buf );
return i_len;
}
static void
ncurses_draw ( time_t *t_last_refresh , intf_thread_t *p_intf )
{
int row = 0;
move ( row, 0 );
attrset ( A_REVERSE );
ncurses_printFullLine( VOUT_TITLE " (ncurses interface)" );
attroff ( A_REVERSE );
row++;
row++;
move ( row, 0 );
if ( p_input_bank->pp_input[0] != NULL )
{
ncurses_printFullLine ( " DVD Chapter:%3d DVD Title:%3d",
p_input_bank->pp_input[0]->stream.p_selected_area->i_part,
p_input_bank->pp_input[0]->stream.p_selected_area->i_id );
}
row++;
mvaddch ( row, 0, ACS_ULCORNER );
mvhline ( row, 1, ACS_HLINE, COLS-2 );
mvaddch ( row, COLS-1, ACS_URCORNER );
row++;
mvaddch ( row, 0, ACS_VLINE );
attrset ( A_REVERSE );
mvhline ( row, 1, ' ', ( (int) p_intf->p_sys->f_slider_state % COLS-2) );
attroff ( A_REVERSE );
mvaddch ( row, COLS-1, ACS_VLINE );
row++;
mvaddch ( row, 0, ACS_LLCORNER );
mvhline ( row, 1, ACS_HLINE, COLS-2 );
mvaddch ( row, COLS-1, ACS_LRCORNER );
refresh();
*t_last_refresh = time( 0 );
}
static void
ncurses_Fullscreen ( void )
{
vlc_mutex_lock( &p_vout_bank->pp_vout[0]->change_lock );
p_vout_bank->pp_vout[0]->i_changes |= VOUT_FULLSCREEN_CHANGE;
vlc_mutex_unlock( &p_vout_bank->pp_vout[0]->change_lock );
}
static void
ncurses_Eject ( void )
{
char *psz_device = NULL;
char *psz_parser;
/*
* Get the active input
* Determine whether we can eject a media, ie it's a VCD or DVD
* If it's neither a VCD nor a DVD, then return
*/
/*
* Don't really know if I must lock the stuff here, we're using it read-only
*/
if (p_main->p_playlist->current.psz_name != NULL)
{
if( !strncmp(p_main->p_playlist->current.psz_name, "dvd:", 4) )
{
switch( p_main->p_playlist->current.psz_name[4] )
{
case '\0':
case '@':
psz_device = config_GetPszVariable( "dvd_device" );
break;
default:
/* Omit the first 4 characters */
psz_device = strdup( p_main->p_playlist->current.psz_name + 4 );
break;
}
}
else if( !strncmp(p_main->p_playlist->current.psz_name, "vcd:", 4) )
{
switch( p_main->p_playlist->current.psz_name[4] )
{
case '\0':
case '@':
psz_device = config_GetPszVariable( "vcd_device" );
break;
default:
/* Omit the first 4 characters */
psz_device = strdup( p_main->p_playlist->current.psz_name + 4 );
break;
}
}
else
{
psz_device = strdup( p_main->p_playlist->current.psz_name );
}
}
if( psz_device == NULL )
{
return;
}
/* Remove what we have after @ */
psz_parser = psz_device;
for( psz_parser = psz_device ; *psz_parser ; psz_parser++ )
{
if( *psz_parser == '@' )
{
*psz_parser = '\0';
break;
}
}
/* If there's a stream playing, we aren't allowed to eject ! */
if( p_input_bank->pp_input[0] == NULL )
{
intf_WarnMsg( 4, "intf: ejecting %s", psz_device );
intf_Eject( psz_device );
}
free(psz_device);
return;
}
static void
ncurses_Play ( void )
{
if( p_input_bank->pp_input[0] != NULL )
{
input_SetStatus( p_input_bank->pp_input[0], INPUT_STATUS_PLAY );
p_main->p_playlist->b_stopped = 0;
}
else
{
vlc_mutex_lock( &p_main->p_playlist->change_lock );
if( p_main->p_playlist->b_stopped )
{
if( p_main->p_playlist->i_size )
{
vlc_mutex_unlock( &p_main->p_playlist->change_lock );
intf_PlaylistJumpto( p_main->p_playlist,
p_main->p_playlist->i_index );
}
else
{
vlc_mutex_unlock( &p_main->p_playlist->change_lock );
}
}
else
{
vlc_mutex_unlock( &p_main->p_playlist->change_lock );
}
}
}
static void
ncurses_Pause ( void )
{
if( p_input_bank->pp_input[0] != NULL )
{
if ( p_input_bank->pp_input[0]->i_status & INPUT_STATUS_PLAY )
{
input_SetStatus( p_input_bank->pp_input[0], INPUT_STATUS_PAUSE );
vlc_mutex_lock( &p_main->p_playlist->change_lock );
p_main->p_playlist->b_stopped = 0;
vlc_mutex_unlock( &p_main->p_playlist->change_lock );
}
else
{
ncurses_Play ();
}
}
}
static void
ncurses_Stop ( void )
{
if( p_input_bank->pp_input[0] != NULL )
{
/* end playing item */
p_input_bank->pp_input[0]->b_eof = 1;
/* update playlist */
vlc_mutex_lock( &p_main->p_playlist->change_lock );
p_main->p_playlist->i_index--;
p_main->p_playlist->b_stopped = 1;
vlc_mutex_unlock( &p_main->p_playlist->change_lock );
}
}
static void
ncurses_Next ( void )
{
int i_id;
input_area_t * p_area;
i_id = p_input_bank->pp_input[0]->stream.p_selected_area->i_id+1;
if ( i_id < p_input_bank->pp_input[0]->stream.i_area_nb )
{
p_area = p_input_bank->pp_input[0]->stream.pp_areas[i_id];
input_ChangeArea( p_input_bank->pp_input[0],
(input_area_t *) p_area );
input_SetStatus( p_input_bank->pp_input[0], INPUT_STATUS_PLAY );
}
}
static void
ncurses_manageSlider ( intf_thread_t *p_intf )
{
if( p_input_bank->pp_input[0] != NULL )
{
vlc_mutex_lock( &p_input_bank->pp_input[0]->stream.stream_lock );
if( p_input_bank->pp_input[0]->stream.b_seekable &&
p_input_bank->pp_input[0]->i_status & INPUT_STATUS_PLAY )
{
float newvalue = p_intf->p_sys->f_slider_state;
#define p_area p_input_bank->pp_input[0]->stream.p_selected_area
/* If the user hasn't touched the slider since the last time,
* then the input can safely change it */
if( newvalue == p_intf->p_sys->f_slider_state_old )
{
/* Update the value */
p_intf->p_sys->f_slider_state =
p_intf->p_sys->f_slider_state_old =
( 100 * p_area->i_tell ) / p_area->i_size;
}
/* Otherwise, send message to the input if the user has
* finished dragging the slider */
else
{
off_t i_seek = ( newvalue * p_area->i_size ) / 100;
/* release the lock to be able to seek */
vlc_mutex_unlock( &p_input_bank->pp_input[0]->stream.stream_lock );
input_Seek( p_input_bank->pp_input[0], i_seek );
vlc_mutex_lock( &p_input_bank->pp_input[0]->stream.stream_lock );
/* Update the old value */
p_intf->p_sys->f_slider_state_old = newvalue;
}
# undef p_area
}
vlc_mutex_unlock( &p_input_bank->pp_input[0]->stream.stream_lock );
}
}
static void
ncurses_TitlePrev ( void )
{
input_area_t * p_area;
int i_id;
i_id = p_input_bank->pp_input[0]->stream.p_selected_area->i_id - 1;
/* Disallow area 0 since it is used for video_ts.vob */
if ( i_id > 0 )
{
p_area = p_input_bank->pp_input[0]->stream.pp_areas[i_id];
input_ChangeArea( p_input_bank->pp_input[0], (input_area_t*)p_area );
input_SetStatus( p_input_bank->pp_input[0], INPUT_STATUS_PLAY );
}
}
static void
ncurses_TitleNext ( void )
{
input_area_t * p_area;
int i_id;
i_id = p_input_bank->pp_input[0]->stream.p_selected_area->i_id + 1;
if ( i_id < p_input_bank->pp_input[0]->stream.i_area_nb )
{
p_area = p_input_bank->pp_input[0]->stream.pp_areas[i_id];
input_ChangeArea( p_input_bank->pp_input[0], (input_area_t*)p_area );
input_SetStatus( p_input_bank->pp_input[0], INPUT_STATUS_PLAY );
}
}
static void
ncurses_ChapterPrev ( void )
{
input_area_t * p_area;
p_area = p_input_bank->pp_input[0]->stream.p_selected_area;
if ( p_area->i_part > 0 )
{
p_area->i_part--;
input_ChangeArea( p_input_bank->pp_input[0], (input_area_t*)p_area );
input_SetStatus( p_input_bank->pp_input[0], INPUT_STATUS_PLAY );
}
}
static void
ncurses_ChapterNext ( void )
{
input_area_t * p_area;
p_area = p_input_bank->pp_input[0]->stream.p_selected_area;
if ( p_area->i_part < p_area->i_part_nb )
{
p_area->i_part++;
input_ChangeArea( p_input_bank->pp_input[0], (input_area_t*)p_area );
input_SetStatus( p_input_bank->pp_input[0], INPUT_STATUS_PLAY );
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment