]> git.sesse.net Git - vlc/blob - plugins/qt/intf_qt.cpp
d4a28ae7d880e5e22329242247c7d0077a08a941
[vlc] / plugins / qt / intf_qt.cpp
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 $
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_qt.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 prototypes.
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 );
142
143 /*****************************************************************************
144  * Functions exported as capabilities. They are declared as static so that
145  * we don't pollute the namespace too much.
146  *****************************************************************************/
147 extern "C"
148 {
149
150 void _M( intf_getfunctions )( function_list_t * p_function_list )
151 {
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;
155 }
156
157 }
158
159 /*****************************************************************************
160  * intf_Open: initialize and create window
161  *****************************************************************************/
162 static int intf_Open( intf_thread_t *p_intf )
163 {
164     char *pp_argv[] = { "" };
165     int   i_argc    = 1;
166
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 )
170     {
171         msg_Err( p_intf, "out of memory" );
172         return 1;
173     }
174
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 );
178
179     /* Tell the world we are here */
180     p_intf->p_sys->p_window->setCaption( VOUT_TITLE " (Qt interface)" );
181
182     p_intf->p_sys->p_input = NULL;
183
184     return 0;
185 }
186
187 /*****************************************************************************
188  * intf_Close: destroy interface window
189  *****************************************************************************/
190 static void intf_Close( intf_thread_t *p_intf )
191 {
192     if( p_intf->p_sys->p_input )
193     {
194         vlc_object_release( p_intf->p_sys->p_input );
195     }
196
197     /* Get rid of the C++ objects */
198     delete p_intf->p_sys->p_window;
199     delete p_intf->p_sys->p_app;
200
201     /* Destroy structure */
202     free( p_intf->p_sys );
203 }
204
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 )
212 {
213     p_intf->p_sys->p_window->show();
214
215     p_intf->p_sys->p_app->exec();
216 }
217
218 /* following functions are local */
219
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 )
227            :QMainWindow( 0 )
228 {
229     setUsesTextLabel( TRUE );
230
231     this->p_intf = p_intf;
232
233     /*
234      * Create the toolbar
235      */
236
237     p_toolbar = new QToolBar( this, "toolbar" );
238     p_toolbar->setHorizontalStretchable( TRUE );
239
240     QIconSet * set = new QIconSet();
241     QPixmap pixmap = set->pixmap( QIconSet::Automatic, QIconSet::Normal );
242
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()) );
258 #undef addbut
259
260     /* 
261      * Create the menubar
262      */
263
264     QPopupMenu * p_tmpmenu = new QPopupMenu( this );
265
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 );
273
274     p_tmpmenu = new QPopupMenu( this );
275     menuBar()->insertItem( "&View", p_tmpmenu );
276     instmp( "&Playlist...", SLOT(Unimplemented()) );
277     instmp( "&Modules...", SLOT(Unimplemented()) );
278
279     p_tmpmenu = new QPopupMenu( this );
280     menuBar()->insertItem( "&Settings", p_tmpmenu );
281     instmp( "&Preferences...", SLOT(Unimplemented()) );
282
283     p_tmpmenu = new QPopupMenu( this );
284     menuBar()->insertItem( "&Help", p_tmpmenu );
285     instmp( "&About...", SLOT(About()) );
286 #undef instmp
287
288     /*
289      * Create the popup menu
290      */
291
292     p_popup = new QPopupMenu( /* floating menu */ );
293
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()) );
306 #undef inspop
307
308     /* Activate the statusbar */
309     statusBar();
310
311     /* Add the vertical box */
312     QVBox * p_vbox = new QVBox( this );
313     setCentralWidget( p_vbox );
314
315         /* The horizontal box */
316         QHBox * p_hbox = new QHBox( p_vbox );
317
318             /* The date label */
319             p_date  = new QLabel( p_hbox );
320             p_date->setAlignment( AlignHCenter | AlignVCenter );
321             p_date->setText( "-:--:--" );
322
323             /* The status label */
324             QLabel *p_label  = new QLabel( p_hbox );
325             p_label->setAlignment( AlignHCenter | AlignVCenter );
326             p_label->setText( "Status: foo" );
327
328             /* The bar label */
329             p_label  = new QLabel( p_hbox );
330             p_label->setAlignment( AlignHCenter | AlignVCenter );
331             p_label->setText( "Bar: baz quux" );
332
333         /* Create the slider and connect it to the date label */
334         p_slider = new IntfSlider( p_intf, p_vbox );
335
336         connect( p_slider, SIGNAL(valueChanged(int)),
337                  this, SLOT(DateDisplay(int)) );
338
339     /* The timer */
340     QTimer *p_timer = new QTimer( this );
341     connect( p_timer, SIGNAL(timeout()), this, SLOT(Manage()) );
342     p_timer->start( INTF_IDLE_SLEEP / 1000 );
343
344     /* Everything worked fine */
345     resize( 620, 30 );
346 }
347
348 /*****************************************************************************
349  * ~IntfWindow: interface window destructor
350  *****************************************************************************
351  * This function is called when the interface window is destroyed.
352  *****************************************************************************/
353 IntfWindow::~IntfWindow( void )
354 {
355     /* FIXME: remove everything cleanly */
356 }
357
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 )
364 {
365     if( p_intf->p_sys->p_input )
366     {
367         char psz_time[ OFFSETTOTIME_MAX_SIZE ];
368
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 )
372                / SLIDER_MAX ) );
373         vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock );
374     }
375 }
376
377 /*****************************************************************************
378  * FileOpen: open a file
379  *****************************************************************************
380  * This function opens a file requester and adds the selected file to
381  * the playlist.
382  *****************************************************************************/
383 void IntfWindow::FileOpen( void )
384 {
385     playlist_t *p_playlist;
386     QString file = QFileDialog::getOpenFileName( QString::null,
387                                                  QString::null, this );
388
389     if( file.isEmpty() )
390     {
391         statusBar()->message( "No file loaded", 2000 );
392     }
393     else
394     {
395         p_playlist = (playlist_t *)
396                 vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE );
397         if( p_playlist == NULL )
398         {
399             return;
400         }
401
402         playlist_Add( p_playlist, file.latin1(),
403                       PLAYLIST_APPEND | PLAYLIST_GO, PLAYLIST_END );
404         vlc_object_release( p_playlist );
405     }
406 }
407
408 /*****************************************************************************
409  * FileQuit: terminate vlc
410  *****************************************************************************/
411 void IntfWindow::FileQuit( void )
412 {
413     p_intf->p_vlc->b_die = VLC_TRUE;
414 }
415
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 )
422 {
423     QMessageBox::about( this, "About",
424         "VideoLAN Client\n"
425         "(C) 1996, 1997, 1998, 1999, 2000, 2001, 2002 - the VideoLAN Team\n"
426         "\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"
430         "\n"
431         "More information: http://www.videolan.org/" );
432 }
433
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 )
441 {
442     /* Update the input */
443     if( p_intf->p_sys->p_input == NULL )
444     {
445         p_intf->p_sys->p_input = (input_thread_t *)
446                 vlc_object_find( p_intf, VLC_OBJECT_INPUT, FIND_ANYWHERE );
447     }
448     else if( p_intf->p_sys->p_input->b_dead )
449     {
450         vlc_object_release( p_intf->p_sys->p_input );
451         p_intf->p_sys->p_input = NULL;
452     }
453
454     /* Manage the slider */
455     if( p_intf->p_sys->p_input && p_intf->p_sys->p_input->stream.b_seekable )
456     {
457         int i_value = p_slider->value();
458
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() )
463         {
464             i_value = ( SLIDER_MAX * p_area->i_tell ) / p_area->i_size;
465
466             p_slider->setValue( i_value );
467             p_slider->setOldValue( i_value );
468         }
469         /* Otherwise, send message to the input if the user has
470          * finished dragging the slider */
471         else if( p_slider->b_free )
472         {
473             off_t i_seek = ( i_value * p_area->i_size ) / SLIDER_MAX;
474
475             input_Seek( p_intf->p_sys->p_input, i_seek, INPUT_SEEK_SET );
476
477             /* Update the old value */
478             p_slider->setOldValue( i_value );
479         }
480 #undef p_area
481     }
482
483     /* If the "display popup" flag has changed, popup the context menu */
484     if( p_intf->b_menu_change )
485     {
486         p_popup->popup( QCursor::pos() );
487         p_intf->b_menu_change = 0;
488     }
489
490     if( p_intf->b_die )
491     {
492         qApp->quit();
493     }
494 }
495
496 /*****************************************************************************
497  * PlaybackPlay: play
498  *****************************************************************************/
499 void IntfWindow::PlaybackPlay( void )
500 {
501     if( p_intf->p_sys->p_input != NULL )
502     {
503         input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_PLAY );
504     }
505 }
506
507 /*****************************************************************************
508  * PlaybackPause: pause
509  *****************************************************************************/
510 void IntfWindow::PlaybackPause( void )
511 {
512     if( p_intf->p_sys->p_input != NULL )
513     {
514         input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_PAUSE );
515     }
516 }
517
518 /*****************************************************************************
519  * PlaybackSlow: slow
520  *****************************************************************************/
521 void IntfWindow::PlaybackSlow( void )
522 {
523     if( p_intf->p_sys->p_input != NULL )
524     {
525         input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_SLOWER );
526     }
527 }
528
529 /*****************************************************************************
530  * PlaybackFast: fast
531  *****************************************************************************/
532 void IntfWindow::PlaybackFast( void )
533 {
534     if( p_intf->p_sys->p_input != NULL )
535     {
536         input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_FASTER );
537     }
538 }
539
540 /*****************************************************************************
541  * PlaylistPrev: previous playlist entry
542  *****************************************************************************/
543 void IntfWindow::PlaylistPrev( void )
544 {
545     playlist_t *p_playlist = (playlist_t *)
546         vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE );
547
548     if( p_playlist == NULL )
549     {
550         return;
551     }
552
553     playlist_Prev( p_playlist );
554     vlc_object_release( p_playlist );
555 }
556
557 /*****************************************************************************
558  * PlaylistNext: next playlist entry
559  *****************************************************************************/
560 void IntfWindow::PlaylistNext( void )
561 {
562     playlist_t *p_playlist = (playlist_t *)
563         vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE );
564
565     if( p_playlist == NULL )
566     {
567         return;
568     }
569
570     playlist_Next( p_playlist );
571     vlc_object_release( p_playlist );
572 }
573
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 )
582 {
583     this->p_intf = p_intf;
584
585     setRange( SLIDER_MIN, SLIDER_MAX );
586     setPageStep( SLIDER_STEP );
587
588     setValue( SLIDER_MIN );
589     setOldValue( SLIDER_MIN );
590
591     setTracking( TRUE );
592     b_free = TRUE;
593
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()) );
597 }
598
599 /*****************************************************************************
600  * ~IntfSlider: slider destructor
601  *****************************************************************************
602  * This function is called when the interface slider is destroyed.
603  *****************************************************************************/
604 IntfSlider::~IntfSlider( void )
605 {
606     /* We don't need to remove anything */
607 }
608
609