1 /*****************************************************************************
2 * intf_qt.cpp: Qt interface
3 *****************************************************************************
4 * Copyright (C) 1999, 2000 VideoLAN
5 * $Id: intf_qt.cpp,v 1.12 2002/02/15 13:32:53 sam Exp $
7 * Authors: Samuel Hocevar <sam@zoy.org>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
22 *****************************************************************************/
27 /*****************************************************************************
29 *****************************************************************************/
30 #include <errno.h> /* ENOMEM */
31 #include <stdlib.h> /* free() */
32 #include <string.h> /* strerror() */
35 #include <videolan/vlc.h>
37 #include "stream_control.h"
38 #include "input_ext-intf.h"
40 #include "intf_playlist.h"
41 #include "interface.h"
45 #include <qapplication.h>
46 #include <qmainwindow.h>
48 #include <qtoolbutton.h>
49 #include <qwhatsthis.h>
50 #include <qpushbutton.h>
51 #include <qfiledialog.h>
53 #include <qlcdnumber.h>
55 #include <qstatusbar.h>
56 #include <qmessagebox.h>
64 /*****************************************************************************
65 * Local Qt slider class
66 *****************************************************************************/
67 class IntfSlider : public QSlider
72 IntfSlider( intf_thread_t *, QWidget * ); /* Constructor and destructor */
75 bool b_free; /* Is the slider free ? */
77 int oldvalue ( void ) { return i_oldvalue; };
78 void setOldValue( int i_value ) { i_oldvalue = i_value; };
81 void SlideStart ( void ) { b_free = FALSE; };
82 void SlideStop ( void ) { b_free = TRUE; };
85 intf_thread_t *p_intf;
89 /*****************************************************************************
90 * Local Qt interface window class
91 *****************************************************************************/
92 class IntfWindow : public QMainWindow
97 IntfWindow( intf_thread_t * );
103 void FileOpen ( void );
104 void FileQuit ( void ) { qApp->quit(); };
106 void PlaybackPlay ( void );
107 void PlaybackPause ( void );
108 void PlaybackSlow ( void );
109 void PlaybackFast ( void );
111 void PlaylistPrev ( void );
112 void PlaylistNext ( void );
114 void DateDisplay ( int );
117 void Unimplemented( void ) { intf_WarnMsg( 1, "intf warning: "
118 "unimplemented function" ); };
121 intf_thread_t *p_intf;
123 IntfSlider *p_slider;
130 #include "intf_qt.moc"
132 #define SLIDER_MIN 0x00000
133 #define SLIDER_MAX 0x10000
134 #define SLIDER_STEP (SLIDER_MAX >> 4)
136 /*****************************************************************************
137 * intf_sys_t: description and status of Qt interface
138 *****************************************************************************/
139 typedef struct intf_sys_s
142 IntfWindow *p_window;
146 /*****************************************************************************
148 *****************************************************************************/
149 static int intf_Open ( intf_thread_t *p_intf );
150 static void intf_Close ( intf_thread_t *p_intf );
151 static void intf_Run ( intf_thread_t *p_intf );
153 /*****************************************************************************
154 * Functions exported as capabilities. They are declared as static so that
155 * we don't pollute the namespace too much.
156 *****************************************************************************/
160 void _M( intf_getfunctions )( function_list_t * p_function_list )
162 p_function_list->functions.intf.pf_open = intf_Open;
163 p_function_list->functions.intf.pf_close = intf_Close;
164 p_function_list->functions.intf.pf_run = intf_Run;
169 /*****************************************************************************
170 * intf_Open: initialize and create window
171 *****************************************************************************/
172 static int intf_Open( intf_thread_t *p_intf )
174 char *pp_argv[] = { "" };
177 /* Allocate instance and initialize some members */
178 p_intf->p_sys = (intf_sys_t *)malloc( sizeof( intf_sys_t ) );
179 if( p_intf->p_sys == NULL )
181 intf_ErrMsg( "intf error: %s", strerror(ENOMEM) );
185 /* Create the C++ objects */
186 p_intf->p_sys->p_app = new QApplication( i_argc, pp_argv );
187 p_intf->p_sys->p_window = new IntfWindow( p_intf );
189 /* Tell the world we are here */
190 p_intf->p_sys->p_window->setCaption( VOUT_TITLE " (Qt interface)" );
195 /*****************************************************************************
196 * intf_Close: destroy interface window
197 *****************************************************************************/
198 static void intf_Close( intf_thread_t *p_intf )
200 /* Get rid of the C++ objects */
201 delete p_intf->p_sys->p_window;
202 delete p_intf->p_sys->p_app;
204 /* Destroy structure */
205 free( p_intf->p_sys );
208 /*****************************************************************************
209 * intf_Run: Qt thread
210 *****************************************************************************
211 * This part of the interface is in a separate thread so that we can call
212 * exec() from within it without annoying the rest of the program.
213 *****************************************************************************/
214 static void intf_Run( intf_thread_t *p_intf )
216 p_intf->p_sys->p_window->show();
218 p_intf->p_sys->p_app->exec();
221 /* following functions are local */
223 /*****************************************************************************
224 * IntfWindow: interface window creator
225 *****************************************************************************
226 * This function creates the interface window, and populates it with a
227 * menu bar, a toolbar and a slider.
228 *****************************************************************************/
229 IntfWindow::IntfWindow( intf_thread_t *p_intf )
232 setUsesTextLabel( TRUE );
234 this->p_intf = p_intf;
240 p_toolbar = new QToolBar( this, "toolbar" );
241 p_toolbar->setHorizontalStretchable( TRUE );
243 QIconSet * set = new QIconSet();
244 QPixmap pixmap = set->pixmap( QIconSet::Automatic, QIconSet::Normal );
246 #define addbut( l, t, s ) new QToolButton( pixmap, l, t, this, s, p_toolbar );
247 addbut( "Open", "Open a File", SLOT(FileOpen()) );
248 addbut( "Disc", "Open a DVD or VCD", SLOT(Unimplemented()) );
249 addbut( "Net", "Select a Network Stream", SLOT(Unimplemented()) );
250 p_toolbar->addSeparator();
251 addbut( "Back", "Rewind Stream", SLOT(Unimplemented()) );
252 addbut( "Stop", "Stop Stream", SLOT(Unimplemented()) );
253 addbut( "Play", "Play Stream", SLOT(PlaybackPlay()) );
254 addbut( "Pause", "Pause Stream", SLOT(PlaybackPause()) );
255 addbut( "Slow", "Play Slower", SLOT(PlaybackSlow()) );
256 addbut( "Fast", "Play Faster", SLOT(PlaybackFast()) );
257 p_toolbar->addSeparator();
258 addbut( "Playlist", "Open Playlist", SLOT(Unimplemented()) );
259 addbut( "Prev", "Previous File", SLOT(PlaylistPrev()) );
260 addbut( "Next", "Next File", SLOT(PlaylistNext()) );
267 QPopupMenu * p_tmpmenu = new QPopupMenu( this );
269 #define instmp( x, y... ) p_tmpmenu->insertItem( x, this, ## y )
270 menuBar()->insertItem( "&File", p_tmpmenu );
271 instmp( "&Open File...", SLOT(FileOpen()), Key_F3 );
272 instmp( "Open &Disc...", SLOT(Unimplemented()), Key_F4 );
273 instmp( "&Network Stream...", SLOT(Unimplemented()), Key_F5 );
274 p_tmpmenu->insertSeparator();
275 instmp( "&Exit", SLOT(FileQuit()), CTRL+Key_Q );
277 p_tmpmenu = new QPopupMenu( this );
278 menuBar()->insertItem( "&View", p_tmpmenu );
279 instmp( "&Playlist...", SLOT(Unimplemented()) );
280 instmp( "&Modules...", SLOT(Unimplemented()) );
282 p_tmpmenu = new QPopupMenu( this );
283 menuBar()->insertItem( "&Settings", p_tmpmenu );
284 instmp( "&Preferences...", SLOT(Unimplemented()) );
286 p_tmpmenu = new QPopupMenu( this );
287 menuBar()->insertItem( "&Help", p_tmpmenu );
288 instmp( "&About...", SLOT(About()) );
292 * Create the popup menu
295 p_popup = new QPopupMenu( /* floating menu */ );
297 #define inspop( x, y... ) p_popup->insertItem( x, this, ## y )
298 inspop( "&Play", SLOT(PlaybackPlay()) );
299 inspop( "Pause", SLOT(PlaybackPause()) );
300 inspop( "&Slow", SLOT(PlaybackSlow()) );
301 inspop( "&Fast", SLOT(PlaybackFast()) );
302 p_popup->insertSeparator();
303 inspop( "&Open File...", SLOT(FileOpen()), Key_F3 );
304 inspop( "Open &Disc...", SLOT(Unimplemented()), Key_F4 );
305 inspop( "&Network Stream...", SLOT(Unimplemented()), Key_F5 );
306 p_popup->insertSeparator();
307 inspop( "&About...", SLOT(About()) );
308 inspop( "&Exit", SLOT(FileQuit()) );
311 /* Activate the statusbar */
314 /* Add the vertical box */
315 QVBox * p_vbox = new QVBox( this );
316 setCentralWidget( p_vbox );
318 /* The horizontal box */
319 QHBox * p_hbox = new QHBox( p_vbox );
322 p_date = new QLabel( p_hbox );
323 p_date->setAlignment( AlignHCenter | AlignVCenter );
324 p_date->setText( "-:--:--" );
326 /* The status label */
327 QLabel *p_label = new QLabel( p_hbox );
328 p_label->setAlignment( AlignHCenter | AlignVCenter );
329 p_label->setText( "Status: foo" );
332 p_label = new QLabel( p_hbox );
333 p_label->setAlignment( AlignHCenter | AlignVCenter );
334 p_label->setText( "Bar: baz quux" );
336 /* Create the slider and connect it to the date label */
337 p_slider = new IntfSlider( p_intf, p_vbox );
339 connect( p_slider, SIGNAL(valueChanged(int)),
340 this, SLOT(DateDisplay(int)) );
343 QTimer *p_timer = new QTimer( this );
344 connect( p_timer, SIGNAL(timeout()), this, SLOT(Manage()) );
345 p_timer->start( INTF_IDLE_SLEEP / 1000 );
347 /* Everything worked fine */
351 /*****************************************************************************
352 * ~IntfWindow: interface window destructor
353 *****************************************************************************
354 * This function is called when the interface window is destroyed.
355 *****************************************************************************/
356 IntfWindow::~IntfWindow( void )
358 /* FIXME: remove everything cleanly */
361 /*****************************************************************************
362 * DateDisplay: display date
363 *****************************************************************************
364 * This function displays the current date in the date label.
365 *****************************************************************************/
366 void IntfWindow::DateDisplay( int i_range )
368 if( p_input_bank->pp_input[0] != NULL )
370 char psz_time[ OFFSETTOTIME_MAX_SIZE ];
372 vlc_mutex_lock( &p_input_bank->pp_input[0]->stream.stream_lock );
373 p_date->setText( input_OffsetToTime( p_input_bank->pp_input[0], psz_time,
374 ( p_input_bank->pp_input[0]->stream.p_selected_area->i_size * i_range )
376 vlc_mutex_unlock( &p_input_bank->pp_input[0]->stream.stream_lock );
380 /*****************************************************************************
381 * FileOpen: open a file
382 *****************************************************************************
383 * This function opens a file requester and adds the selected file to
385 *****************************************************************************/
386 void IntfWindow::FileOpen( void )
388 QString file = QFileDialog::getOpenFileName( QString::null,
389 QString::null, this );
393 statusBar()->message( "No file loaded", 2000 );
397 intf_PlaylistAdd( p_main->p_playlist, PLAYLIST_END, file.latin1() );
401 /*****************************************************************************
402 * About: display the "about" box
403 *****************************************************************************
404 * This function displays a simple "about" box with copyright information.
405 *****************************************************************************/
406 void IntfWindow::About( void )
408 QMessageBox::about( this, "About",
410 "(C) 1996, 1997, 1998, 1999, 2000, 2001 - the VideoLAN Team\n"
412 "This is the VideoLAN client, a DVD and MPEG player.\n"
413 "It can play MPEG and MPEG 2 files from a file "
414 "or from a network source.\n"
416 "More information: http://www.videolan.org/" );
419 /*****************************************************************************
420 * Manage: manage main thread messages
421 *****************************************************************************
422 * In this function, called approx. 10 times a second, we check what the
423 * main program wanted to tell us.
424 *****************************************************************************/
425 void IntfWindow::Manage( void )
427 /* Manage the slider */
428 if( p_input_bank->pp_input[0] != NULL && p_input_bank->pp_input[0]->stream.b_seekable )
430 int i_value = p_slider->value();
432 #define p_area p_input_bank->pp_input[0]->stream.p_selected_area
433 /* If the user hasn't touched the slider since the last time,
434 * then the input can safely change it */
435 if( i_value == p_slider->oldvalue() )
437 i_value = ( SLIDER_MAX * p_area->i_tell ) / p_area->i_size;
439 p_slider->setValue( i_value );
440 p_slider->setOldValue( i_value );
442 /* Otherwise, send message to the input if the user has
443 * finished dragging the slider */
444 else if( p_slider->b_free )
446 off_t i_seek = ( i_value * p_area->i_size ) / SLIDER_MAX;
448 input_Seek( p_input_bank->pp_input[0], i_seek );
450 /* Update the old value */
451 p_slider->setOldValue( i_value );
456 /* If the "display popup" flag has changed, popup the context menu */
457 if( p_intf->b_menu_change )
459 p_popup->popup( QCursor::pos() );
460 p_intf->b_menu_change = 0;
468 /* Manage core vlc functions through the callback */
469 p_intf->pf_manage( p_intf );
472 /*****************************************************************************
474 *****************************************************************************/
475 void IntfWindow::PlaybackPlay( void )
477 if( p_input_bank->pp_input[0] != NULL )
479 input_SetStatus( p_input_bank->pp_input[0], INPUT_STATUS_PLAY );
483 /*****************************************************************************
484 * PlaybackPause: pause
485 *****************************************************************************/
486 void IntfWindow::PlaybackPause( void )
488 if( p_input_bank->pp_input[0] != NULL )
490 input_SetStatus( p_input_bank->pp_input[0], INPUT_STATUS_PAUSE );
494 /*****************************************************************************
496 *****************************************************************************/
497 void IntfWindow::PlaybackSlow( void )
499 if( p_input_bank->pp_input[0] != NULL )
501 input_SetStatus( p_input_bank->pp_input[0], INPUT_STATUS_SLOWER );
505 /*****************************************************************************
507 *****************************************************************************/
508 void IntfWindow::PlaybackFast( void )
510 if( p_input_bank->pp_input[0] != NULL )
512 input_SetStatus( p_input_bank->pp_input[0], INPUT_STATUS_FASTER );
516 /*****************************************************************************
517 * PlaylistPrev: previous playlist entry
518 *****************************************************************************/
519 void IntfWindow::PlaylistPrev( void )
521 if( p_input_bank->pp_input[0] != NULL )
523 /* FIXME: temporary hack */
524 intf_PlaylistPrev( p_main->p_playlist );
525 intf_PlaylistPrev( p_main->p_playlist );
526 p_input_bank->pp_input[0]->b_eof = 1;
530 /*****************************************************************************
531 * PlaylistNext: next playlist entry
532 *****************************************************************************/
533 void IntfWindow::PlaylistNext( void )
535 if( p_input_bank->pp_input[0] != NULL )
537 /* FIXME: temporary hack */
538 p_input_bank->pp_input[0]->b_eof = 1;
542 /*****************************************************************************
543 * IntfSlider: slider creator
544 *****************************************************************************
545 * This function creates the slider, sets its default values, and connects
546 * the interesting signals.
547 *****************************************************************************/
548 IntfSlider::IntfSlider( intf_thread_t *p_intf, QWidget *p_parent )
549 :QSlider( Horizontal, p_parent )
551 this->p_intf = p_intf;
553 setRange( SLIDER_MIN, SLIDER_MAX );
554 setPageStep( SLIDER_STEP );
556 setValue( SLIDER_MIN );
557 setOldValue( SLIDER_MIN );
562 connect( this, SIGNAL(sliderMoved(int)), this, SLOT(SlideStart()) );
563 connect( this, SIGNAL(sliderPressed()), this, SLOT(SlideStart()) );
564 connect( this, SIGNAL(sliderReleased()), this, SLOT(SlideStop()) );
567 /*****************************************************************************
568 * ~IntfSlider: slider destructor
569 *****************************************************************************
570 * This function is called when the interface slider is destroyed.
571 *****************************************************************************/
572 IntfSlider::~IntfSlider( void )
574 /* We don't need to remove anything */