]> git.sesse.net Git - vlc/blob - plugins/qt/intf_qt.cpp
* ALL: got rid of *_Probe functions because most of them were duplicates
[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.12 2002/02/15 13:32:53 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 extern "C"
25 {
26
27 /*****************************************************************************
28  * Preamble
29  *****************************************************************************/
30 #include <errno.h>                                                 /* ENOMEM */
31 #include <stdlib.h>                                                /* free() */
32 #include <string.h>                                            /* strerror() */
33 #include <stdio.h>
34
35 #include <videolan/vlc.h>
36
37 #include "stream_control.h"
38 #include "input_ext-intf.h"
39
40 #include "intf_playlist.h"
41 #include "interface.h"
42
43 } /* extern "C" */
44
45 #include <qapplication.h>
46 #include <qmainwindow.h>
47 #include <qtoolbar.h>
48 #include <qtoolbutton.h>
49 #include <qwhatsthis.h>
50 #include <qpushbutton.h>
51 #include <qfiledialog.h>
52 #include <qslider.h>
53 #include <qlcdnumber.h>
54 #include <qmenubar.h>
55 #include <qstatusbar.h>
56 #include <qmessagebox.h>
57 #include <qlabel.h> 
58 #include <qtimer.h> 
59 #include <qiconset.h> 
60
61 #include <qvbox.h>
62 #include <qhbox.h>
63
64 /*****************************************************************************
65  * Local Qt slider class
66  *****************************************************************************/
67 class IntfSlider : public QSlider
68 {
69     Q_OBJECT
70
71 public:
72     IntfSlider( intf_thread_t *, QWidget * );  /* Constructor and destructor */
73     ~IntfSlider();
74
75     bool b_free;                                     /* Is the slider free ? */
76
77     int  oldvalue   ( void ) { return i_oldvalue; };
78     void setOldValue( int i_value ) { i_oldvalue = i_value; };
79
80 private slots:
81     void SlideStart ( void ) { b_free = FALSE; };
82     void SlideStop  ( void ) { b_free = TRUE; };
83
84 private:
85     intf_thread_t *p_intf;
86     int  i_oldvalue;
87 };
88
89 /*****************************************************************************
90  * Local Qt interface window class
91  *****************************************************************************/
92 class IntfWindow : public QMainWindow
93 {
94     Q_OBJECT
95
96 public:
97     IntfWindow( intf_thread_t * );
98     ~IntfWindow();
99
100 private slots:
101     void Manage( void );
102
103     void FileOpen  ( void );
104     void FileQuit  ( void ) { qApp->quit(); };
105
106     void PlaybackPlay  ( void );
107     void PlaybackPause ( void );
108     void PlaybackSlow  ( void );
109     void PlaybackFast  ( void );
110
111     void PlaylistPrev  ( void );
112     void PlaylistNext  ( void );
113
114     void DateDisplay  ( int );
115     void About ( void );
116
117     void Unimplemented( void ) { intf_WarnMsg( 1, "intf warning: "
118                                  "unimplemented function" ); };
119
120 private:
121     intf_thread_t *p_intf;
122
123     IntfSlider *p_slider;
124
125     QToolBar   *p_toolbar;
126     QPopupMenu *p_popup;
127     QLabel     *p_date;
128 };
129
130 #include "intf_qt.moc"
131
132 #define SLIDER_MIN    0x00000
133 #define SLIDER_MAX    0x10000
134 #define SLIDER_STEP   (SLIDER_MAX >> 4)
135
136 /*****************************************************************************
137  * intf_sys_t: description and status of Qt interface
138  *****************************************************************************/
139 typedef struct intf_sys_s
140 {
141     QApplication *p_app;
142     IntfWindow   *p_window;
143
144 } intf_sys_t;
145
146 /*****************************************************************************
147  * Local prototypes.
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 );
152
153 /*****************************************************************************
154  * Functions exported as capabilities. They are declared as static so that
155  * we don't pollute the namespace too much.
156  *****************************************************************************/
157 extern "C"
158 {
159
160 void _M( intf_getfunctions )( function_list_t * p_function_list )
161 {
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;
165 }
166
167 }
168
169 /*****************************************************************************
170  * intf_Open: initialize and create window
171  *****************************************************************************/
172 static int intf_Open( intf_thread_t *p_intf )
173 {
174     char *pp_argv[] = { "" };
175     int   i_argc    = 1;
176
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 )
180     {
181         intf_ErrMsg( "intf error: %s", strerror(ENOMEM) );
182         return( 1 );
183     }
184
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 );
188
189     /* Tell the world we are here */
190     p_intf->p_sys->p_window->setCaption( VOUT_TITLE " (Qt interface)" );
191
192     return( 0 );
193 }
194
195 /*****************************************************************************
196  * intf_Close: destroy interface window
197  *****************************************************************************/
198 static void intf_Close( intf_thread_t *p_intf )
199 {
200     /* Get rid of the C++ objects */
201     delete p_intf->p_sys->p_window;
202     delete p_intf->p_sys->p_app;
203
204     /* Destroy structure */
205     free( p_intf->p_sys );
206 }
207
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 )
215 {
216     p_intf->p_sys->p_window->show();
217
218     p_intf->p_sys->p_app->exec();
219 }
220
221 /* following functions are local */
222
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 )
230            :QMainWindow( 0 )
231 {
232     setUsesTextLabel( TRUE );
233
234     this->p_intf = p_intf;
235
236     /*
237      * Create the toolbar
238      */
239
240     p_toolbar = new QToolBar( this, "toolbar" );
241     p_toolbar->setHorizontalStretchable( TRUE );
242
243     QIconSet * set = new QIconSet();
244     QPixmap pixmap = set->pixmap( QIconSet::Automatic, QIconSet::Normal );
245
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()) );
261 #undef addbut
262
263     /* 
264      * Create the menubar
265      */
266
267     QPopupMenu * p_tmpmenu = new QPopupMenu( this );
268
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 );
276
277     p_tmpmenu = new QPopupMenu( this );
278     menuBar()->insertItem( "&View", p_tmpmenu );
279     instmp( "&Playlist...", SLOT(Unimplemented()) );
280     instmp( "&Modules...", SLOT(Unimplemented()) );
281
282     p_tmpmenu = new QPopupMenu( this );
283     menuBar()->insertItem( "&Settings", p_tmpmenu );
284     instmp( "&Preferences...", SLOT(Unimplemented()) );
285
286     p_tmpmenu = new QPopupMenu( this );
287     menuBar()->insertItem( "&Help", p_tmpmenu );
288     instmp( "&About...", SLOT(About()) );
289 #undef instmp
290
291     /*
292      * Create the popup menu
293      */
294
295     p_popup = new QPopupMenu( /* floating menu */ );
296
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()) );
309 #undef inspop
310
311     /* Activate the statusbar */
312     statusBar();
313
314     /* Add the vertical box */
315     QVBox * p_vbox = new QVBox( this );
316     setCentralWidget( p_vbox );
317
318         /* The horizontal box */
319         QHBox * p_hbox = new QHBox( p_vbox );
320
321             /* The date label */
322             p_date  = new QLabel( p_hbox );
323             p_date->setAlignment( AlignHCenter | AlignVCenter );
324             p_date->setText( "-:--:--" );
325
326             /* The status label */
327             QLabel *p_label  = new QLabel( p_hbox );
328             p_label->setAlignment( AlignHCenter | AlignVCenter );
329             p_label->setText( "Status: foo" );
330
331             /* The bar label */
332             p_label  = new QLabel( p_hbox );
333             p_label->setAlignment( AlignHCenter | AlignVCenter );
334             p_label->setText( "Bar: baz quux" );
335
336         /* Create the slider and connect it to the date label */
337         p_slider = new IntfSlider( p_intf, p_vbox );
338
339         connect( p_slider, SIGNAL(valueChanged(int)),
340                  this, SLOT(DateDisplay(int)) );
341
342     /* The timer */
343     QTimer *p_timer = new QTimer( this );
344     connect( p_timer, SIGNAL(timeout()), this, SLOT(Manage()) );
345     p_timer->start( INTF_IDLE_SLEEP / 1000 );
346
347     /* Everything worked fine */
348     resize( 620, 30 );
349 }
350
351 /*****************************************************************************
352  * ~IntfWindow: interface window destructor
353  *****************************************************************************
354  * This function is called when the interface window is destroyed.
355  *****************************************************************************/
356 IntfWindow::~IntfWindow( void )
357 {
358     /* FIXME: remove everything cleanly */
359 }
360
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 )
367 {
368     if( p_input_bank->pp_input[0] != NULL )
369     {
370         char psz_time[ OFFSETTOTIME_MAX_SIZE ];
371
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 )
375                    / SLIDER_MAX ) );
376         vlc_mutex_unlock( &p_input_bank->pp_input[0]->stream.stream_lock );
377     }
378 }
379
380 /*****************************************************************************
381  * FileOpen: open a file
382  *****************************************************************************
383  * This function opens a file requester and adds the selected file to
384  * the playlist.
385  *****************************************************************************/
386 void IntfWindow::FileOpen( void )
387 {
388     QString file = QFileDialog::getOpenFileName( QString::null,
389                                                  QString::null, this );
390
391     if( file.isEmpty() )
392     {
393         statusBar()->message( "No file loaded", 2000 );
394     }
395     else
396     {
397         intf_PlaylistAdd( p_main->p_playlist, PLAYLIST_END, file.latin1() );
398     }
399 }
400
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 )
407 {
408     QMessageBox::about( this, "About",
409         "VideoLAN Client\n"
410         "(C) 1996, 1997, 1998, 1999, 2000, 2001 - the VideoLAN Team\n"
411         "\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"
415         "\n"
416         "More information: http://www.videolan.org/" );
417 }
418
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 )
426 {
427     /* Manage the slider */
428     if( p_input_bank->pp_input[0] != NULL && p_input_bank->pp_input[0]->stream.b_seekable )
429     {
430         int i_value = p_slider->value();
431
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() )
436         {
437             i_value = ( SLIDER_MAX * p_area->i_tell ) / p_area->i_size;
438
439             p_slider->setValue( i_value );
440             p_slider->setOldValue( i_value );
441         }
442         /* Otherwise, send message to the input if the user has
443          * finished dragging the slider */
444         else if( p_slider->b_free )
445         {
446             off_t i_seek = ( i_value * p_area->i_size ) / SLIDER_MAX;
447
448             input_Seek( p_input_bank->pp_input[0], i_seek );
449
450             /* Update the old value */
451             p_slider->setOldValue( i_value );
452         }
453 #undef p_area
454     }
455
456     /* If the "display popup" flag has changed, popup the context menu */
457     if( p_intf->b_menu_change )
458     {
459         p_popup->popup( QCursor::pos() );
460         p_intf->b_menu_change = 0;
461     }
462
463     if( p_intf->b_die )
464     {
465         qApp->quit();
466     }
467
468     /* Manage core vlc functions through the callback */
469     p_intf->pf_manage( p_intf );
470 }
471
472 /*****************************************************************************
473  * PlaybackPlay: play
474  *****************************************************************************/
475 void IntfWindow::PlaybackPlay( void )
476 {
477     if( p_input_bank->pp_input[0] != NULL )
478     {
479         input_SetStatus( p_input_bank->pp_input[0], INPUT_STATUS_PLAY );
480     }
481 }
482
483 /*****************************************************************************
484  * PlaybackPause: pause
485  *****************************************************************************/
486 void IntfWindow::PlaybackPause( void )
487 {
488     if( p_input_bank->pp_input[0] != NULL )
489     {
490         input_SetStatus( p_input_bank->pp_input[0], INPUT_STATUS_PAUSE );
491     }
492 }
493
494 /*****************************************************************************
495  * PlaybackSlow: slow
496  *****************************************************************************/
497 void IntfWindow::PlaybackSlow( void )
498 {
499     if( p_input_bank->pp_input[0] != NULL )
500     {
501         input_SetStatus( p_input_bank->pp_input[0], INPUT_STATUS_SLOWER );
502     }
503 }
504
505 /*****************************************************************************
506  * PlaybackFast: fast
507  *****************************************************************************/
508 void IntfWindow::PlaybackFast( void )
509 {
510     if( p_input_bank->pp_input[0] != NULL )
511     {
512         input_SetStatus( p_input_bank->pp_input[0], INPUT_STATUS_FASTER );
513     }
514 }
515
516 /*****************************************************************************
517  * PlaylistPrev: previous playlist entry
518  *****************************************************************************/
519 void IntfWindow::PlaylistPrev( void )
520 {
521     if( p_input_bank->pp_input[0] != NULL )
522     {
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;
527     }
528 }
529
530 /*****************************************************************************
531  * PlaylistNext: next playlist entry
532  *****************************************************************************/
533 void IntfWindow::PlaylistNext( void )
534 {
535     if( p_input_bank->pp_input[0] != NULL )
536     {
537         /* FIXME: temporary hack */
538         p_input_bank->pp_input[0]->b_eof = 1;
539     }
540 }
541
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 )
550 {
551     this->p_intf = p_intf;
552
553     setRange( SLIDER_MIN, SLIDER_MAX );
554     setPageStep( SLIDER_STEP );
555
556     setValue( SLIDER_MIN );
557     setOldValue( SLIDER_MIN );
558
559     setTracking( TRUE );
560     b_free = TRUE;
561
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()) );
565 }
566
567 /*****************************************************************************
568  * ~IntfSlider: slider destructor
569  *****************************************************************************
570  * This function is called when the interface slider is destroyed.
571  *****************************************************************************/
572 IntfSlider::~IntfSlider( void )
573 {
574     /* We don't need to remove anything */
575 }
576
577