]> git.sesse.net Git - vlc/blob - plugins/qt/intf_qt.cpp
Some heavy changes today:
[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.10 2001/12/30 07:09:56 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_Probe     ( probedata_t *p_data );
150 static int  intf_Open      ( intf_thread_t *p_intf );
151 static void intf_Close     ( intf_thread_t *p_intf );
152 static void intf_Run       ( intf_thread_t *p_intf );
153
154 /*****************************************************************************
155  * Functions exported as capabilities. They are declared as static so that
156  * we don't pollute the namespace too much.
157  *****************************************************************************/
158 extern "C"
159 {
160
161 void _M( intf_getfunctions )( function_list_t * p_function_list )
162 {
163     p_function_list->pf_probe = intf_Probe;
164     p_function_list->functions.intf.pf_open  = intf_Open;
165     p_function_list->functions.intf.pf_close = intf_Close;
166     p_function_list->functions.intf.pf_run   = intf_Run;
167 }
168
169 }
170
171 /*****************************************************************************
172  * intf_Probe: probe the interface and return a score
173  *****************************************************************************
174  * This function tries to initialize Qt and returns a score to the
175  * plugin manager so that it can select the best plugin.
176  *****************************************************************************/
177 static int intf_Probe( probedata_t *p_data )
178 {
179     return( 80 );
180 }
181
182 /*****************************************************************************
183  * intf_Open: initialize and create window
184  *****************************************************************************/
185 static int intf_Open( intf_thread_t *p_intf )
186 {
187     char *pp_argv[] = { "" };
188     int   i_argc    = 1;
189
190     /* Allocate instance and initialize some members */
191     p_intf->p_sys = (intf_sys_t *)malloc( sizeof( intf_sys_t ) );
192     if( p_intf->p_sys == NULL )
193     {
194         intf_ErrMsg( "intf error: %s", strerror(ENOMEM) );
195         return( 1 );
196     }
197
198     /* Create the C++ objects */
199     p_intf->p_sys->p_app = new QApplication( i_argc, pp_argv );
200     p_intf->p_sys->p_window = new IntfWindow( p_intf );
201
202     /* Tell the world we are here */
203     p_intf->p_sys->p_window->setCaption( VOUT_TITLE " (Qt interface)" );
204
205     return( 0 );
206 }
207
208 /*****************************************************************************
209  * intf_Close: destroy interface window
210  *****************************************************************************/
211 static void intf_Close( intf_thread_t *p_intf )
212 {
213     /* Get rid of the C++ objects */
214     delete p_intf->p_sys->p_window;
215     delete p_intf->p_sys->p_app;
216
217     /* Destroy structure */
218     free( p_intf->p_sys );
219 }
220
221 /*****************************************************************************
222  * intf_Run: Qt thread
223  *****************************************************************************
224  * This part of the interface is in a separate thread so that we can call
225  * exec() from within it without annoying the rest of the program.
226  *****************************************************************************/
227 static void intf_Run( intf_thread_t *p_intf )
228 {
229     p_intf->p_sys->p_window->show();
230
231     p_intf->p_sys->p_app->exec();
232 }
233
234 /* following functions are local */
235
236 /*****************************************************************************
237  * IntfWindow: interface window creator
238  *****************************************************************************
239  * This function creates the interface window, and populates it with a
240  * menu bar, a toolbar and a slider.
241  *****************************************************************************/
242 IntfWindow::IntfWindow( intf_thread_t *p_intf )
243            :QMainWindow( 0 )
244 {
245     setUsesTextLabel( TRUE );
246
247     this->p_intf = p_intf;
248
249     /*
250      * Create the toolbar
251      */
252
253     p_toolbar = new QToolBar( this, "toolbar" );
254     p_toolbar->setHorizontalStretchable( TRUE );
255
256     QIconSet * set = new QIconSet();
257     QPixmap pixmap = set->pixmap( QIconSet::Automatic, QIconSet::Normal );
258
259 #define addbut( l, t, s ) new QToolButton( pixmap, l, t, this, s, p_toolbar );
260     addbut( "Open", "Open a File", SLOT(FileOpen()) );
261     addbut( "Disc", "Open a DVD or VCD", SLOT(Unimplemented()) );
262     addbut( "Net", "Select a Network Stream", SLOT(Unimplemented()) );
263     p_toolbar->addSeparator();
264     addbut( "Back", "Rewind Stream", SLOT(Unimplemented()) );
265     addbut( "Stop", "Stop Stream", SLOT(Unimplemented()) );
266     addbut( "Play", "Play Stream", SLOT(PlaybackPlay()) );
267     addbut( "Pause", "Pause Stream", SLOT(PlaybackPause()) );
268     addbut( "Slow", "Play Slower", SLOT(PlaybackSlow()) );
269     addbut( "Fast", "Play Faster", SLOT(PlaybackFast()) );
270     p_toolbar->addSeparator();
271     addbut( "Playlist", "Open Playlist", SLOT(Unimplemented()) );
272     addbut( "Prev", "Previous File", SLOT(PlaylistPrev()) );
273     addbut( "Next", "Next File", SLOT(PlaylistNext()) );
274 #undef addbut
275
276     /* 
277      * Create the menubar
278      */
279
280     QPopupMenu * p_tmpmenu = new QPopupMenu( this );
281
282 #define instmp( x, y... ) p_tmpmenu->insertItem( x, this, ## y )
283     menuBar()->insertItem( "&File", p_tmpmenu );
284     instmp( "&Open File...", SLOT(FileOpen()), Key_F3 );
285     instmp( "Open &Disc...", SLOT(Unimplemented()), Key_F4 );
286     instmp( "&Network Stream...", SLOT(Unimplemented()), Key_F5 );
287     p_tmpmenu->insertSeparator();
288     instmp( "&Exit", SLOT(FileQuit()), CTRL+Key_Q );
289
290     p_tmpmenu = new QPopupMenu( this );
291     menuBar()->insertItem( "&View", p_tmpmenu );
292     instmp( "&Playlist...", SLOT(Unimplemented()) );
293     instmp( "&Modules...", SLOT(Unimplemented()) );
294
295     p_tmpmenu = new QPopupMenu( this );
296     menuBar()->insertItem( "&Settings", p_tmpmenu );
297     instmp( "&Preferences...", SLOT(Unimplemented()) );
298
299     p_tmpmenu = new QPopupMenu( this );
300     menuBar()->insertItem( "&Help", p_tmpmenu );
301     instmp( "&About...", SLOT(About()) );
302 #undef instmp
303
304     /*
305      * Create the popup menu
306      */
307
308     p_popup = new QPopupMenu( /* floating menu */ );
309
310 #define inspop( x, y... ) p_popup->insertItem( x, this, ## y )
311     inspop( "&Play", SLOT(PlaybackPlay()) );
312     inspop( "Pause", SLOT(PlaybackPause()) );
313     inspop( "&Slow", SLOT(PlaybackSlow()) );
314     inspop( "&Fast", SLOT(PlaybackFast()) );
315     p_popup->insertSeparator();
316     inspop( "&Open File...", SLOT(FileOpen()), Key_F3 );
317     inspop( "Open &Disc...", SLOT(Unimplemented()), Key_F4 );
318     inspop( "&Network Stream...", SLOT(Unimplemented()), Key_F5 );
319     p_popup->insertSeparator();
320     inspop( "&About...", SLOT(About()) );
321     inspop( "&Exit", SLOT(FileQuit()) );
322 #undef inspop
323
324     /* Activate the statusbar */
325     statusBar();
326
327     /* Add the vertical box */
328     QVBox * p_vbox = new QVBox( this );
329     setCentralWidget( p_vbox );
330
331         /* The horizontal box */
332         QHBox * p_hbox = new QHBox( p_vbox );
333
334             /* The date label */
335             p_date  = new QLabel( p_hbox );
336             p_date->setAlignment( AlignHCenter | AlignVCenter );
337             p_date->setText( "-:--:--" );
338
339             /* The status label */
340             QLabel *p_label  = new QLabel( p_hbox );
341             p_label->setAlignment( AlignHCenter | AlignVCenter );
342             p_label->setText( "Status: foo" );
343
344             /* The bar label */
345             p_label  = new QLabel( p_hbox );
346             p_label->setAlignment( AlignHCenter | AlignVCenter );
347             p_label->setText( "Bar: baz quux" );
348
349         /* Create the slider and connect it to the date label */
350         p_slider = new IntfSlider( p_intf, p_vbox );
351
352         connect( p_slider, SIGNAL(valueChanged(int)),
353                  this, SLOT(DateDisplay(int)) );
354
355     /* The timer */
356     QTimer *p_timer = new QTimer( this );
357     connect( p_timer, SIGNAL(timeout()), this, SLOT(Manage()) );
358     p_timer->start( INTF_IDLE_SLEEP / 1000 );
359
360     /* Everything worked fine */
361     resize( 620, 30 );
362 }
363
364 /*****************************************************************************
365  * ~IntfWindow: interface window destructor
366  *****************************************************************************
367  * This function is called when the interface window is destroyed.
368  *****************************************************************************/
369 IntfWindow::~IntfWindow( void )
370 {
371     /* FIXME: remove everything cleanly */
372 }
373
374 /*****************************************************************************
375  * DateDisplay: display date
376  *****************************************************************************
377  * This function displays the current date in the date label.
378  *****************************************************************************/
379 void IntfWindow::DateDisplay( int i_range )
380 {
381     if( p_intf->p_input != NULL )
382     {
383         char psz_time[ OFFSETTOTIME_MAX_SIZE ];
384
385         vlc_mutex_lock( &p_intf->p_input->stream.stream_lock );
386         p_date->setText( input_OffsetToTime( p_intf->p_input, psz_time,
387                ( p_intf->p_input->stream.p_selected_area->i_size * i_range )
388                    / SLIDER_MAX ) );
389         vlc_mutex_unlock( &p_intf->p_input->stream.stream_lock );
390     }
391 }
392
393 /*****************************************************************************
394  * FileOpen: open a file
395  *****************************************************************************
396  * This function opens a file requester and adds the selected file to
397  * the playlist.
398  *****************************************************************************/
399 void IntfWindow::FileOpen( void )
400 {
401     QString file = QFileDialog::getOpenFileName( QString::null,
402                                                  QString::null, this );
403
404     if( file.isEmpty() )
405     {
406         statusBar()->message( "No file loaded", 2000 );
407     }
408     else
409     {
410         intf_PlaylistAdd( p_main->p_playlist, PLAYLIST_END, file.latin1() );
411     }
412 }
413
414 /*****************************************************************************
415  * About: display the "about" box
416  *****************************************************************************
417  * This function displays a simple "about" box with copyright information.
418  *****************************************************************************/
419 void IntfWindow::About( void )
420 {
421     QMessageBox::about( this, "About",
422         "VideoLAN Client\n"
423         "(C) 1996, 1997, 1998, 1999, 2000, 2001 - the VideoLAN Team\n"
424         "\n"
425         "This is the VideoLAN client, a DVD and MPEG player.\n"
426         "It can play MPEG and MPEG 2 files from a file "
427             "or from a network source.\n"
428         "\n"
429         "More information: http://www.videolan.org/" );
430 }
431
432 /*****************************************************************************
433  * Manage: manage main thread messages
434  *****************************************************************************
435  * In this function, called approx. 10 times a second, we check what the
436  * main program wanted to tell us.
437  *****************************************************************************/
438 void IntfWindow::Manage( void )
439 {
440     /* Manage the slider */
441     if( p_intf->p_input != NULL && p_intf->p_input->stream.b_seekable )
442     {
443         int i_value = p_slider->value();
444
445 #define p_area p_intf->p_input->stream.p_selected_area
446         /* If the user hasn't touched the slider since the last time,
447          * then the input can safely change it */
448         if( i_value == p_slider->oldvalue() )
449         {
450             i_value = ( SLIDER_MAX * p_area->i_tell ) / p_area->i_size;
451
452             p_slider->setValue( i_value );
453             p_slider->setOldValue( i_value );
454         }
455         /* Otherwise, send message to the input if the user has
456          * finished dragging the slider */
457         else if( p_slider->b_free )
458         {
459             off_t i_seek = ( i_value * p_area->i_size ) / SLIDER_MAX;
460
461             input_Seek( p_intf->p_input, i_seek );
462
463             /* Update the old value */
464             p_slider->setOldValue( i_value );
465         }
466 #undef p_area
467     }
468
469     /* If the "display popup" flag has changed, popup the context menu */
470     if( p_intf->b_menu_change )
471     {
472         p_popup->popup( QCursor::pos() );
473         p_intf->b_menu_change = 0;
474     }
475
476     if( p_intf->b_die )
477     {
478         qApp->quit();
479     }
480
481     /* Manage core vlc functions through the callback */
482     p_intf->pf_manage( p_intf );
483 }
484
485 /*****************************************************************************
486  * PlaybackPlay: play
487  *****************************************************************************/
488 void IntfWindow::PlaybackPlay( void )
489 {
490     if( p_intf->p_input != NULL )
491     {
492         input_SetStatus( p_intf->p_input, INPUT_STATUS_PLAY );
493     }
494 }
495
496 /*****************************************************************************
497  * PlaybackPause: pause
498  *****************************************************************************/
499 void IntfWindow::PlaybackPause( void )
500 {
501     if( p_intf->p_input != NULL )
502     {
503         input_SetStatus( p_intf->p_input, INPUT_STATUS_PAUSE );
504     }
505 }
506
507 /*****************************************************************************
508  * PlaybackSlow: slow
509  *****************************************************************************/
510 void IntfWindow::PlaybackSlow( void )
511 {
512     if( p_intf->p_input != NULL )
513     {
514         input_SetStatus( p_intf->p_input, INPUT_STATUS_SLOWER );
515     }
516 }
517
518 /*****************************************************************************
519  * PlaybackFast: fast
520  *****************************************************************************/
521 void IntfWindow::PlaybackFast( void )
522 {
523     if( p_intf->p_input != NULL )
524     {
525         input_SetStatus( p_intf->p_input, INPUT_STATUS_FASTER );
526     }
527 }
528
529 /*****************************************************************************
530  * PlaylistPrev: previous playlist entry
531  *****************************************************************************/
532 void IntfWindow::PlaylistPrev( void )
533 {
534     if( p_intf->p_input != NULL )
535     {
536         /* FIXME: temporary hack */
537         intf_PlaylistPrev( p_main->p_playlist );
538         intf_PlaylistPrev( p_main->p_playlist );
539         p_intf->p_input->b_eof = 1;
540     }
541 }
542
543 /*****************************************************************************
544  * PlaylistNext: next playlist entry
545  *****************************************************************************/
546 void IntfWindow::PlaylistNext( void )
547 {
548     if( p_intf->p_input != NULL )
549     {
550         /* FIXME: temporary hack */
551         p_intf->p_input->b_eof = 1;
552     }
553 }
554
555 /*****************************************************************************
556  * IntfSlider: slider creator
557  *****************************************************************************
558  * This function creates the slider, sets its default values, and connects
559  * the interesting signals.
560  *****************************************************************************/
561 IntfSlider::IntfSlider( intf_thread_t *p_intf, QWidget *p_parent )
562            :QSlider( Horizontal, p_parent )
563 {
564     this->p_intf = p_intf;
565
566     setRange( SLIDER_MIN, SLIDER_MAX );
567     setPageStep( SLIDER_STEP );
568
569     setValue( SLIDER_MIN );
570     setOldValue( SLIDER_MIN );
571
572     setTracking( TRUE );
573     b_free = TRUE;
574
575     connect( this, SIGNAL(sliderMoved(int)), this, SLOT(SlideStart()) );
576     connect( this, SIGNAL(sliderPressed()), this, SLOT(SlideStart()) );
577     connect( this, SIGNAL(sliderReleased()), this, SLOT(SlideStop()) );
578 }
579
580 /*****************************************************************************
581  * ~IntfSlider: slider destructor
582  *****************************************************************************
583  * This function is called when the interface slider is destroyed.
584  *****************************************************************************/
585 IntfSlider::~IntfSlider( void )
586 {
587     /* We don't need to remove anything */
588 }
589
590