1 /*****************************************************************************
2 * intf.cpp: Qt interface
3 *****************************************************************************
4 * Copyright (C) 1999, 2000 VideoLAN
5 * $Id: intf.cpp,v 1.2 2002/08/08 22:28:22 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;
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 void Run ( intf_thread_t *p_intf );
141 /*****************************************************************************
142 * Open: initialize and create window
143 *****************************************************************************/
144 int E_(Open) ( vlc_object_t *p_this )
146 intf_thread_t *p_intf = (intf_thread_t*) p_this;
147 char *pp_argv[] = { "" };
150 /* Allocate instance and initialize some members */
151 p_intf->p_sys = (intf_sys_t *)malloc( sizeof( intf_sys_t ) );
152 if( p_intf->p_sys == NULL )
154 msg_Err( p_intf, "out of memory" );
158 p_intf->pf_run = Run;
160 /* Create the C++ objects */
161 p_intf->p_sys->p_app = new QApplication( i_argc, pp_argv );
162 p_intf->p_sys->p_window = new IntfWindow( p_intf );
164 /* Tell the world we are here */
165 p_intf->p_sys->p_window->setCaption( VOUT_TITLE " (Qt interface)" );
167 p_intf->p_sys->p_input = NULL;
172 /*****************************************************************************
173 * Close: destroy interface window
174 *****************************************************************************/
175 void E_(Close) ( vlc_object_t *p_this )
177 intf_thread_t *p_intf = (intf_thread_t*) p_this;
179 if( p_intf->p_sys->p_input )
181 vlc_object_release( p_intf->p_sys->p_input );
184 /* Get rid of the C++ objects */
185 delete p_intf->p_sys->p_window;
186 delete p_intf->p_sys->p_app;
188 /* Destroy structure */
189 free( p_intf->p_sys );
192 /*****************************************************************************
194 *****************************************************************************
195 * This part of the interface is in a separate thread so that we can call
196 * exec() from within it without annoying the rest of the program.
197 *****************************************************************************/
198 static void Run( intf_thread_t *p_intf )
200 p_intf->p_sys->p_window->show();
202 p_intf->p_sys->p_app->exec();
205 /* following functions are local */
207 /*****************************************************************************
208 * IntfWindow: interface window creator
209 *****************************************************************************
210 * This function creates the interface window, and populates it with a
211 * menu bar, a toolbar and a slider.
212 *****************************************************************************/
213 IntfWindow::IntfWindow( intf_thread_t *p_intf )
216 setUsesTextLabel( TRUE );
218 this->p_intf = p_intf;
224 p_toolbar = new QToolBar( this, "toolbar" );
225 p_toolbar->setHorizontalStretchable( TRUE );
227 QIconSet * set = new QIconSet();
228 QPixmap pixmap = set->pixmap( QIconSet::Automatic, QIconSet::Normal );
230 #define addbut( l, t, s ) new QToolButton( pixmap, l, t, this, s, p_toolbar );
231 addbut( "Open", "Open a File", SLOT(FileOpen()) );
232 addbut( "Disc", "Open a DVD or VCD", SLOT(Unimplemented()) );
233 addbut( "Net", "Select a Network Stream", SLOT(Unimplemented()) );
234 p_toolbar->addSeparator();
235 addbut( "Back", "Rewind Stream", SLOT(Unimplemented()) );
236 addbut( "Stop", "Stop Stream", SLOT(Unimplemented()) );
237 addbut( "Play", "Play Stream", SLOT(PlaybackPlay()) );
238 addbut( "Pause", "Pause Stream", SLOT(PlaybackPause()) );
239 addbut( "Slow", "Play Slower", SLOT(PlaybackSlow()) );
240 addbut( "Fast", "Play Faster", SLOT(PlaybackFast()) );
241 p_toolbar->addSeparator();
242 addbut( "Playlist", "Open Playlist", SLOT(Unimplemented()) );
243 addbut( "Prev", "Previous File", SLOT(PlaylistPrev()) );
244 addbut( "Next", "Next File", SLOT(PlaylistNext()) );
251 QPopupMenu * p_tmpmenu = new QPopupMenu( this );
253 #define instmp0( x, y ) p_tmpmenu->insertItem( x, this, y )
254 #define instmp1( x, y, a ) p_tmpmenu->insertItem( x, this, y, a )
255 menuBar()->insertItem( "&File", p_tmpmenu );
256 instmp1( "&Open File...", SLOT(FileOpen()), Key_F3 );
257 instmp1( "Open &Disc...", SLOT(Unimplemented()), Key_F4 );
258 instmp1( "&Network Stream...", SLOT(Unimplemented()), Key_F5 );
259 p_tmpmenu->insertSeparator();
260 instmp1( "&Exit", SLOT(FileQuit()), CTRL+Key_Q );
262 p_tmpmenu = new QPopupMenu( this );
263 menuBar()->insertItem( "&View", p_tmpmenu );
264 instmp0( "&Playlist...", SLOT(Unimplemented()) );
265 instmp0( "&Modules...", SLOT(Unimplemented()) );
267 p_tmpmenu = new QPopupMenu( this );
268 menuBar()->insertItem( "&Settings", p_tmpmenu );
269 instmp0( "&Preferences...", SLOT(Unimplemented()) );
271 p_tmpmenu = new QPopupMenu( this );
272 menuBar()->insertItem( "&Help", p_tmpmenu );
273 instmp0( "&About...", SLOT(About()) );
276 * Create the popup menu
279 p_popup = new QPopupMenu( /* floating menu */ );
281 #define inspop0( x, y ) p_popup->insertItem( x, this, y )
282 #define inspop1( x, y, a ) p_popup->insertItem( x, this, y, a )
283 inspop0( "&Play", SLOT(PlaybackPlay()) );
284 inspop0( "Pause", SLOT(PlaybackPause()) );
285 inspop0( "&Slow", SLOT(PlaybackSlow()) );
286 inspop0( "&Fast", SLOT(PlaybackFast()) );
287 p_popup->insertSeparator();
288 inspop1( "&Open File...", SLOT(FileOpen()), Key_F3 );
289 inspop1( "Open &Disc...", SLOT(Unimplemented()), Key_F4 );
290 inspop1( "&Network Stream...", SLOT(Unimplemented()), Key_F5 );
291 p_popup->insertSeparator();
292 inspop0( "&About...", SLOT(About()) );
293 inspop0( "&Exit", SLOT(FileQuit()) );
295 /* Activate the statusbar */
298 /* Add the vertical box */
299 QVBox * p_vbox = new QVBox( this );
300 setCentralWidget( p_vbox );
302 /* The horizontal box */
303 QHBox * p_hbox = new QHBox( p_vbox );
306 p_date = new QLabel( p_hbox );
307 p_date->setAlignment( AlignHCenter | AlignVCenter );
308 p_date->setText( "-:--:--" );
310 /* The status label */
311 QLabel *p_label = new QLabel( p_hbox );
312 p_label->setAlignment( AlignHCenter | AlignVCenter );
313 p_label->setText( "Status: foo" );
316 p_label = new QLabel( p_hbox );
317 p_label->setAlignment( AlignHCenter | AlignVCenter );
318 p_label->setText( "Bar: baz quux" );
320 /* Create the slider and connect it to the date label */
321 p_slider = new IntfSlider( p_intf, p_vbox );
323 connect( p_slider, SIGNAL(valueChanged(int)),
324 this, SLOT(DateDisplay(int)) );
327 QTimer *p_timer = new QTimer( this );
328 connect( p_timer, SIGNAL(timeout()), this, SLOT(Manage()) );
329 p_timer->start( INTF_IDLE_SLEEP / 1000 );
331 /* Everything worked fine */
335 /*****************************************************************************
336 * ~IntfWindow: interface window destructor
337 *****************************************************************************
338 * This function is called when the interface window is destroyed.
339 *****************************************************************************/
340 IntfWindow::~IntfWindow( void )
342 /* FIXME: remove everything cleanly */
345 /*****************************************************************************
346 * DateDisplay: display date
347 *****************************************************************************
348 * This function displays the current date in the date label.
349 *****************************************************************************/
350 void IntfWindow::DateDisplay( int i_range )
352 if( p_intf->p_sys->p_input )
354 char psz_time[ OFFSETTOTIME_MAX_SIZE ];
356 vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock );
357 p_date->setText( input_OffsetToTime( p_intf->p_sys->p_input, psz_time,
358 ( p_intf->p_sys->p_input->stream.p_selected_area->i_size * i_range )
360 vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock );
364 /*****************************************************************************
365 * FileOpen: open a file
366 *****************************************************************************
367 * This function opens a file requester and adds the selected file to
369 *****************************************************************************/
370 void IntfWindow::FileOpen( void )
372 playlist_t *p_playlist;
373 QString file = QFileDialog::getOpenFileName( QString::null,
374 QString::null, this );
378 statusBar()->message( "No file loaded", 2000 );
382 p_playlist = (playlist_t *)
383 vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE );
384 if( p_playlist == NULL )
389 playlist_Add( p_playlist, file.latin1(),
390 PLAYLIST_APPEND | PLAYLIST_GO, PLAYLIST_END );
391 vlc_object_release( p_playlist );
395 /*****************************************************************************
396 * FileQuit: terminate vlc
397 *****************************************************************************/
398 void IntfWindow::FileQuit( void )
400 p_intf->p_vlc->b_die = VLC_TRUE;
403 /*****************************************************************************
404 * About: display the "about" box
405 *****************************************************************************
406 * This function displays a simple "about" box with copyright information.
407 *****************************************************************************/
408 void IntfWindow::About( void )
410 QMessageBox::about( this, "About",
412 "(C) 1996, 1997, 1998, 1999, 2000, 2001, 2002 - the VideoLAN Team\n"
414 "This is the VideoLAN client, a DVD and MPEG player.\n"
415 "It can play MPEG and MPEG 2 files from a file "
416 "or from a network source.\n"
418 "More information: http://www.videolan.org/" );
421 /*****************************************************************************
422 * Manage: manage main thread messages
423 *****************************************************************************
424 * In this function, called approx. 10 times a second, we check what the
425 * main program wanted to tell us.
426 *****************************************************************************/
427 void IntfWindow::Manage( void )
429 /* Update the input */
430 if( p_intf->p_sys->p_input == NULL )
432 p_intf->p_sys->p_input = (input_thread_t *)
433 vlc_object_find( p_intf, VLC_OBJECT_INPUT, FIND_ANYWHERE );
435 else if( p_intf->p_sys->p_input->b_dead )
437 vlc_object_release( p_intf->p_sys->p_input );
438 p_intf->p_sys->p_input = NULL;
441 /* Manage the slider */
442 if( p_intf->p_sys->p_input && p_intf->p_sys->p_input->stream.b_seekable )
444 int i_value = p_slider->value();
446 #define p_area p_intf->p_sys->p_input->stream.p_selected_area
447 /* If the user hasn't touched the slider since the last time,
448 * then the input can safely change it */
449 if( i_value == p_slider->oldvalue() )
451 i_value = ( SLIDER_MAX * p_area->i_tell ) / p_area->i_size;
453 p_slider->setValue( i_value );
454 p_slider->setOldValue( i_value );
456 /* Otherwise, send message to the input if the user has
457 * finished dragging the slider */
458 else if( p_slider->b_free )
460 off_t i_seek = ( i_value * p_area->i_size ) / SLIDER_MAX;
462 input_Seek( p_intf->p_sys->p_input, i_seek, INPUT_SEEK_SET );
464 /* Update the old value */
465 p_slider->setOldValue( i_value );
470 /* If the "display popup" flag has changed, popup the context menu */
471 if( p_intf->b_menu_change )
473 p_popup->popup( QCursor::pos() );
474 p_intf->b_menu_change = 0;
483 /*****************************************************************************
485 *****************************************************************************/
486 void IntfWindow::PlaybackPlay( void )
488 if( p_intf->p_sys->p_input != NULL )
490 input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_PLAY );
494 /*****************************************************************************
495 * PlaybackPause: pause
496 *****************************************************************************/
497 void IntfWindow::PlaybackPause( void )
499 if( p_intf->p_sys->p_input != NULL )
501 input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_PAUSE );
505 /*****************************************************************************
507 *****************************************************************************/
508 void IntfWindow::PlaybackSlow( void )
510 if( p_intf->p_sys->p_input != NULL )
512 input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_SLOWER );
516 /*****************************************************************************
518 *****************************************************************************/
519 void IntfWindow::PlaybackFast( void )
521 if( p_intf->p_sys->p_input != NULL )
523 input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_FASTER );
527 /*****************************************************************************
528 * PlaylistPrev: previous playlist entry
529 *****************************************************************************/
530 void IntfWindow::PlaylistPrev( void )
532 playlist_t *p_playlist = (playlist_t *)
533 vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE );
535 if( p_playlist == NULL )
540 playlist_Prev( p_playlist );
541 vlc_object_release( p_playlist );
544 /*****************************************************************************
545 * PlaylistNext: next playlist entry
546 *****************************************************************************/
547 void IntfWindow::PlaylistNext( void )
549 playlist_t *p_playlist = (playlist_t *)
550 vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE );
552 if( p_playlist == NULL )
557 playlist_Next( p_playlist );
558 vlc_object_release( p_playlist );
561 /*****************************************************************************
562 * IntfSlider: slider creator
563 *****************************************************************************
564 * This function creates the slider, sets its default values, and connects
565 * the interesting signals.
566 *****************************************************************************/
567 IntfSlider::IntfSlider( intf_thread_t *p_intf, QWidget *p_parent )
568 :QSlider( Horizontal, p_parent )
570 this->p_intf = p_intf;
572 setRange( SLIDER_MIN, SLIDER_MAX );
573 setPageStep( SLIDER_STEP );
575 setValue( SLIDER_MIN );
576 setOldValue( SLIDER_MIN );
581 connect( this, SIGNAL(sliderMoved(int)), this, SLOT(SlideStart()) );
582 connect( this, SIGNAL(sliderPressed()), this, SLOT(SlideStart()) );
583 connect( this, SIGNAL(sliderReleased()), this, SLOT(SlideStop()) );
586 /*****************************************************************************
587 * ~IntfSlider: slider destructor
588 *****************************************************************************
589 * This function is called when the interface slider is destroyed.
590 *****************************************************************************/
591 IntfSlider::~IntfSlider( void )
593 /* We don't need to remove anything */