]> git.sesse.net Git - vlc/blob - modules/gui/qt/intf.cpp
e5cb7c971f55ae03768ece1f6af0c9dcd1cc7e09
[vlc] / modules / gui / qt / intf.cpp
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 $
6  *
7  * Authors: Samuel Hocevar <sam@zoy.org>
8  *
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.
13  * 
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.
18  *
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  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include <errno.h>                                                 /* ENOMEM */
28 #include <stdlib.h>                                                /* free() */
29 #include <string.h>                                            /* strerror() */
30 #include <stdio.h>
31
32 #include <vlc/vlc.h>
33 #include <vlc/intf.h>
34
35 #include <qapplication.h>
36 #include <qmainwindow.h>
37 #include <qtoolbar.h>
38 #include <qtoolbutton.h>
39 #include <qwhatsthis.h>
40 #include <qpushbutton.h>
41 #include <qfiledialog.h>
42 #include <qslider.h>
43 #include <qlcdnumber.h>
44 #include <qmenubar.h>
45 #include <qstatusbar.h>
46 #include <qmessagebox.h>
47 #include <qlabel.h> 
48 #include <qtimer.h> 
49 #include <qiconset.h> 
50
51 #include <qvbox.h>
52 #include <qhbox.h>
53
54 /*****************************************************************************
55  * Local Qt slider class
56  *****************************************************************************/
57 class IntfSlider : public QSlider
58 {
59     Q_OBJECT
60
61 public:
62     IntfSlider( intf_thread_t *, QWidget * );  /* Constructor and destructor */
63     ~IntfSlider();
64
65     bool b_free;                                     /* Is the slider free ? */
66
67     int  oldvalue   ( void ) { return i_oldvalue; };
68     void setOldValue( int i_value ) { i_oldvalue = i_value; };
69
70 private slots:
71     void SlideStart ( void ) { b_free = FALSE; };
72     void SlideStop  ( void ) { b_free = TRUE; };
73
74 private:
75     intf_thread_t *p_intf;
76     int  i_oldvalue;
77 };
78
79 /*****************************************************************************
80  * Local Qt interface window class
81  *****************************************************************************/
82 class IntfWindow : public QMainWindow
83 {
84     Q_OBJECT
85
86 public:
87     IntfWindow( intf_thread_t * );
88     ~IntfWindow();
89
90 private slots:
91     void Manage ( void );
92
93     void FileOpen  ( void );
94     void FileQuit  ( void );
95
96     void PlaybackPlay  ( void );
97     void PlaybackPause ( void );
98     void PlaybackSlow  ( void );
99     void PlaybackFast  ( void );
100
101     void PlaylistPrev  ( void );
102     void PlaylistNext  ( void );
103
104     void DateDisplay  ( int );
105     void About ( void );
106
107     void Unimplemented( void ) { msg_Warn( p_intf, "unimplemented" ); };
108
109 private:
110     intf_thread_t *p_intf;
111
112     IntfSlider *p_slider;
113
114     QToolBar   *p_toolbar;
115     QPopupMenu *p_popup;
116     QLabel     *p_date;
117 };
118
119 #include "intf.moc"
120
121 #define SLIDER_MIN    0x00000
122 #define SLIDER_MAX    0x10000
123 #define SLIDER_STEP   (SLIDER_MAX >> 4)
124
125 /*****************************************************************************
126  * intf_sys_t: description and status of Qt interface
127  *****************************************************************************/
128 struct intf_sys_t
129 {
130     QApplication *p_app;
131     IntfWindow   *p_window;
132
133     input_thread_t *p_input;
134 };
135
136 /*****************************************************************************
137  * Local prototype
138  *****************************************************************************/
139 static void Run ( intf_thread_t *p_intf );
140
141 /*****************************************************************************
142  * Open: initialize and create window
143  *****************************************************************************/
144 int E_(Open) ( vlc_object_t *p_this )
145 {
146     intf_thread_t *p_intf = (intf_thread_t*) p_this;
147     char *pp_argv[] = { "" };
148     int   i_argc    = 1;
149
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 )
153     {
154         msg_Err( p_intf, "out of memory" );
155         return 1;
156     }
157
158     p_intf->pf_run = Run;
159
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 );
163
164     /* Tell the world we are here */
165     p_intf->p_sys->p_window->setCaption( VOUT_TITLE " (Qt interface)" );
166
167     p_intf->p_sys->p_input = NULL;
168
169     return 0;
170 }
171
172 /*****************************************************************************
173  * Close: destroy interface window
174  *****************************************************************************/
175 void E_(Close) ( vlc_object_t *p_this )
176 {
177     intf_thread_t *p_intf = (intf_thread_t*) p_this;
178
179     if( p_intf->p_sys->p_input )
180     {
181         vlc_object_release( p_intf->p_sys->p_input );
182     }
183
184     /* Get rid of the C++ objects */
185     delete p_intf->p_sys->p_window;
186     delete p_intf->p_sys->p_app;
187
188     /* Destroy structure */
189     free( p_intf->p_sys );
190 }
191
192 /*****************************************************************************
193  * Run: Qt thread
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 )
199 {
200     p_intf->p_sys->p_window->show();
201
202     p_intf->p_sys->p_app->exec();
203 }
204
205 /* following functions are local */
206
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 )
214            :QMainWindow( 0 )
215 {
216     setUsesTextLabel( TRUE );
217
218     this->p_intf = p_intf;
219
220     /*
221      * Create the toolbar
222      */
223
224     p_toolbar = new QToolBar( this, "toolbar" );
225     p_toolbar->setHorizontalStretchable( TRUE );
226
227     QIconSet * set = new QIconSet();
228     QPixmap pixmap = set->pixmap( QIconSet::Automatic, QIconSet::Normal );
229
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()) );
245 #undef addbut
246
247     /* 
248      * Create the menubar
249      */
250
251     QPopupMenu * p_tmpmenu = new QPopupMenu( this );
252
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 );
261
262     p_tmpmenu = new QPopupMenu( this );
263     menuBar()->insertItem( "&View", p_tmpmenu );
264     instmp0( "&Playlist...", SLOT(Unimplemented()) );
265     instmp0( "&Modules...", SLOT(Unimplemented()) );
266
267     p_tmpmenu = new QPopupMenu( this );
268     menuBar()->insertItem( "&Settings", p_tmpmenu );
269     instmp0( "&Preferences...", SLOT(Unimplemented()) );
270
271     p_tmpmenu = new QPopupMenu( this );
272     menuBar()->insertItem( "&Help", p_tmpmenu );
273     instmp0( "&About...", SLOT(About()) );
274
275     /*
276      * Create the popup menu
277      */
278
279     p_popup = new QPopupMenu( /* floating menu */ );
280
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()) );
294
295     /* Activate the statusbar */
296     statusBar();
297
298     /* Add the vertical box */
299     QVBox * p_vbox = new QVBox( this );
300     setCentralWidget( p_vbox );
301
302         /* The horizontal box */
303         QHBox * p_hbox = new QHBox( p_vbox );
304
305             /* The date label */
306             p_date  = new QLabel( p_hbox );
307             p_date->setAlignment( AlignHCenter | AlignVCenter );
308             p_date->setText( "-:--:--" );
309
310             /* The status label */
311             QLabel *p_label  = new QLabel( p_hbox );
312             p_label->setAlignment( AlignHCenter | AlignVCenter );
313             p_label->setText( "Status: foo" );
314
315             /* The bar label */
316             p_label  = new QLabel( p_hbox );
317             p_label->setAlignment( AlignHCenter | AlignVCenter );
318             p_label->setText( "Bar: baz quux" );
319
320         /* Create the slider and connect it to the date label */
321         p_slider = new IntfSlider( p_intf, p_vbox );
322
323         connect( p_slider, SIGNAL(valueChanged(int)),
324                  this, SLOT(DateDisplay(int)) );
325
326     /* The timer */
327     QTimer *p_timer = new QTimer( this );
328     connect( p_timer, SIGNAL(timeout()), this, SLOT(Manage()) );
329     p_timer->start( INTF_IDLE_SLEEP / 1000 );
330
331     /* Everything worked fine */
332     resize( 620, 30 );
333 }
334
335 /*****************************************************************************
336  * ~IntfWindow: interface window destructor
337  *****************************************************************************
338  * This function is called when the interface window is destroyed.
339  *****************************************************************************/
340 IntfWindow::~IntfWindow( void )
341 {
342     /* FIXME: remove everything cleanly */
343 }
344
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 )
351 {
352     if( p_intf->p_sys->p_input )
353     {
354         char psz_time[ OFFSETTOTIME_MAX_SIZE ];
355
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 )
359                / SLIDER_MAX ) );
360         vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock );
361     }
362 }
363
364 /*****************************************************************************
365  * FileOpen: open a file
366  *****************************************************************************
367  * This function opens a file requester and adds the selected file to
368  * the playlist.
369  *****************************************************************************/
370 void IntfWindow::FileOpen( void )
371 {
372     playlist_t *p_playlist;
373     QString file = QFileDialog::getOpenFileName( QString::null,
374                                                  QString::null, this );
375
376     if( file.isEmpty() )
377     {
378         statusBar()->message( "No file loaded", 2000 );
379     }
380     else
381     {
382         p_playlist = (playlist_t *)
383                 vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE );
384         if( p_playlist == NULL )
385         {
386             return;
387         }
388
389         playlist_Add( p_playlist, file.latin1(),
390                       PLAYLIST_APPEND | PLAYLIST_GO, PLAYLIST_END );
391         vlc_object_release( p_playlist );
392     }
393 }
394
395 /*****************************************************************************
396  * FileQuit: terminate vlc
397  *****************************************************************************/
398 void IntfWindow::FileQuit( void )
399 {
400     p_intf->p_vlc->b_die = VLC_TRUE;
401 }
402
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 )
409 {
410     QMessageBox::about( this, "About",
411         "VideoLAN Client\n"
412         "(C) 1996, 1997, 1998, 1999, 2000, 2001, 2002 - the VideoLAN Team\n"
413         "\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"
417         "\n"
418         "More information: http://www.videolan.org/" );
419 }
420
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 )
428 {
429     /* Update the input */
430     if( p_intf->p_sys->p_input == NULL )
431     {
432         p_intf->p_sys->p_input = (input_thread_t *)
433                 vlc_object_find( p_intf, VLC_OBJECT_INPUT, FIND_ANYWHERE );
434     }
435     else if( p_intf->p_sys->p_input->b_dead )
436     {
437         vlc_object_release( p_intf->p_sys->p_input );
438         p_intf->p_sys->p_input = NULL;
439     }
440
441     /* Manage the slider */
442     if( p_intf->p_sys->p_input && p_intf->p_sys->p_input->stream.b_seekable )
443     {
444         int i_value = p_slider->value();
445
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() )
450         {
451             i_value = ( SLIDER_MAX * p_area->i_tell ) / p_area->i_size;
452
453             p_slider->setValue( i_value );
454             p_slider->setOldValue( i_value );
455         }
456         /* Otherwise, send message to the input if the user has
457          * finished dragging the slider */
458         else if( p_slider->b_free )
459         {
460             off_t i_seek = ( i_value * p_area->i_size ) / SLIDER_MAX;
461
462             input_Seek( p_intf->p_sys->p_input, i_seek, INPUT_SEEK_SET );
463
464             /* Update the old value */
465             p_slider->setOldValue( i_value );
466         }
467 #undef p_area
468     }
469
470     /* If the "display popup" flag has changed, popup the context menu */
471     if( p_intf->b_menu_change )
472     {
473         p_popup->popup( QCursor::pos() );
474         p_intf->b_menu_change = 0;
475     }
476
477     if( p_intf->b_die )
478     {
479         qApp->quit();
480     }
481 }
482
483 /*****************************************************************************
484  * PlaybackPlay: play
485  *****************************************************************************/
486 void IntfWindow::PlaybackPlay( void )
487 {
488     if( p_intf->p_sys->p_input != NULL )
489     {
490         input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_PLAY );
491     }
492 }
493
494 /*****************************************************************************
495  * PlaybackPause: pause
496  *****************************************************************************/
497 void IntfWindow::PlaybackPause( void )
498 {
499     if( p_intf->p_sys->p_input != NULL )
500     {
501         input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_PAUSE );
502     }
503 }
504
505 /*****************************************************************************
506  * PlaybackSlow: slow
507  *****************************************************************************/
508 void IntfWindow::PlaybackSlow( void )
509 {
510     if( p_intf->p_sys->p_input != NULL )
511     {
512         input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_SLOWER );
513     }
514 }
515
516 /*****************************************************************************
517  * PlaybackFast: fast
518  *****************************************************************************/
519 void IntfWindow::PlaybackFast( void )
520 {
521     if( p_intf->p_sys->p_input != NULL )
522     {
523         input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_FASTER );
524     }
525 }
526
527 /*****************************************************************************
528  * PlaylistPrev: previous playlist entry
529  *****************************************************************************/
530 void IntfWindow::PlaylistPrev( void )
531 {
532     playlist_t *p_playlist = (playlist_t *)
533         vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE );
534
535     if( p_playlist == NULL )
536     {
537         return;
538     }
539
540     playlist_Prev( p_playlist );
541     vlc_object_release( p_playlist );
542 }
543
544 /*****************************************************************************
545  * PlaylistNext: next playlist entry
546  *****************************************************************************/
547 void IntfWindow::PlaylistNext( void )
548 {
549     playlist_t *p_playlist = (playlist_t *)
550         vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE );
551
552     if( p_playlist == NULL )
553     {
554         return;
555     }
556
557     playlist_Next( p_playlist );
558     vlc_object_release( p_playlist );
559 }
560
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 )
569 {
570     this->p_intf = p_intf;
571
572     setRange( SLIDER_MIN, SLIDER_MAX );
573     setPageStep( SLIDER_STEP );
574
575     setValue( SLIDER_MIN );
576     setOldValue( SLIDER_MIN );
577
578     setTracking( TRUE );
579     b_free = TRUE;
580
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()) );
584 }
585
586 /*****************************************************************************
587  * ~IntfSlider: slider destructor
588  *****************************************************************************
589  * This function is called when the interface slider is destroyed.
590  *****************************************************************************/
591 IntfSlider::~IntfSlider( void )
592 {
593     /* We don't need to remove anything */
594 }
595
596