1 /*****************************************************************************
2 * intf_qt.cpp: Qt interface
3 *****************************************************************************
4 * Copyright (C) 1999, 2000 VideoLAN
5 * $Id: intf_qt.cpp,v 1.17 2002/07/20 18:01:43 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 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
27 #include <errno.h> /* ENOMEM */
28 #include <stdlib.h> /* free() */
29 #include <string.h> /* strerror() */
35 #include <qapplication.h>
36 #include <qmainwindow.h>
38 #include <qtoolbutton.h>
39 #include <qwhatsthis.h>
40 #include <qpushbutton.h>
41 #include <qfiledialog.h>
43 #include <qlcdnumber.h>
45 #include <qstatusbar.h>
46 #include <qmessagebox.h>
54 /*****************************************************************************
55 * Local Qt slider class
56 *****************************************************************************/
57 class IntfSlider : public QSlider
62 IntfSlider( intf_thread_t *, QWidget * ); /* Constructor and destructor */
65 bool b_free; /* Is the slider free ? */
67 int oldvalue ( void ) { return i_oldvalue; };
68 void setOldValue( int i_value ) { i_oldvalue = i_value; };
71 void SlideStart ( void ) { b_free = FALSE; };
72 void SlideStop ( void ) { b_free = TRUE; };
75 intf_thread_t *p_intf;
79 /*****************************************************************************
80 * Local Qt interface window class
81 *****************************************************************************/
82 class IntfWindow : public QMainWindow
87 IntfWindow( intf_thread_t * );
93 void FileOpen ( void );
94 void FileQuit ( void );
96 void PlaybackPlay ( void );
97 void PlaybackPause ( void );
98 void PlaybackSlow ( void );
99 void PlaybackFast ( void );
101 void PlaylistPrev ( void );
102 void PlaylistNext ( void );
104 void DateDisplay ( int );
107 void Unimplemented( void ) { msg_Warn( p_intf, "unimplemented" ); };
110 intf_thread_t *p_intf;
112 IntfSlider *p_slider;
119 #include "intf_qt.moc"
121 #define SLIDER_MIN 0x00000
122 #define SLIDER_MAX 0x10000
123 #define SLIDER_STEP (SLIDER_MAX >> 4)
125 /*****************************************************************************
126 * intf_sys_t: description and status of Qt interface
127 *****************************************************************************/
131 IntfWindow *p_window;
133 input_thread_t *p_input;
136 /*****************************************************************************
138 *****************************************************************************/
139 static int intf_Open ( intf_thread_t *p_intf );
140 static void intf_Close ( intf_thread_t *p_intf );
141 static void intf_Run ( intf_thread_t *p_intf );
143 /*****************************************************************************
144 * Functions exported as capabilities. They are declared as static so that
145 * we don't pollute the namespace too much.
146 *****************************************************************************/
150 void _M( intf_getfunctions )( function_list_t * p_function_list )
152 p_function_list->functions.intf.pf_open = intf_Open;
153 p_function_list->functions.intf.pf_close = intf_Close;
154 p_function_list->functions.intf.pf_run = intf_Run;
159 /*****************************************************************************
160 * intf_Open: initialize and create window
161 *****************************************************************************/
162 static int intf_Open( intf_thread_t *p_intf )
164 char *pp_argv[] = { "" };
167 /* Allocate instance and initialize some members */
168 p_intf->p_sys = (intf_sys_t *)malloc( sizeof( intf_sys_t ) );
169 if( p_intf->p_sys == NULL )
171 msg_Err( p_intf, "out of memory" );
175 /* Create the C++ objects */
176 p_intf->p_sys->p_app = new QApplication( i_argc, pp_argv );
177 p_intf->p_sys->p_window = new IntfWindow( p_intf );
179 /* Tell the world we are here */
180 p_intf->p_sys->p_window->setCaption( VOUT_TITLE " (Qt interface)" );
182 p_intf->p_sys->p_input = NULL;
187 /*****************************************************************************
188 * intf_Close: destroy interface window
189 *****************************************************************************/
190 static void intf_Close( intf_thread_t *p_intf )
192 if( p_intf->p_sys->p_input )
194 vlc_object_release( p_intf->p_sys->p_input );
197 /* Get rid of the C++ objects */
198 delete p_intf->p_sys->p_window;
199 delete p_intf->p_sys->p_app;
201 /* Destroy structure */
202 free( p_intf->p_sys );
205 /*****************************************************************************
206 * intf_Run: Qt thread
207 *****************************************************************************
208 * This part of the interface is in a separate thread so that we can call
209 * exec() from within it without annoying the rest of the program.
210 *****************************************************************************/
211 static void intf_Run( intf_thread_t *p_intf )
213 p_intf->p_sys->p_window->show();
215 p_intf->p_sys->p_app->exec();
218 /* following functions are local */
220 /*****************************************************************************
221 * IntfWindow: interface window creator
222 *****************************************************************************
223 * This function creates the interface window, and populates it with a
224 * menu bar, a toolbar and a slider.
225 *****************************************************************************/
226 IntfWindow::IntfWindow( intf_thread_t *p_intf )
229 setUsesTextLabel( TRUE );
231 this->p_intf = p_intf;
237 p_toolbar = new QToolBar( this, "toolbar" );
238 p_toolbar->setHorizontalStretchable( TRUE );
240 QIconSet * set = new QIconSet();
241 QPixmap pixmap = set->pixmap( QIconSet::Automatic, QIconSet::Normal );
243 #define addbut( l, t, s ) new QToolButton( pixmap, l, t, this, s, p_toolbar );
244 addbut( "Open", "Open a File", SLOT(FileOpen()) );
245 addbut( "Disc", "Open a DVD or VCD", SLOT(Unimplemented()) );
246 addbut( "Net", "Select a Network Stream", SLOT(Unimplemented()) );
247 p_toolbar->addSeparator();
248 addbut( "Back", "Rewind Stream", SLOT(Unimplemented()) );
249 addbut( "Stop", "Stop Stream", SLOT(Unimplemented()) );
250 addbut( "Play", "Play Stream", SLOT(PlaybackPlay()) );
251 addbut( "Pause", "Pause Stream", SLOT(PlaybackPause()) );
252 addbut( "Slow", "Play Slower", SLOT(PlaybackSlow()) );
253 addbut( "Fast", "Play Faster", SLOT(PlaybackFast()) );
254 p_toolbar->addSeparator();
255 addbut( "Playlist", "Open Playlist", SLOT(Unimplemented()) );
256 addbut( "Prev", "Previous File", SLOT(PlaylistPrev()) );
257 addbut( "Next", "Next File", SLOT(PlaylistNext()) );
264 QPopupMenu * p_tmpmenu = new QPopupMenu( this );
266 #define instmp( x, y... ) p_tmpmenu->insertItem( x, this, ## y )
267 menuBar()->insertItem( "&File", p_tmpmenu );
268 instmp( "&Open File...", SLOT(FileOpen()), Key_F3 );
269 instmp( "Open &Disc...", SLOT(Unimplemented()), Key_F4 );
270 instmp( "&Network Stream...", SLOT(Unimplemented()), Key_F5 );
271 p_tmpmenu->insertSeparator();
272 instmp( "&Exit", SLOT(FileQuit()), CTRL+Key_Q );
274 p_tmpmenu = new QPopupMenu( this );
275 menuBar()->insertItem( "&View", p_tmpmenu );
276 instmp( "&Playlist...", SLOT(Unimplemented()) );
277 instmp( "&Modules...", SLOT(Unimplemented()) );
279 p_tmpmenu = new QPopupMenu( this );
280 menuBar()->insertItem( "&Settings", p_tmpmenu );
281 instmp( "&Preferences...", SLOT(Unimplemented()) );
283 p_tmpmenu = new QPopupMenu( this );
284 menuBar()->insertItem( "&Help", p_tmpmenu );
285 instmp( "&About...", SLOT(About()) );
289 * Create the popup menu
292 p_popup = new QPopupMenu( /* floating menu */ );
294 #define inspop( x, y... ) p_popup->insertItem( x, this, ## y )
295 inspop( "&Play", SLOT(PlaybackPlay()) );
296 inspop( "Pause", SLOT(PlaybackPause()) );
297 inspop( "&Slow", SLOT(PlaybackSlow()) );
298 inspop( "&Fast", SLOT(PlaybackFast()) );
299 p_popup->insertSeparator();
300 inspop( "&Open File...", SLOT(FileOpen()), Key_F3 );
301 inspop( "Open &Disc...", SLOT(Unimplemented()), Key_F4 );
302 inspop( "&Network Stream...", SLOT(Unimplemented()), Key_F5 );
303 p_popup->insertSeparator();
304 inspop( "&About...", SLOT(About()) );
305 inspop( "&Exit", SLOT(FileQuit()) );
308 /* Activate the statusbar */
311 /* Add the vertical box */
312 QVBox * p_vbox = new QVBox( this );
313 setCentralWidget( p_vbox );
315 /* The horizontal box */
316 QHBox * p_hbox = new QHBox( p_vbox );
319 p_date = new QLabel( p_hbox );
320 p_date->setAlignment( AlignHCenter | AlignVCenter );
321 p_date->setText( "-:--:--" );
323 /* The status label */
324 QLabel *p_label = new QLabel( p_hbox );
325 p_label->setAlignment( AlignHCenter | AlignVCenter );
326 p_label->setText( "Status: foo" );
329 p_label = new QLabel( p_hbox );
330 p_label->setAlignment( AlignHCenter | AlignVCenter );
331 p_label->setText( "Bar: baz quux" );
333 /* Create the slider and connect it to the date label */
334 p_slider = new IntfSlider( p_intf, p_vbox );
336 connect( p_slider, SIGNAL(valueChanged(int)),
337 this, SLOT(DateDisplay(int)) );
340 QTimer *p_timer = new QTimer( this );
341 connect( p_timer, SIGNAL(timeout()), this, SLOT(Manage()) );
342 p_timer->start( INTF_IDLE_SLEEP / 1000 );
344 /* Everything worked fine */
348 /*****************************************************************************
349 * ~IntfWindow: interface window destructor
350 *****************************************************************************
351 * This function is called when the interface window is destroyed.
352 *****************************************************************************/
353 IntfWindow::~IntfWindow( void )
355 /* FIXME: remove everything cleanly */
358 /*****************************************************************************
359 * DateDisplay: display date
360 *****************************************************************************
361 * This function displays the current date in the date label.
362 *****************************************************************************/
363 void IntfWindow::DateDisplay( int i_range )
365 if( p_intf->p_sys->p_input )
367 char psz_time[ OFFSETTOTIME_MAX_SIZE ];
369 vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock );
370 p_date->setText( input_OffsetToTime( p_intf->p_sys->p_input, psz_time,
371 ( p_intf->p_sys->p_input->stream.p_selected_area->i_size * i_range )
373 vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock );
377 /*****************************************************************************
378 * FileOpen: open a file
379 *****************************************************************************
380 * This function opens a file requester and adds the selected file to
382 *****************************************************************************/
383 void IntfWindow::FileOpen( void )
385 playlist_t *p_playlist;
386 QString file = QFileDialog::getOpenFileName( QString::null,
387 QString::null, this );
391 statusBar()->message( "No file loaded", 2000 );
395 p_playlist = (playlist_t *)
396 vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE );
397 if( p_playlist == NULL )
402 playlist_Add( p_playlist, file.latin1(),
403 PLAYLIST_APPEND | PLAYLIST_GO, PLAYLIST_END );
404 vlc_object_release( p_playlist );
408 /*****************************************************************************
409 * FileQuit: terminate vlc
410 *****************************************************************************/
411 void IntfWindow::FileQuit( void )
413 p_intf->p_vlc->b_die = VLC_TRUE;
416 /*****************************************************************************
417 * About: display the "about" box
418 *****************************************************************************
419 * This function displays a simple "about" box with copyright information.
420 *****************************************************************************/
421 void IntfWindow::About( void )
423 QMessageBox::about( this, "About",
425 "(C) 1996, 1997, 1998, 1999, 2000, 2001, 2002 - the VideoLAN Team\n"
427 "This is the VideoLAN client, a DVD and MPEG player.\n"
428 "It can play MPEG and MPEG 2 files from a file "
429 "or from a network source.\n"
431 "More information: http://www.videolan.org/" );
434 /*****************************************************************************
435 * Manage: manage main thread messages
436 *****************************************************************************
437 * In this function, called approx. 10 times a second, we check what the
438 * main program wanted to tell us.
439 *****************************************************************************/
440 void IntfWindow::Manage( void )
442 /* Update the input */
443 if( p_intf->p_sys->p_input == NULL )
445 p_intf->p_sys->p_input = (input_thread_t *)
446 vlc_object_find( p_intf, VLC_OBJECT_INPUT, FIND_ANYWHERE );
448 else if( p_intf->p_sys->p_input->b_dead )
450 vlc_object_release( p_intf->p_sys->p_input );
451 p_intf->p_sys->p_input = NULL;
454 /* Manage the slider */
455 if( p_intf->p_sys->p_input && p_intf->p_sys->p_input->stream.b_seekable )
457 int i_value = p_slider->value();
459 #define p_area p_intf->p_sys->p_input->stream.p_selected_area
460 /* If the user hasn't touched the slider since the last time,
461 * then the input can safely change it */
462 if( i_value == p_slider->oldvalue() )
464 i_value = ( SLIDER_MAX * p_area->i_tell ) / p_area->i_size;
466 p_slider->setValue( i_value );
467 p_slider->setOldValue( i_value );
469 /* Otherwise, send message to the input if the user has
470 * finished dragging the slider */
471 else if( p_slider->b_free )
473 off_t i_seek = ( i_value * p_area->i_size ) / SLIDER_MAX;
475 input_Seek( p_intf->p_sys->p_input, i_seek, INPUT_SEEK_SET );
477 /* Update the old value */
478 p_slider->setOldValue( i_value );
483 /* If the "display popup" flag has changed, popup the context menu */
484 if( p_intf->b_menu_change )
486 p_popup->popup( QCursor::pos() );
487 p_intf->b_menu_change = 0;
496 /*****************************************************************************
498 *****************************************************************************/
499 void IntfWindow::PlaybackPlay( void )
501 if( p_intf->p_sys->p_input != NULL )
503 input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_PLAY );
507 /*****************************************************************************
508 * PlaybackPause: pause
509 *****************************************************************************/
510 void IntfWindow::PlaybackPause( void )
512 if( p_intf->p_sys->p_input != NULL )
514 input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_PAUSE );
518 /*****************************************************************************
520 *****************************************************************************/
521 void IntfWindow::PlaybackSlow( void )
523 if( p_intf->p_sys->p_input != NULL )
525 input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_SLOWER );
529 /*****************************************************************************
531 *****************************************************************************/
532 void IntfWindow::PlaybackFast( void )
534 if( p_intf->p_sys->p_input != NULL )
536 input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_FASTER );
540 /*****************************************************************************
541 * PlaylistPrev: previous playlist entry
542 *****************************************************************************/
543 void IntfWindow::PlaylistPrev( void )
545 playlist_t *p_playlist = (playlist_t *)
546 vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE );
548 if( p_playlist == NULL )
553 playlist_Prev( p_playlist );
554 vlc_object_release( p_playlist );
557 /*****************************************************************************
558 * PlaylistNext: next playlist entry
559 *****************************************************************************/
560 void IntfWindow::PlaylistNext( void )
562 playlist_t *p_playlist = (playlist_t *)
563 vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE );
565 if( p_playlist == NULL )
570 playlist_Next( p_playlist );
571 vlc_object_release( p_playlist );
574 /*****************************************************************************
575 * IntfSlider: slider creator
576 *****************************************************************************
577 * This function creates the slider, sets its default values, and connects
578 * the interesting signals.
579 *****************************************************************************/
580 IntfSlider::IntfSlider( intf_thread_t *p_intf, QWidget *p_parent )
581 :QSlider( Horizontal, p_parent )
583 this->p_intf = p_intf;
585 setRange( SLIDER_MIN, SLIDER_MAX );
586 setPageStep( SLIDER_STEP );
588 setValue( SLIDER_MIN );
589 setOldValue( SLIDER_MIN );
594 connect( this, SIGNAL(sliderMoved(int)), this, SLOT(SlideStart()) );
595 connect( this, SIGNAL(sliderPressed()), this, SLOT(SlideStart()) );
596 connect( this, SIGNAL(sliderReleased()), this, SLOT(SlideStop()) );
599 /*****************************************************************************
600 * ~IntfSlider: slider destructor
601 *****************************************************************************
602 * This function is called when the interface slider is destroyed.
603 *****************************************************************************/
604 IntfSlider::~IntfSlider( void )
606 /* We don't need to remove anything */