1 /*****************************************************************************
2 * intf_qt.cpp: Qt interface
3 *****************************************************************************
4 * Copyright (C) 1999, 2000 VideoLAN
5 * $Id: intf_qt.cpp,v 1.1 2001/03/15 01:42:20 sam Exp $
7 * Authors: Samuel Hocevar <sam@zoy.org>
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.
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.
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 *****************************************************************************/
27 #define MODULE_NAME qt
28 #include "modules_inner.h"
30 /*****************************************************************************
32 *****************************************************************************/
35 #include <errno.h> /* ENOMEM */
36 #include <stdlib.h> /* free() */
37 #include <string.h> /* strerror() */
47 #include "stream_control.h"
48 #include "input_ext-intf.h"
51 #include "intf_playlist.h"
52 #include "interface.h"
58 #include <qapplication.h>
59 #include <qmainwindow.h>
61 #include <qtoolbutton.h>
62 #include <qwhatsthis.h>
63 #include <qpushbutton.h>
64 #include <qfiledialog.h>
66 #include <qlcdnumber.h>
68 #include <qstatusbar.h>
69 #include <qmessagebox.h>
76 /*****************************************************************************
77 * Local Qt slider class
78 *****************************************************************************/
79 class IntfSlider : public QSlider
84 IntfSlider( intf_thread_t *, QWidget * ); /* Constructor and destructor */
87 bool b_free; /* Is the slider free ? */
89 int oldvalue ( void ) { return i_oldvalue; };
90 void setOldValue( int i_value ) { i_oldvalue = i_value; };
93 void SlideStart ( void ) { b_free = FALSE; };
94 void SlideStop ( void ) { b_free = TRUE; };
97 intf_thread_t *p_intf;
101 /*****************************************************************************
102 * Local Qt interface window class
103 *****************************************************************************/
104 class IntfWindow : public QMainWindow
109 IntfWindow( intf_thread_t * );
115 void FileOpen ( void );
116 void FileQuit ( void ) { p_intf->b_die = 1; };
118 void PlaybackPlay ( void );
119 void PlaybackPause ( void );
120 void PlaybackSlow ( void );
121 void PlaybackFast ( void );
123 void PlaylistPrev ( void );
124 void PlaylistNext ( void );
126 void DateDisplay ( int );
129 void Unimplemented( void ) { intf_WarnMsg( 3, "intf warning: "
130 "unimplemented function" ); };
133 intf_thread_t *p_intf;
135 IntfSlider *p_slider;
142 #include "intf_qt.moc"
144 #define SLIDER_MIN 0x00000
145 #define SLIDER_MAX 0x10000
146 #define SLIDER_STEP (SLIDER_MAX >> 4)
148 /*****************************************************************************
149 * intf_sys_t: description and status of Qt interface
150 *****************************************************************************/
151 typedef struct intf_sys_s
154 IntfWindow *p_window;
158 /*****************************************************************************
160 *****************************************************************************/
161 static int intf_Probe ( probedata_t *p_data );
162 static int intf_Open ( intf_thread_t *p_intf );
163 static void intf_Close ( intf_thread_t *p_intf );
164 static void intf_Run ( intf_thread_t *p_intf );
166 /*****************************************************************************
167 * Functions exported as capabilities. They are declared as static so that
168 * we don't pollute the namespace too much.
169 *****************************************************************************/
173 void _M( intf_getfunctions )( function_list_t * p_function_list )
175 p_function_list->pf_probe = intf_Probe;
176 p_function_list->functions.intf.pf_open = intf_Open;
177 p_function_list->functions.intf.pf_close = intf_Close;
178 p_function_list->functions.intf.pf_run = intf_Run;
183 /*****************************************************************************
184 * intf_Probe: probe the interface and return a score
185 *****************************************************************************
186 * This function tries to initialize Qt and returns a score to the
187 * plugin manager so that it can select the best plugin.
188 *****************************************************************************/
189 static int intf_Probe( probedata_t *p_data )
191 if( TestMethod( INTF_METHOD_VAR, "qt" ) )
196 if( TestProgram( "qvlc" ) )
204 /*****************************************************************************
205 * intf_Open: initialize and create window
206 *****************************************************************************/
207 static int intf_Open( intf_thread_t *p_intf )
209 char *pp_argv[] = { "" };
212 /* Allocate instance and initialize some members */
213 p_intf->p_sys = (intf_sys_t *)malloc( sizeof( intf_sys_t ) );
214 if( p_intf->p_sys == NULL )
216 intf_ErrMsg( "intf error: %s", strerror(ENOMEM) );
220 /* Create the C++ objects */
221 p_intf->p_sys->p_app = new QApplication( i_argc, pp_argv );
222 p_intf->p_sys->p_window = new IntfWindow( p_intf );
224 /* Tell the world we are here */
225 p_intf->p_sys->p_window->setCaption( VOUT_TITLE " (Qt interface)" );
230 /*****************************************************************************
231 * intf_Close: destroy interface window
232 *****************************************************************************/
233 static void intf_Close( intf_thread_t *p_intf )
235 /* Get rid of the C++ objects */
236 delete p_intf->p_sys->p_window;
237 delete p_intf->p_sys->p_app;
239 /* Destroy structure */
240 free( p_intf->p_sys );
243 /*****************************************************************************
244 * intf_Run: Qt thread
245 *****************************************************************************
246 * This part of the interface is in a separate thread so that we can call
247 * exec() from within it without annoying the rest of the program.
248 *****************************************************************************/
249 static void intf_Run( intf_thread_t *p_intf )
251 p_intf->p_sys->p_window->show();
253 p_intf->p_sys->p_app->exec();
256 /* following functions are local */
258 /*****************************************************************************
259 * IntfWindow: interface window creator
260 *****************************************************************************
261 * This function creates the interface window, and populates it with a
262 * menu bar, a toolbar and a slider.
263 *****************************************************************************/
264 IntfWindow::IntfWindow( intf_thread_t *p_intf )
267 setUsesTextLabel( TRUE );
269 this->p_intf = p_intf;
275 p_toolbar = new QToolBar( this, "toolbar" );
276 p_toolbar->setHorizontalStretchable( TRUE );
278 QPixmap pixmap = QPixmap( 0, 0 );
280 #define addbut( l, t, s ) new QToolButton( pixmap, l, t, this, s, p_toolbar );
281 addbut( "Open", "Open a File", SLOT(FileOpen()) );
282 addbut( "Disc", "Open a DVD or VCD", SLOT(Unimplemented()) );
283 addbut( "Net", "Select a Network Stream", SLOT(Unimplemented()) );
284 p_toolbar->addSeparator();
285 addbut( "Back", "Rewind Stream", SLOT(Unimplemented()) );
286 addbut( "Stop", "Stop Stream", SLOT(Unimplemented()) );
287 addbut( "Play", "Play Stream", SLOT(PlaybackPlay()) );
288 addbut( "Pause", "Pause Stream", SLOT(PlaybackPause()) );
289 addbut( "Slow", "Play Slower", SLOT(PlaybackSlow()) );
290 addbut( "Fast", "Play Faster", SLOT(PlaybackFast()) );
291 p_toolbar->addSeparator();
292 addbut( "Playlist", "Open Playlist", SLOT(Unimplemented()) );
293 addbut( "Prev", "Previous File", SLOT(PlaylistPrev()) );
294 addbut( "Next", "Next File", SLOT(PlaylistNext()) );
301 QPopupMenu * p_tmpmenu = new QPopupMenu( this );
303 #define instmp( x, y... ) p_tmpmenu->insertItem( x, this, ## y )
304 menuBar()->insertItem( "&File", p_tmpmenu );
305 instmp( "&Open File...", SLOT(FileOpen()), Key_F3 );
306 instmp( "Open &Disc...", SLOT(Unimplemented()), Key_F4 );
307 instmp( "&Network Stream...", SLOT(Unimplemented()), Key_F5 );
308 p_tmpmenu->insertSeparator();
309 instmp( "&Exit", SLOT(FileQuit()), CTRL+Key_Q );
311 p_tmpmenu = new QPopupMenu( this );
312 menuBar()->insertItem( "&View", p_tmpmenu );
313 instmp( "&Playlist...", SLOT(Unimplemented()) );
314 instmp( "&Modules...", SLOT(Unimplemented()) );
316 p_tmpmenu = new QPopupMenu( this );
317 menuBar()->insertItem( "&Settings", p_tmpmenu );
318 instmp( "&Preferences...", SLOT(Unimplemented()) );
320 p_tmpmenu = new QPopupMenu( this );
321 menuBar()->insertItem( "&Help", p_tmpmenu );
322 instmp( "&About...", SLOT(About()) );
326 * Create the popup menu
329 p_popup = new QPopupMenu( /* floating menu */ );
331 #define inspop( x, y... ) p_popup->insertItem( x, this, ## y )
332 inspop( "&Play", SLOT(PlaybackPlay()) );
333 inspop( "Pause", SLOT(PlaybackPause()) );
334 inspop( "&Slow", SLOT(PlaybackSlow()) );
335 inspop( "&Fast", SLOT(PlaybackFast()) );
336 p_popup->insertSeparator();
337 inspop( "&Open File...", SLOT(FileOpen()), Key_F3 );
338 inspop( "Open &Disc...", SLOT(Unimplemented()), Key_F4 );
339 inspop( "&Network Stream...", SLOT(Unimplemented()), Key_F5 );
340 p_popup->insertSeparator();
341 inspop( "&About...", SLOT(About()) );
342 inspop( "&Exit", SLOT(FileQuit()) );
345 /* Activate the statusbar */
348 /* Add the vertical box */
349 QVBox * p_vbox = new QVBox( this );
350 setCentralWidget( p_vbox );
352 /* The horizontal box */
353 QHBox * p_hbox = new QHBox( p_vbox );
356 p_date = new QLabel( p_hbox );
357 p_date->setAlignment( AlignHCenter | AlignVCenter );
358 p_date->setText( "-:--:--" );
360 /* The status label */
361 QLabel *p_label = new QLabel( p_hbox );
362 p_label->setAlignment( AlignHCenter | AlignVCenter );
363 p_label->setText( "Status: foo" );
366 p_label = new QLabel( p_hbox );
367 p_label->setAlignment( AlignHCenter | AlignVCenter );
368 p_label->setText( "Bar: baz quux" );
370 /* Create the slider and connect it to the date label */
371 p_slider = new IntfSlider( p_intf, p_vbox );
373 connect( p_slider, SIGNAL(valueChanged(int)),
374 this, SLOT(DateDisplay(int)) );
377 QTimer *p_timer = new QTimer( this );
378 connect( p_timer, SIGNAL(timeout()), this, SLOT(Manage()) );
379 p_timer->start( INTF_IDLE_SLEEP / 1000 );
381 /* Everything worked fine */
385 /*****************************************************************************
386 * ~IntfWindow: interface window destructor
387 *****************************************************************************
388 * This function is called when the interface window is destroyed.
389 *****************************************************************************/
390 IntfWindow::~IntfWindow( void )
392 /* FIXME: remove everything cleanly */
395 /*****************************************************************************
396 * DateDisplay: display date
397 *****************************************************************************
398 * This function displays the current date in the date label.
399 *****************************************************************************/
400 void IntfWindow::DateDisplay( int i_range )
402 if( p_intf->p_input != NULL )
404 char psz_time[ OFFSETTOTIME_MAX_SIZE ];
406 vlc_mutex_lock( &p_intf->p_input->stream.stream_lock );
407 p_date->setText( input_OffsetToTime( p_intf->p_input, psz_time,
408 ( p_intf->p_input->stream.p_selected_area->i_size * i_range )
410 vlc_mutex_unlock( &p_intf->p_input->stream.stream_lock );
414 /*****************************************************************************
415 * FileOpen: open a file
416 *****************************************************************************
417 * This function opens a file requester and adds the selected file to
419 *****************************************************************************/
420 void IntfWindow::FileOpen( void )
422 QString file = QFileDialog::getOpenFileName( QString::null,
423 QString::null, this );
427 statusBar()->message( "No file loaded", 2000 );
431 intf_PlaylistAdd( p_main->p_playlist, PLAYLIST_END, file.latin1() );
435 /*****************************************************************************
436 * About: display the "about" box
437 *****************************************************************************
438 * This function displays a simple "about" box with copyright information.
439 *****************************************************************************/
440 void IntfWindow::About( void )
442 QMessageBox::about( this, "About",
444 "(C) 1996, 1997, 1998, 1999, 2000, 2001 - the VideoLAN Team\n"
446 "This is the VideoLAN client, a DVD and MPEG player.\n"
447 "It can play MPEG and MPEG 2 files from a file "
448 "or from a network source.\n"
450 "More information: http://www.videolan.org/" );
453 /*****************************************************************************
454 * Manage: manage main thread messages
455 *****************************************************************************
456 * In this function, called approx. 10 times a second, we check what the
457 * main program wanted to tell us.
458 *****************************************************************************/
459 void IntfWindow::Manage( void )
461 /* Manage the slider */
462 if( p_intf->p_input != NULL )
464 int i_value = p_slider->value();
466 #define p_area p_intf->p_input->stream.p_selected_area
467 /* If the user hasn't touched the slider since the last time,
468 * then the input can safely change it */
469 if( i_value == p_slider->oldvalue() )
471 i_value = ( SLIDER_MAX * p_area->i_tell ) / p_area->i_size;
473 p_slider->setValue( i_value );
474 p_slider->setOldValue( i_value );
476 /* Otherwise, send message to the input if the user has
477 * finished dragging the slider */
478 else if( p_slider->b_free )
480 off_t i_seek = ( i_value * p_area->i_size ) / SLIDER_MAX;
482 input_Seek( p_intf->p_input, i_seek );
484 /* Update the old value */
485 p_slider->setOldValue( i_value );
490 /* If the "display popup" flag has changed */
491 if( p_intf->b_menu_change )
493 /* FIXME: find a way to display this menu right under the mouse */
494 p_popup->popup( QPoint(
495 p_intf->p_sys->p_app->desktop()->width() / 2,
496 p_intf->p_sys->p_app->desktop()->height() / 2 ), 0 );
497 p_intf->b_menu_change = 0;
500 /* Manage core vlc functions through the callback */
501 p_intf->pf_manage( p_intf );
505 /* Prepare to die, young Skywalker */
513 /*****************************************************************************
515 *****************************************************************************/
516 void IntfWindow::PlaybackPlay( void )
518 if( p_intf->p_input != NULL )
520 input_SetStatus( p_intf->p_input, INPUT_STATUS_PLAY );
524 /*****************************************************************************
525 * PlaybackPause: pause
526 *****************************************************************************/
527 void IntfWindow::PlaybackPause( void )
529 if( p_intf->p_input != NULL )
531 input_SetStatus( p_intf->p_input, INPUT_STATUS_PAUSE );
535 /*****************************************************************************
537 *****************************************************************************/
538 void IntfWindow::PlaybackSlow( void )
540 if( p_intf->p_input != NULL )
542 input_SetStatus( p_intf->p_input, INPUT_STATUS_SLOWER );
546 /*****************************************************************************
548 *****************************************************************************/
549 void IntfWindow::PlaybackFast( void )
551 if( p_intf->p_input != NULL )
553 input_SetStatus( p_intf->p_input, INPUT_STATUS_FASTER );
557 /*****************************************************************************
558 * PlaylistPrev: previous playlist entry
559 *****************************************************************************/
560 void IntfWindow::PlaylistPrev( void )
562 if( p_intf->p_input != NULL )
564 /* FIXME: temporary hack */
565 intf_PlaylistPrev( p_main->p_playlist );
566 intf_PlaylistPrev( p_main->p_playlist );
567 p_intf->p_input->b_eof = 1;
571 /*****************************************************************************
572 * PlaylistNext: next playlist entry
573 *****************************************************************************/
574 void IntfWindow::PlaylistNext( void )
576 if( p_intf->p_input != NULL )
578 /* FIXME: temporary hack */
579 p_intf->p_input->b_eof = 1;
583 /*****************************************************************************
584 * IntfSlider: slider creator
585 *****************************************************************************
586 * This function creates the slider, sets its default values, and connects
587 * the interesting signals.
588 *****************************************************************************/
589 IntfSlider::IntfSlider( intf_thread_t *p_intf, QWidget *p_parent )
590 :QSlider( Horizontal, p_parent )
592 this->p_intf = p_intf;
594 setRange( SLIDER_MIN, SLIDER_MAX );
595 setPageStep( SLIDER_STEP );
597 setValue( SLIDER_MIN );
598 setOldValue( SLIDER_MIN );
603 connect( this, SIGNAL(sliderMoved(int)), this, SLOT(SlideStart()) );
604 connect( this, SIGNAL(sliderPressed()), this, SLOT(SlideStart()) );
605 connect( this, SIGNAL(sliderReleased()), this, SLOT(SlideStop()) );
608 /*****************************************************************************
609 * ~IntfSlider: slider destructor
610 *****************************************************************************
611 * This function is called when the interface slider is destroyed.
612 *****************************************************************************/
613 IntfSlider::~IntfSlider( void )
615 /* We don't need to remove anything */