]> git.sesse.net Git - vlc/blob - modules/gui/qt/intf.cpp
* ALL: the build mechanism now uses automake. See HACKING for more details.
[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.3 2002/09/30 11:05:39 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 "intf.h"
33
34 #define SLIDER_MIN    0x00000
35 #define SLIDER_MAX    0x10000
36 #define SLIDER_STEP   (SLIDER_MAX >> 4)
37
38 /*****************************************************************************
39  * intf_sys_t: description and status of Qt interface
40  *****************************************************************************/
41 struct intf_sys_t
42 {
43     QApplication *p_app;
44     IntfWindow   *p_window;
45
46     input_thread_t *p_input;
47 };
48
49 /*****************************************************************************
50  * Local prototype
51  *****************************************************************************/
52 static void Run ( intf_thread_t *p_intf );
53
54 /*****************************************************************************
55  * Open: initialize and create window
56  *****************************************************************************/
57 int E_(Open) ( vlc_object_t *p_this )
58 {
59     intf_thread_t *p_intf = (intf_thread_t*) p_this;
60     char *pp_argv[] = { "" };
61     int   i_argc    = 1;
62
63     /* Allocate instance and initialize some members */
64     p_intf->p_sys = (intf_sys_t *)malloc( sizeof( intf_sys_t ) );
65     if( p_intf->p_sys == NULL )
66     {
67         msg_Err( p_intf, "out of memory" );
68         return 1;
69     }
70
71     p_intf->pf_run = Run;
72
73     /* Create the C++ objects */
74     p_intf->p_sys->p_app = new QApplication( i_argc, pp_argv );
75     p_intf->p_sys->p_window = new IntfWindow( p_intf );
76
77     /* Tell the world we are here */
78     p_intf->p_sys->p_window->setCaption( VOUT_TITLE " (Qt interface)" );
79
80     p_intf->p_sys->p_input = NULL;
81
82     return 0;
83 }
84
85 /*****************************************************************************
86  * Close: destroy interface window
87  *****************************************************************************/
88 void E_(Close) ( vlc_object_t *p_this )
89 {
90     intf_thread_t *p_intf = (intf_thread_t*) p_this;
91
92     if( p_intf->p_sys->p_input )
93     {
94         vlc_object_release( p_intf->p_sys->p_input );
95     }
96
97     /* Get rid of the C++ objects */
98     delete p_intf->p_sys->p_window;
99     delete p_intf->p_sys->p_app;
100
101     /* Destroy structure */
102     free( p_intf->p_sys );
103 }
104
105 /*****************************************************************************
106  * Run: Qt thread
107  *****************************************************************************
108  * This part of the interface is in a separate thread so that we can call
109  * exec() from within it without annoying the rest of the program.
110  *****************************************************************************/
111 static void Run( intf_thread_t *p_intf )
112 {
113     p_intf->p_sys->p_window->show();
114
115     p_intf->p_sys->p_app->exec();
116 }
117
118 /* following functions are local */
119
120 /*****************************************************************************
121  * IntfWindow: interface window creator
122  *****************************************************************************
123  * This function creates the interface window, and populates it with a
124  * menu bar, a toolbar and a slider.
125  *****************************************************************************/
126 IntfWindow::IntfWindow( intf_thread_t *p_intf )
127            :QMainWindow( 0 )
128 {
129     setUsesTextLabel( TRUE );
130
131     this->p_intf = p_intf;
132
133     /*
134      * Create the toolbar
135      */
136
137     p_toolbar = new QToolBar( this, "toolbar" );
138     p_toolbar->setHorizontalStretchable( TRUE );
139
140     QIconSet * set = new QIconSet();
141     QPixmap pixmap = set->pixmap( QIconSet::Automatic, QIconSet::Normal );
142
143 #define addbut( l, t, s ) new QToolButton( pixmap, l, t, this, s, p_toolbar );
144     addbut( "Open", "Open a File", SLOT(FileOpen()) );
145     addbut( "Disc", "Open a DVD or VCD", SLOT(Unimplemented()) );
146     addbut( "Net", "Select a Network Stream", SLOT(Unimplemented()) );
147     p_toolbar->addSeparator();
148     addbut( "Back", "Rewind Stream", SLOT(Unimplemented()) );
149     addbut( "Stop", "Stop Stream", SLOT(Unimplemented()) );
150     addbut( "Play", "Play Stream", SLOT(PlaybackPlay()) );
151     addbut( "Pause", "Pause Stream", SLOT(PlaybackPause()) );
152     addbut( "Slow", "Play Slower", SLOT(PlaybackSlow()) );
153     addbut( "Fast", "Play Faster", SLOT(PlaybackFast()) );
154     p_toolbar->addSeparator();
155     addbut( "Playlist", "Open Playlist", SLOT(Unimplemented()) );
156     addbut( "Prev", "Previous File", SLOT(PlaylistPrev()) );
157     addbut( "Next", "Next File", SLOT(PlaylistNext()) );
158 #undef addbut
159
160     /* 
161      * Create the menubar
162      */
163
164     QPopupMenu * p_tmpmenu = new QPopupMenu( this );
165
166 #define instmp0( x, y )    p_tmpmenu->insertItem( x, this, y )
167 #define instmp1( x, y, a ) p_tmpmenu->insertItem( x, this, y, a )
168     menuBar()->insertItem( "&File", p_tmpmenu );
169     instmp1( "&Open File...", SLOT(FileOpen()), Key_F3 );
170     instmp1( "Open &Disc...", SLOT(Unimplemented()), Key_F4 );
171     instmp1( "&Network Stream...", SLOT(Unimplemented()), Key_F5 );
172     p_tmpmenu->insertSeparator();
173     instmp1( "&Exit", SLOT(FileQuit()), CTRL+Key_Q );
174
175     p_tmpmenu = new QPopupMenu( this );
176     menuBar()->insertItem( "&View", p_tmpmenu );
177     instmp0( "&Playlist...", SLOT(Unimplemented()) );
178     instmp0( "&Modules...", SLOT(Unimplemented()) );
179
180     p_tmpmenu = new QPopupMenu( this );
181     menuBar()->insertItem( "&Settings", p_tmpmenu );
182     instmp0( "&Preferences...", SLOT(Unimplemented()) );
183
184     p_tmpmenu = new QPopupMenu( this );
185     menuBar()->insertItem( "&Help", p_tmpmenu );
186     instmp0( "&About...", SLOT(About()) );
187
188     /*
189      * Create the popup menu
190      */
191
192     p_popup = new QPopupMenu( /* floating menu */ );
193
194 #define inspop0( x, y )    p_popup->insertItem( x, this, y )
195 #define inspop1( x, y, a ) p_popup->insertItem( x, this, y, a )
196     inspop0( "&Play", SLOT(PlaybackPlay()) );
197     inspop0( "Pause", SLOT(PlaybackPause()) );
198     inspop0( "&Slow", SLOT(PlaybackSlow()) );
199     inspop0( "&Fast", SLOT(PlaybackFast()) );
200     p_popup->insertSeparator();
201     inspop1( "&Open File...", SLOT(FileOpen()), Key_F3 );
202     inspop1( "Open &Disc...", SLOT(Unimplemented()), Key_F4 );
203     inspop1( "&Network Stream...", SLOT(Unimplemented()), Key_F5 );
204     p_popup->insertSeparator();
205     inspop0( "&About...", SLOT(About()) );
206     inspop0( "&Exit", SLOT(FileQuit()) );
207
208     /* Activate the statusbar */
209     statusBar();
210
211     /* Add the vertical box */
212     QVBox * p_vbox = new QVBox( this );
213     setCentralWidget( p_vbox );
214
215         /* The horizontal box */
216         QHBox * p_hbox = new QHBox( p_vbox );
217
218             /* The date label */
219             p_date  = new QLabel( p_hbox );
220             p_date->setAlignment( AlignHCenter | AlignVCenter );
221             p_date->setText( "-:--:--" );
222
223             /* The status label */
224             QLabel *p_label  = new QLabel( p_hbox );
225             p_label->setAlignment( AlignHCenter | AlignVCenter );
226             p_label->setText( "Status: foo" );
227
228             /* The bar label */
229             p_label  = new QLabel( p_hbox );
230             p_label->setAlignment( AlignHCenter | AlignVCenter );
231             p_label->setText( "Bar: baz quux" );
232
233         /* Create the slider and connect it to the date label */
234         p_slider = new IntfSlider( p_intf, p_vbox );
235
236         connect( p_slider, SIGNAL(valueChanged(int)),
237                  this, SLOT(DateDisplay(int)) );
238
239     /* The timer */
240     QTimer *p_timer = new QTimer( this );
241     connect( p_timer, SIGNAL(timeout()), this, SLOT(Manage()) );
242     p_timer->start( INTF_IDLE_SLEEP / 1000 );
243
244     /* Everything worked fine */
245     resize( 620, 30 );
246 }
247
248 /*****************************************************************************
249  * ~IntfWindow: interface window destructor
250  *****************************************************************************
251  * This function is called when the interface window is destroyed.
252  *****************************************************************************/
253 IntfWindow::~IntfWindow( void )
254 {
255     /* FIXME: remove everything cleanly */
256 }
257
258 /*****************************************************************************
259  * DateDisplay: display date
260  *****************************************************************************
261  * This function displays the current date in the date label.
262  *****************************************************************************/
263 void IntfWindow::DateDisplay( int i_range )
264 {
265     if( p_intf->p_sys->p_input )
266     {
267         char psz_time[ OFFSETTOTIME_MAX_SIZE ];
268
269         vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock );
270         p_date->setText( input_OffsetToTime( p_intf->p_sys->p_input, psz_time,
271            ( p_intf->p_sys->p_input->stream.p_selected_area->i_size * i_range )
272                / SLIDER_MAX ) );
273         vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock );
274     }
275 }
276
277 /*****************************************************************************
278  * FileOpen: open a file
279  *****************************************************************************
280  * This function opens a file requester and adds the selected file to
281  * the playlist.
282  *****************************************************************************/
283 void IntfWindow::FileOpen( void )
284 {
285     playlist_t *p_playlist;
286     QString file = QFileDialog::getOpenFileName( QString::null,
287                                                  QString::null, this );
288
289     if( file.isEmpty() )
290     {
291         statusBar()->message( "No file loaded", 2000 );
292     }
293     else
294     {
295         p_playlist = (playlist_t *)
296                 vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE );
297         if( p_playlist == NULL )
298         {
299             return;
300         }
301
302         playlist_Add( p_playlist, file.latin1(),
303                       PLAYLIST_APPEND | PLAYLIST_GO, PLAYLIST_END );
304         vlc_object_release( p_playlist );
305     }
306 }
307
308 /*****************************************************************************
309  * FileQuit: terminate vlc
310  *****************************************************************************/
311 void IntfWindow::FileQuit( void )
312 {
313     p_intf->p_vlc->b_die = VLC_TRUE;
314 }
315
316 /*****************************************************************************
317  * About: display the "about" box
318  *****************************************************************************
319  * This function displays a simple "about" box with copyright information.
320  *****************************************************************************/
321 void IntfWindow::About( void )
322 {
323     QMessageBox::about( this, "About",
324         "VideoLAN Client\n"
325         "(C) 1996, 1997, 1998, 1999, 2000, 2001, 2002 - the VideoLAN Team\n"
326         "\n"
327         "This is the VideoLAN client, a DVD and MPEG player.\n"
328         "It can play MPEG and MPEG 2 files from a file "
329             "or from a network source.\n"
330         "\n"
331         "More information: http://www.videolan.org/" );
332 }
333
334 /*****************************************************************************
335  * Manage: manage main thread messages
336  *****************************************************************************
337  * In this function, called approx. 10 times a second, we check what the
338  * main program wanted to tell us.
339  *****************************************************************************/
340 void IntfWindow::Manage( void )
341 {
342     /* Update the input */
343     if( p_intf->p_sys->p_input == NULL )
344     {
345         p_intf->p_sys->p_input = (input_thread_t *)
346                 vlc_object_find( p_intf, VLC_OBJECT_INPUT, FIND_ANYWHERE );
347     }
348     else if( p_intf->p_sys->p_input->b_dead )
349     {
350         vlc_object_release( p_intf->p_sys->p_input );
351         p_intf->p_sys->p_input = NULL;
352     }
353
354     /* Manage the slider */
355     if( p_intf->p_sys->p_input && p_intf->p_sys->p_input->stream.b_seekable )
356     {
357         int i_value = p_slider->value();
358
359 #define p_area p_intf->p_sys->p_input->stream.p_selected_area
360         /* If the user hasn't touched the slider since the last time,
361          * then the input can safely change it */
362         if( i_value == p_slider->oldvalue() )
363         {
364             i_value = ( SLIDER_MAX * p_area->i_tell ) / p_area->i_size;
365
366             p_slider->setValue( i_value );
367             p_slider->setOldValue( i_value );
368         }
369         /* Otherwise, send message to the input if the user has
370          * finished dragging the slider */
371         else if( p_slider->b_free )
372         {
373             off_t i_seek = ( i_value * p_area->i_size ) / SLIDER_MAX;
374
375             input_Seek( p_intf->p_sys->p_input, i_seek, INPUT_SEEK_SET );
376
377             /* Update the old value */
378             p_slider->setOldValue( i_value );
379         }
380 #undef p_area
381     }
382
383     /* If the "display popup" flag has changed, popup the context menu */
384     if( p_intf->b_menu_change )
385     {
386         p_popup->popup( QCursor::pos() );
387         p_intf->b_menu_change = 0;
388     }
389
390     if( p_intf->b_die )
391     {
392         qApp->quit();
393     }
394 }
395
396 /*****************************************************************************
397  * PlaybackPlay: play
398  *****************************************************************************/
399 void IntfWindow::PlaybackPlay( void )
400 {
401     if( p_intf->p_sys->p_input != NULL )
402     {
403         input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_PLAY );
404     }
405 }
406
407 /*****************************************************************************
408  * PlaybackPause: pause
409  *****************************************************************************/
410 void IntfWindow::PlaybackPause( void )
411 {
412     if( p_intf->p_sys->p_input != NULL )
413     {
414         input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_PAUSE );
415     }
416 }
417
418 /*****************************************************************************
419  * PlaybackSlow: slow
420  *****************************************************************************/
421 void IntfWindow::PlaybackSlow( void )
422 {
423     if( p_intf->p_sys->p_input != NULL )
424     {
425         input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_SLOWER );
426     }
427 }
428
429 /*****************************************************************************
430  * PlaybackFast: fast
431  *****************************************************************************/
432 void IntfWindow::PlaybackFast( void )
433 {
434     if( p_intf->p_sys->p_input != NULL )
435     {
436         input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_FASTER );
437     }
438 }
439
440 /*****************************************************************************
441  * PlaylistPrev: previous playlist entry
442  *****************************************************************************/
443 void IntfWindow::PlaylistPrev( void )
444 {
445     playlist_t *p_playlist = (playlist_t *)
446         vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE );
447
448     if( p_playlist == NULL )
449     {
450         return;
451     }
452
453     playlist_Prev( p_playlist );
454     vlc_object_release( p_playlist );
455 }
456
457 /*****************************************************************************
458  * PlaylistNext: next playlist entry
459  *****************************************************************************/
460 void IntfWindow::PlaylistNext( void )
461 {
462     playlist_t *p_playlist = (playlist_t *)
463         vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE );
464
465     if( p_playlist == NULL )
466     {
467         return;
468     }
469
470     playlist_Next( p_playlist );
471     vlc_object_release( p_playlist );
472 }
473
474 /*****************************************************************************
475  * IntfSlider: slider creator
476  *****************************************************************************
477  * This function creates the slider, sets its default values, and connects
478  * the interesting signals.
479  *****************************************************************************/
480 IntfSlider::IntfSlider( intf_thread_t *p_intf, QWidget *p_parent )
481            :QSlider( Horizontal, p_parent )
482 {
483     this->p_intf = p_intf;
484
485     setRange( SLIDER_MIN, SLIDER_MAX );
486     setPageStep( SLIDER_STEP );
487
488     setValue( SLIDER_MIN );
489     setOldValue( SLIDER_MIN );
490
491     setTracking( TRUE );
492     b_free = TRUE;
493
494     connect( this, SIGNAL(sliderMoved(int)), this, SLOT(SlideStart()) );
495     connect( this, SIGNAL(sliderPressed()), this, SLOT(SlideStart()) );
496     connect( this, SIGNAL(sliderReleased()), this, SLOT(SlideStop()) );
497 }
498
499 /*****************************************************************************
500  * ~IntfSlider: slider destructor
501  *****************************************************************************
502  * This function is called when the interface slider is destroyed.
503  *****************************************************************************/
504 IntfSlider::~IntfSlider( void )
505 {
506     /* We don't need to remove anything */
507 }
508
509