1 /*****************************************************************************
2 * intf.cpp: Qt interface
3 *****************************************************************************
4 * Copyright (C) 1999, 2000 VideoLAN
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 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
27 #include <errno.h> /* ENOMEM */
28 #include <stdlib.h> /* free() */
29 #include <string.h> /* strerror() */
34 #define SLIDER_MIN 0x00000
35 #define SLIDER_MAX 0x10000
36 #define SLIDER_STEP (SLIDER_MAX >> 4)
38 /*****************************************************************************
39 * intf_sys_t: description and status of Qt interface
40 *****************************************************************************/
46 input_thread_t *p_input;
49 /*****************************************************************************
51 *****************************************************************************/
52 static void Run ( intf_thread_t *p_intf );
54 /*****************************************************************************
55 * Open: initialize and create window
56 *****************************************************************************/
57 int E_(Open) ( vlc_object_t *p_this )
59 intf_thread_t *p_intf = (intf_thread_t*) p_this;
60 char *pp_argv[] = { "" };
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 )
67 msg_Err( p_intf, "out of memory" );
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 );
77 /* Tell the world we are here */
78 p_intf->p_sys->p_window->setCaption( VOUT_TITLE " (Qt interface)" );
80 p_intf->p_sys->p_input = NULL;
85 /*****************************************************************************
86 * Close: destroy interface window
87 *****************************************************************************/
88 void E_(Close) ( vlc_object_t *p_this )
90 intf_thread_t *p_intf = (intf_thread_t*) p_this;
92 if( p_intf->p_sys->p_input )
94 vlc_object_release( p_intf->p_sys->p_input );
97 /* Get rid of the C++ objects */
98 delete p_intf->p_sys->p_window;
99 delete p_intf->p_sys->p_app;
101 /* Destroy structure */
102 free( p_intf->p_sys );
105 /*****************************************************************************
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 )
113 p_intf->p_sys->p_window->show();
115 p_intf->p_sys->p_app->exec();
118 /* following functions are local */
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 )
129 setUsesTextLabel( TRUE );
131 this->p_intf = p_intf;
137 p_toolbar = new QToolBar( this, "toolbar" );
138 p_toolbar->setHorizontalStretchable( TRUE );
140 QIconSet * set = new QIconSet();
141 QPixmap pixmap = set->pixmap( QIconSet::Automatic, QIconSet::Normal );
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()) );
164 QPopupMenu * p_tmpmenu = new QPopupMenu( this );
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 );
175 p_tmpmenu = new QPopupMenu( this );
176 menuBar()->insertItem( "&View", p_tmpmenu );
177 instmp0( "&Playlist...", SLOT(Unimplemented()) );
178 instmp0( "&Modules...", SLOT(Unimplemented()) );
180 p_tmpmenu = new QPopupMenu( this );
181 menuBar()->insertItem( "&Settings", p_tmpmenu );
182 instmp0( "&Preferences...", SLOT(Unimplemented()) );
184 p_tmpmenu = new QPopupMenu( this );
185 menuBar()->insertItem( "&Help", p_tmpmenu );
186 instmp0( "&About...", SLOT(About()) );
189 * Create the popup menu
192 p_popup = new QPopupMenu( /* floating menu */ );
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()) );
208 /* Activate the statusbar */
211 /* Add the vertical box */
212 QVBox * p_vbox = new QVBox( this );
213 setCentralWidget( p_vbox );
215 /* The horizontal box */
216 QHBox * p_hbox = new QHBox( p_vbox );
219 p_date = new QLabel( p_hbox );
220 p_date->setAlignment( AlignHCenter | AlignVCenter );
221 p_date->setText( "-:--:--" );
223 /* The status label */
224 QLabel *p_label = new QLabel( p_hbox );
225 p_label->setAlignment( AlignHCenter | AlignVCenter );
226 p_label->setText( "Status: foo" );
229 p_label = new QLabel( p_hbox );
230 p_label->setAlignment( AlignHCenter | AlignVCenter );
231 p_label->setText( "Bar: baz quux" );
233 /* Create the slider and connect it to the date label */
234 p_slider = new IntfSlider( p_intf, p_vbox );
236 connect( p_slider, SIGNAL(valueChanged(int)),
237 this, SLOT(DateDisplay(int)) );
240 QTimer *p_timer = new QTimer( this );
241 connect( p_timer, SIGNAL(timeout()), this, SLOT(Manage()) );
242 p_timer->start( INTF_IDLE_SLEEP / 1000 );
244 /* Everything worked fine */
248 /*****************************************************************************
249 * ~IntfWindow: interface window destructor
250 *****************************************************************************
251 * This function is called when the interface window is destroyed.
252 *****************************************************************************/
253 IntfWindow::~IntfWindow( void )
255 /* FIXME: remove everything cleanly */
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 )
265 if( p_intf->p_sys->p_input )
267 char psz_time[ MSTRTIME_MAX_SIZE ];
270 i_seconds = var_GetTime( p_intf->p_sys->p_input, "time" ) / I64C(1000000 );
271 secstotimestr( psz_time, i_seconds );
273 p_date->setText( psz_time );
277 /*****************************************************************************
278 * FileOpen: open a file
279 *****************************************************************************
280 * This function opens a file requester and adds the selected file to
282 *****************************************************************************/
283 void IntfWindow::FileOpen( void )
285 playlist_t *p_playlist;
286 QString file = QFileDialog::getOpenFileName( QString::null,
287 QString::null, this );
291 statusBar()->message( "No file loaded", 2000 );
295 p_playlist = (playlist_t *)
296 vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE );
297 if( p_playlist == NULL )
302 playlist_Add( p_playlist, file.latin1(), file.latin1(),
303 PLAYLIST_APPEND | PLAYLIST_GO, PLAYLIST_END );
304 vlc_object_release( p_playlist );
308 /*****************************************************************************
309 * FileQuit: terminate vlc
310 *****************************************************************************/
311 void IntfWindow::FileQuit( void )
313 p_intf->p_vlc->b_die = VLC_TRUE;
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 )
323 QMessageBox::about( this, "About",
325 "(C) 1996 - 2004 - the VideoLAN Team\n"
327 "This is the VLC media player, 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"
331 "More information: http://www.videolan.org/" );
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 )
342 /* Update the input */
343 if( p_intf->p_sys->p_input == NULL )
345 p_intf->p_sys->p_input = (input_thread_t *)
346 vlc_object_find( p_intf, VLC_OBJECT_INPUT, FIND_ANYWHERE );
348 else if( p_intf->p_sys->p_input->b_dead )
350 vlc_object_release( p_intf->p_sys->p_input );
351 p_intf->p_sys->p_input = NULL;
354 /* Manage the slider */
355 if( p_intf->p_sys->p_input && p_intf->p_sys->p_input->stream.b_seekable )
357 int i_value = p_slider->value();
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() )
364 i_value = ( SLIDER_MAX * p_area->i_tell ) / p_area->i_size;
366 p_slider->setValue( i_value );
367 p_slider->setOldValue( i_value );
369 /* Otherwise, send message to the input if the user has
370 * finished dragging the slider */
371 else if( p_slider->b_free )
373 double f_pos = (double)i_value / (double)SLIDER_MAX;
374 var_SetFloat( p_intf->p_sys->p_input, "position", f_pos );
376 /* Update the old value */
377 p_slider->setOldValue( i_value );
382 /* If the "display popup" flag has changed, popup the context menu */
383 if( p_intf->b_menu_change )
385 p_popup->popup( QCursor::pos() );
386 p_intf->b_menu_change = 0;
395 /*****************************************************************************
397 *****************************************************************************/
398 void IntfWindow::PlaybackPlay( void )
400 if( p_intf->p_sys->p_input != NULL )
402 var_SetInteger( p_intf->p_sys->p_input, "state", PLAYING_S );
406 /*****************************************************************************
407 * PlaybackPause: pause
408 *****************************************************************************/
409 void IntfWindow::PlaybackPause( void )
411 if( p_intf->p_sys->p_input != NULL )
413 var_SetInteger( p_intf->p_sys->p_input, "state", PAUSE_S );
417 /*****************************************************************************
419 *****************************************************************************/
420 void IntfWindow::PlaybackSlow( void )
422 if( p_intf->p_sys->p_input != NULL )
424 var_SetVoid( p_intf->p_sys->p_input, "rate-slower" );
428 /*****************************************************************************
430 *****************************************************************************/
431 void IntfWindow::PlaybackFast( void )
433 if( p_intf->p_sys->p_input != NULL )
435 var_SetVoid( p_intf->p_sys->p_input, "rate-faster" );
439 /*****************************************************************************
440 * PlaylistPrev: previous playlist entry
441 *****************************************************************************/
442 void IntfWindow::PlaylistPrev( void )
444 playlist_t *p_playlist = (playlist_t *)
445 vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE );
447 if( p_playlist == NULL )
452 playlist_Prev( p_playlist );
453 vlc_object_release( p_playlist );
456 /*****************************************************************************
457 * PlaylistNext: next playlist entry
458 *****************************************************************************/
459 void IntfWindow::PlaylistNext( void )
461 playlist_t *p_playlist = (playlist_t *)
462 vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE );
464 if( p_playlist == NULL )
469 playlist_Next( p_playlist );
470 vlc_object_release( p_playlist );
473 /*****************************************************************************
474 * IntfSlider: slider creator
475 *****************************************************************************
476 * This function creates the slider, sets its default values, and connects
477 * the interesting signals.
478 *****************************************************************************/
479 IntfSlider::IntfSlider( intf_thread_t *p_intf, QWidget *p_parent )
480 :QSlider( Horizontal, p_parent )
482 this->p_intf = p_intf;
484 setRange( SLIDER_MIN, SLIDER_MAX );
485 setPageStep( SLIDER_STEP );
487 setValue( SLIDER_MIN );
488 setOldValue( SLIDER_MIN );
493 connect( this, SIGNAL(sliderMoved(int)), this, SLOT(SlideStart()) );
494 connect( this, SIGNAL(sliderPressed()), this, SLOT(SlideStart()) );
495 connect( this, SIGNAL(sliderReleased()), this, SLOT(SlideStop()) );
498 /*****************************************************************************
499 * ~IntfSlider: slider destructor
500 *****************************************************************************
501 * This function is called when the interface slider is destroyed.
502 *****************************************************************************/
503 IntfSlider::~IntfSlider( void )
505 /* We don't need to remove anything */