]> git.sesse.net Git - vlc/blob - modules/gui/wxwidgets/interface.cpp
* modules/gui/wxwidgets/interface.cpp: slightly smaller interface size.
[vlc] / modules / gui / wxwidgets / interface.cpp
1 /*****************************************************************************
2  * interface.cpp : wxWidgets plugin for vlc
3  *****************************************************************************
4  * Copyright (C) 2000-2005 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Gildas Bazin <gbazin@videolan.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 "interface.hpp"
28 #include "extrapanel.hpp"
29 #include "timer.hpp"
30 #include "video.hpp"
31 #include <vlc_keys.h>
32
33 #include "charset.h"
34
35 #include <vlc/aout.h>
36 #include "charset.h"
37
38 /* include the toolbar graphics */
39 #include "bitmaps/play.xpm"
40 #include "bitmaps/pause.xpm"
41 #include "bitmaps/stop.xpm"
42 #include "bitmaps/prev.xpm"
43 #include "bitmaps/next.xpm"
44 #include "bitmaps/eject.xpm"
45 #include "bitmaps/slow.xpm"
46 #include "bitmaps/fast.xpm"
47 #include "bitmaps/playlist.xpm"
48 #include "bitmaps/speaker.xpm"
49 #include "bitmaps/speaker_mute.xpm"
50
51 #define TOOLBAR_BMP_WIDTH 16
52 #define TOOLBAR_BMP_HEIGHT 16
53
54 /* include the icon graphic */
55 #include "../../../share/vlc32x32.xpm"
56 /* include a small icon graphic for the systray icon */
57 #ifdef wxHAS_TASK_BAR_ICON
58 #include "../../../share/vlc16x16.xpm"
59 #endif
60
61 /*****************************************************************************
62  * Local class declarations.
63  *****************************************************************************/
64 class wxMenuExt: public wxMenu
65 {
66 public:
67     /* Constructor */
68     wxMenuExt( wxMenu* parentMenu, int id, const wxString& text,
69                    const wxString& helpString, wxItemKind kind,
70                    char *_psz_var, int _i_object_id, vlc_value_t _val,
71                    int _i_val_type );
72
73     virtual ~wxMenuExt() {};
74
75     char *psz_var;
76     int  i_val_type;
77     int  i_object_id;
78     vlc_value_t val;
79
80 private:
81
82 };
83
84 class wxVolCtrl;
85 class VLCVolCtrl : public wxControl
86 {
87 public:
88     VLCVolCtrl( intf_thread_t *p_intf, wxWindow *p_parent );
89     virtual ~VLCVolCtrl() {};
90
91     virtual void OnPaint( wxPaintEvent &event );
92     void OnChange( wxMouseEvent& event );
93     void UpdateVolume();
94
95   private:
96     DECLARE_EVENT_TABLE()
97
98     wxVolCtrl *gauge;
99     int i_y_offset;
100     vlc_bool_t b_mute;
101     intf_thread_t *p_intf;
102 };
103
104 BEGIN_EVENT_TABLE(VLCVolCtrl, wxControl)
105     EVT_PAINT(VLCVolCtrl::OnPaint)
106
107     /* Mouse events */
108     EVT_LEFT_UP(VLCVolCtrl::OnChange)
109 END_EVENT_TABLE()
110
111 /*****************************************************************************
112  * Event Table.
113  *****************************************************************************/
114
115 DEFINE_LOCAL_EVENT_TYPE( wxEVT_INTF );
116
117 /* IDs for the controls and the menu commands */
118 enum
119 {
120     /* menu items */
121     MenuDummy_Event = wxID_HIGHEST + 1000,
122     Exit_Event = wxID_HIGHEST,
123     OpenFileSimple_Event,
124     OpenAdv_Event,
125     OpenFile_Event,
126     OpenDir_Event,
127     OpenDisc_Event,
128     OpenNet_Event,
129     OpenCapture_Event,
130     OpenSat_Event,
131     OpenOther_Event,
132     EjectDisc_Event,
133
134     Wizard_Event,
135
136     Playlist_Event,
137     Logs_Event,
138     FileInfo_Event,
139
140     Prefs_Event,
141     Extended_Event,
142     Bookmarks_Event,
143     Skins_Event,
144
145     StopStream_Event,
146     PlayStream_Event,
147     PrevStream_Event,
148     NextStream_Event,
149     SlowStream_Event,
150     FastStream_Event,
151
152     /* it is important for the id corresponding to the "About" command to have
153      * this standard value as otherwise it won't be handled properly under Mac
154      * (where it is special and put into the "Apple" menu) */
155     About_Event = wxID_ABOUT,
156     UpdateVLC_Event,
157     VLM_Event,
158
159     Iconize_Event
160 };
161
162 BEGIN_EVENT_TABLE(Interface, wxFrame)
163     /* Menu events */
164     EVT_MENU(Exit_Event, Interface::OnExit)
165     EVT_MENU(About_Event, Interface::OnAbout)
166     EVT_MENU(UpdateVLC_Event, Interface::OnShowDialog)
167     EVT_MENU(VLM_Event, Interface::OnShowDialog)
168
169     EVT_MENU(Playlist_Event, Interface::OnShowDialog)
170     EVT_MENU(Logs_Event, Interface::OnShowDialog)
171     EVT_MENU(FileInfo_Event, Interface::OnShowDialog)
172     EVT_MENU(Prefs_Event, Interface::OnShowDialog)
173
174     EVT_MENU_OPEN(Interface::OnMenuOpen)
175
176     EVT_MENU( Extended_Event, Interface::OnExtended )
177
178     EVT_MENU( Bookmarks_Event, Interface::OnShowDialog)
179
180 #if defined( __WXMSW__ ) || defined( __WXMAC__ )
181     EVT_CONTEXT_MENU(Interface::OnContextMenu2)
182 #endif
183     EVT_RIGHT_UP(Interface::OnContextMenu)
184
185     /* Toolbar events */
186     EVT_MENU(OpenFileSimple_Event, Interface::OnShowDialog)
187     EVT_MENU(OpenAdv_Event, Interface::OnShowDialog)
188     EVT_MENU(OpenFile_Event, Interface::OnShowDialog)
189     EVT_MENU(OpenDir_Event, Interface::OnShowDialog)
190     EVT_MENU(OpenDisc_Event, Interface::OnShowDialog)
191     EVT_MENU(OpenNet_Event, Interface::OnShowDialog)
192     EVT_MENU(OpenCapture_Event, Interface::OnShowDialog)
193     EVT_MENU(OpenSat_Event, Interface::OnShowDialog)
194     EVT_MENU(Wizard_Event, Interface::OnShowDialog)
195     EVT_MENU(StopStream_Event, Interface::OnStopStream)
196     EVT_MENU(PlayStream_Event, Interface::OnPlayStream)
197     EVT_MENU(PrevStream_Event, Interface::OnPrevStream)
198     EVT_MENU(NextStream_Event, Interface::OnNextStream)
199     EVT_MENU(SlowStream_Event, Interface::OnSlowStream)
200     EVT_MENU(FastStream_Event, Interface::OnFastStream)
201
202     /* Custom events */
203     EVT_COMMAND(0, wxEVT_INTF, Interface::OnControlEvent)
204     EVT_COMMAND(1, wxEVT_INTF, Interface::OnControlEvent)
205 END_EVENT_TABLE()
206
207 /*****************************************************************************
208  * Constructor.
209  *****************************************************************************/
210 Interface::Interface( intf_thread_t *_p_intf, long style ):
211     wxFrame( NULL, -1, wxT("VLC media player"),
212              wxDefaultPosition, wxSize(700,100), style )
213 {
214     /* Initializations */
215     p_intf = _p_intf;
216     b_extra = VLC_FALSE;
217     extra_frame = 0;
218
219     /* Give our interface a nice little icon */
220     SetIcon( wxIcon( vlc_xpm ) );
221
222     /* Create a main panel that will fill in the interface window */
223     main_sizer = new wxBoxSizer( wxVERTICAL );
224     SetSizer( main_sizer );
225     main_panel = new wxPanel( this, -1, wxPoint(0,0), wxSize(0,0),
226                               wxCLIP_CHILDREN );
227     main_sizer->Add( main_panel, 1, wxEXPAND );
228     main_panel->SetFocus();
229
230 #if defined(__WXGTK20__) && wxCHECK_VERSION(2,5,6)
231     /* As ugly as your butt! Please remove when wxWidgets 2.6 fixed their
232      * Accelerators bug. */
233     main_panel->m_imData = 0;
234     m_imData = 0;
235 #endif
236
237     /* Create a sizer for the main frame */
238     panel_sizer = new wxBoxSizer( wxVERTICAL );
239     main_panel->SetSizer( panel_sizer );
240
241 #ifdef wxHAS_TASK_BAR_ICON
242     /* Systray integration */
243     p_systray = NULL;
244     if( config_GetInt( p_intf, "wx-systray" ) )
245     {
246         p_systray = new Systray( this, p_intf );
247     }
248 #endif
249
250     /* Creation of the menu bar */
251     CreateOurMenuBar();
252
253     /* Creation of the tool bar */
254     CreateOurToolBar();
255
256     /* Creation of the status bar
257      * Helptext for menu items and toolbar tools will automatically get
258      * displayed here. */
259     int i_status_width[3] = {-6, -2, -9};
260     statusbar = CreateStatusBar( 3 );                            /* 2 fields */
261     statusbar->SetStatusWidths( 3, i_status_width );
262     statusbar->SetStatusText( wxString::Format(wxT("x%.2f"), 1.0), 1 );
263
264     /* Get minimum window size to prevent user from glitching it */
265     main_panel->SetSizeHints( wxSize(-1,0) );
266     panel_sizer->Layout(); panel_sizer->Fit( main_panel );
267     main_sizer->Layout(); main_sizer->Fit( this );
268     main_min_size = GetSize();
269     main_panel->SetSizeHints( wxSize(-1,-1) );
270
271     /* Video window */
272     video_window = 0;
273     if( config_GetInt( p_intf, "wx-embed" ) )
274     {
275         video_window = CreateVideoWindow( p_intf, main_panel );
276         panel_sizer->Add( p_intf->p_sys->p_video_sizer, 1, wxEXPAND, 0 );
277     }
278
279     /* Creation of the input manager panel */
280     input_manager = new InputManager( p_intf, this, main_panel );
281     panel_sizer->Add( input_manager, 0, wxEXPAND , 0 );
282
283     /* Layout everything */
284     main_panel->SetSizeHints( wxSize(-1,0) );
285     panel_sizer->Layout(); panel_sizer->Fit( main_panel );
286     main_sizer->Layout(); main_sizer->Fit( this );
287     main_panel->SetSizeHints( wxSize(-1,-1) );
288
289 #if wxUSE_DRAG_AND_DROP
290     /* Associate drop targets with the main interface */
291     SetDropTarget( new DragAndDrop( p_intf ) );
292 #endif
293
294     SetupHotkeys();
295
296     /* Start timer */
297     timer = new Timer( p_intf, this );
298
299     /* Restore previous position / settings */
300     WindowSettings *ws = p_intf->p_sys->p_window_settings;
301     wxPoint p;
302     wxSize s;
303     bool b_shown;
304
305     ws->SetScreen( wxSystemSettings::GetMetric( wxSYS_SCREEN_X ),
306                    wxSystemSettings::GetMetric( wxSYS_SCREEN_Y ) );
307
308     if( ws->GetSettings( WindowSettings::ID_MAIN, b_shown, p, s ) ) Move( p );
309
310     /* Show extended GUI if requested */
311     wxCommandEvent dummy;
312     if( config_GetInt( p_intf, "wx-extended" ) ) OnExtended( dummy );
313
314     SetIntfMinSize();
315 }
316
317 Interface::~Interface()
318 {
319     WindowSettings *ws = p_intf->p_sys->p_window_settings;
320
321     if( !IsIconized() )
322     {
323         ws->SetSettings( WindowSettings::ID_MAIN, true,
324                          GetPosition(), GetSize() );
325     }
326
327     PopEventHandler(true);
328
329     if( video_window ) delete video_window;
330
331 #ifdef wxHAS_TASK_BAR_ICON
332     if( p_systray ) delete p_systray;
333 #endif
334
335     if( p_intf->p_sys->p_wxwindow ) delete p_intf->p_sys->p_wxwindow;
336
337     /* Clean up */
338     delete timer;
339 }
340
341 void Interface::Init()
342 {
343     /* Misc init */
344     SetupHotkeys();
345 }
346
347 void Interface::Update()
348 {
349     /* Misc updates */
350     ((VLCVolCtrl *)volctrl)->UpdateVolume();
351 }
352
353 void Interface::OnControlEvent( wxCommandEvent& event )
354 {
355     switch( event.GetId() )
356     {
357     case 0:
358         main_sizer->Layout();
359         main_sizer->Fit( this );
360         break;
361
362     case 1:
363         long i_style = GetWindowStyle();
364         if( event.GetInt() ) i_style |= wxSTAY_ON_TOP;
365         else i_style &= ~wxSTAY_ON_TOP;
366         SetWindowStyle( i_style );
367         break;
368     }
369 }
370
371 /*****************************************************************************
372  * Private methods.
373  *****************************************************************************/
374 void Interface::CreateOurMenuBar()
375 {
376     int minimal = config_GetInt( p_intf, "wx-minimal" );
377
378     /* Create the "File" menu */
379     wxMenu *file_menu = new wxMenu;
380
381     if (!minimal)
382     {
383     file_menu->Append( OpenFileSimple_Event,
384                        wxU(_("Quick &Open File...\tCtrl-O")) );
385
386     file_menu->AppendSeparator();
387     file_menu->Append( OpenFile_Event, wxU(_("Open &File...\tCtrl-F")) );
388     file_menu->Append( OpenDir_Event, wxU(_("Open Dir&ectory...\tCtrl-E")) );
389     file_menu->Append( OpenDisc_Event, wxU(_("Open &Disc...\tCtrl-D")) );
390     file_menu->Append( OpenNet_Event,
391                        wxU(_("Open &Network Stream...\tCtrl-N")) );
392     file_menu->Append( OpenCapture_Event,
393                        wxU(_("Open C&apture Device...\tCtrl-A")) );
394
395     file_menu->AppendSeparator();
396     file_menu->Append( Wizard_Event, wxU(_("&Wizard...\tCtrl-W")) );
397     file_menu->AppendSeparator();
398     }
399     file_menu->Append( Exit_Event, wxU(_("E&xit\tCtrl-X")) );
400
401     /* Create the "View" menu */
402     wxMenu *view_menu = new wxMenu;
403     if (!minimal)
404     {
405     view_menu->Append( Playlist_Event, wxU(_("&Playlist...\tCtrl-P")) );
406     }
407     view_menu->Append( Logs_Event, wxU(_("&Messages...\tCtrl-M")) );
408     view_menu->Append( FileInfo_Event,
409                        wxU(_("Stream and Media &info...\tCtrl-I")) );
410     view_menu->Append( VLM_Event,
411                        wxU(_("VLM Control...\tCtrl-V")) );
412
413     /* Create the "Auto-generated" menus */
414     p_settings_menu = SettingsMenu( p_intf, this );
415     p_audio_menu = AudioMenu( p_intf, this );
416     p_video_menu = VideoMenu( p_intf, this );
417     p_navig_menu = NavigMenu( p_intf, this );
418
419     /* Create the "Help" menu */
420     wxMenu *help_menu = new wxMenu;
421     help_menu->Append( About_Event, wxU(_("About VLC media player")) );
422     help_menu->AppendSeparator();
423     help_menu->Append( UpdateVLC_Event, wxU(_("Check for updates ...")) );
424
425     /* Append the freshly created menus to the menu bar... */
426     wxMenuBar *menubar = new wxMenuBar();
427     menubar->Append( file_menu, wxU(_("&File")) );
428     menubar->Append( view_menu, wxU(_("&View")) );
429     menubar->Append( p_settings_menu, wxU(_("&Settings")) );
430     menubar->Append( p_audio_menu, wxU(_("&Audio")) );
431     menubar->Append( p_video_menu, wxU(_("&Video")) );
432     menubar->Append( p_navig_menu, wxU(_("&Navigation")) );
433     menubar->Append( help_menu, wxU(_("&Help")) );
434
435     /* Attach the menu bar to the frame */
436     SetMenuBar( menubar );
437
438     /* Find out size of menu bar */
439     int i_size = 0;
440     for( unsigned int i = 0; i < menubar->GetMenuCount(); i++ )
441     {
442         int i_width, i_height;
443         menubar->GetTextExtent( menubar->GetLabelTop(i), &i_width, &i_height );
444         i_size += i_width +
445 #if defined(__WXGTK__)
446             22 /* approximate margin */;
447 #else
448 #if (wxMAJOR_VERSION <= 2) && (wxMINOR_VERSION <= 5) && (wxRELEASE_NUMBER < 3)
449             4 /* approximate margin */;
450 #else
451             18 /* approximate margin */;
452 #endif
453 #endif
454     }
455
456 /* Patch by zcot for menu wrapping */
457 #if defined(WIN32)
458     /* Find out size of msw menu bar */
459     i_size = 0;
460     SIZE sizing;
461     HDC hdc = GetDC( NULL );
462     for( unsigned int i = 0; i < menubar->GetMenuCount(); i++ )
463     {
464         GetTextExtentPoint32( hdc, menubar->GetLabelTop(i).c_str(),
465                                 menubar->GetLabelTop(i).Length(), &sizing );
466
467         // [ SM_CXDLGFRAME + pixels + textextent + pixels + SM_CXDLGFRAME ]
468         i_size += sizing.cx + 2 + GetSystemMetrics( SM_CXDLGFRAME ) * 2;
469     }
470     ReleaseDC( NULL, hdc );
471     i_size += GetSystemMetrics( SM_CXSIZEFRAME ) * 2 + 4;
472 #endif
473 /* End patch by zcot */
474
475     panel_sizer->SetMinSize( i_size, -1 );
476
477     /* Intercept all menu events in our custom event handler */
478     PushEventHandler( new MenuEvtHandler( p_intf, this ) );
479
480 #if wxUSE_DRAG_AND_DROP
481     /* Associate drop targets with the menubar */
482     menubar->SetDropTarget( new DragAndDrop( p_intf ) );
483 #endif
484 }
485
486 void Interface::CreateOurToolBar()
487 {
488 #define HELP_OPEN N_("Open")
489 #define HELP_STOP N_("Stop")
490 #define HELP_PLAY N_("Play")
491 #define HELP_PAUSE N_("Pause")
492 #define HELP_PLO N_("Playlist")
493 #define HELP_PLP N_("Previous playlist item")
494 #define HELP_PLN N_("Next playlist item")
495 #define HELP_SLOW N_("Play slower")
496 #define HELP_FAST N_("Play faster")
497
498     int minimal = config_GetInt( p_intf, "wx-minimal" );
499
500     wxLogNull LogDummy; /* Hack to suppress annoying log message on the win32
501                          * version because we don't include wx.rc */
502
503     wxToolBar *toolbar =
504         CreateToolBar( wxTB_HORIZONTAL | wxTB_FLAT );
505
506     toolbar->SetToolBitmapSize( wxSize(TOOLBAR_BMP_WIDTH,TOOLBAR_BMP_HEIGHT) );
507
508     if (!minimal)
509     {
510     toolbar->AddTool( OpenFile_Event, wxT(""),
511                       wxBitmap( eject_xpm ), wxU(_(HELP_OPEN)) );
512     toolbar->AddSeparator();
513     }
514
515     wxToolBarToolBase *p_tool = toolbar->AddTool( PlayStream_Event, wxT(""),
516                       wxBitmap( play_xpm ), wxU(_(HELP_PLAY)), wxITEM_CHECK );
517     p_tool->SetClientData( p_tool );
518
519     if (!minimal)
520     {
521     toolbar->AddTool( StopStream_Event, wxT(""), wxBitmap( stop_xpm ),
522                       wxU(_(HELP_STOP)) );
523     toolbar->AddSeparator();
524
525     toolbar->AddTool( PrevStream_Event, wxT(""),
526                       wxBitmap( prev_xpm ), wxU(_(HELP_PLP)) );
527     toolbar->AddTool( SlowStream_Event, wxT(""),
528                       wxBitmap( slow_xpm ), wxU(_(HELP_SLOW)) );
529     toolbar->AddTool( FastStream_Event, wxT(""),
530                       wxBitmap( fast_xpm ), wxU(_(HELP_FAST)) );
531     toolbar->AddTool( NextStream_Event, wxT(""), wxBitmap( next_xpm ),
532                       wxU(_(HELP_PLN)) );
533     toolbar->AddSeparator();
534     toolbar->AddTool( Playlist_Event, wxT(""), wxBitmap( playlist_xpm ),
535                       wxU(_(HELP_PLO)) );
536     }
537
538 #if !( (wxMAJOR_VERSION <= 2) && (wxMINOR_VERSION <= 6) && (wxRELEASE_NUMBER < 2) )
539     wxControl *p_dummy_ctrl =
540         new wxControl( toolbar, -1, wxDefaultPosition,
541                        wxSize(35, 16 ), wxBORDER_NONE );
542
543     toolbar->AddControl( p_dummy_ctrl );
544 #endif
545
546     volctrl = new VLCVolCtrl( p_intf, toolbar );
547     toolbar->AddControl( volctrl );
548
549     toolbar->Realize();
550
551 #if wxUSE_DRAG_AND_DROP
552     /* Associate drop targets with the toolbar */
553     toolbar->SetDropTarget( new DragAndDrop( p_intf ) );
554 #endif
555 }
556
557 static int ConvertHotkeyModifiers( int i_hotkey )
558 {
559     int i_accel_flags = 0;
560     if( i_hotkey & KEY_MODIFIER_ALT ) i_accel_flags |= wxACCEL_ALT;
561     if( i_hotkey & KEY_MODIFIER_CTRL ) i_accel_flags |= wxACCEL_CTRL;
562     if( i_hotkey & KEY_MODIFIER_SHIFT ) i_accel_flags |= wxACCEL_SHIFT;
563     if( !i_accel_flags ) i_accel_flags = wxACCEL_NORMAL;
564     return i_accel_flags;
565 }
566
567 static int ConvertHotkey( int i_hotkey )
568 {
569     int i_key = i_hotkey & ~KEY_MODIFIER;
570     if( i_key & KEY_ASCII ) return i_key & KEY_ASCII;
571     else if( i_key & KEY_SPECIAL )
572     {
573         switch ( i_key )
574         {
575         case KEY_LEFT: return WXK_LEFT;
576         case KEY_RIGHT: return WXK_RIGHT;
577         case KEY_UP: return WXK_UP;
578         case KEY_DOWN: return WXK_DOWN;
579         case KEY_SPACE: return WXK_SPACE;
580         case KEY_ENTER: return WXK_RETURN;
581         case KEY_F1: return WXK_F1;
582         case KEY_F2: return WXK_F2;
583         case KEY_F3: return WXK_F3;
584         case KEY_F4: return WXK_F4;
585         case KEY_F5: return WXK_F5;
586         case KEY_F6: return WXK_F6;
587         case KEY_F7: return WXK_F7;
588         case KEY_F8: return WXK_F8;
589         case KEY_F9: return WXK_F9;
590         case KEY_F10: return WXK_F10;
591         case KEY_F11: return WXK_F11;
592         case KEY_F12: return WXK_F12;
593         case KEY_HOME: return WXK_HOME;
594         case KEY_END: return WXK_END;
595         case KEY_INSERT: return WXK_INSERT;
596         case KEY_DELETE: return WXK_DELETE;
597         case KEY_MENU: return WXK_MENU;
598         case KEY_ESC: return WXK_ESCAPE;
599         case KEY_PAGEUP: return WXK_PRIOR;
600         case KEY_PAGEDOWN: return WXK_NEXT;
601         case KEY_TAB: return WXK_TAB;
602         case KEY_BACKSPACE: return WXK_BACK;
603         }
604     }
605     return WXK_F24;
606 }
607
608 void Interface::SetupHotkeys()
609 {
610     struct vlc_t::hotkey *p_hotkeys = p_intf->p_vlc->p_hotkeys;
611     int i_hotkeys;
612
613     /* Count number of hoteys */
614     for( i_hotkeys = 0; p_hotkeys[i_hotkeys].psz_action != NULL; i_hotkeys++ );
615
616     p_intf->p_sys->i_first_hotkey_event = wxID_HIGHEST + 7000;
617     p_intf->p_sys->i_hotkeys = i_hotkeys;
618
619     wxAcceleratorEntry *p_entries = new wxAcceleratorEntry[i_hotkeys];
620
621     /* Setup the hotkeys as accelerators */
622     for( int i = 0; i < i_hotkeys; i++ )
623     {
624         int i_mod = ConvertHotkeyModifiers( p_hotkeys[i].i_key );
625         int i_key = ConvertHotkey( p_hotkeys[i].i_key );
626
627 #ifdef WIN32
628         if( !(p_hotkeys[i].i_key & KEY_SPECIAL) && i_mod )
629             i_key = toupper(i_key);
630 #endif
631
632         p_entries[i].Set( i_mod, i_key,
633                           p_intf->p_sys->i_first_hotkey_event + i );
634     }
635
636     wxAcceleratorTable accel( i_hotkeys, p_entries );
637
638     if( !accel.Ok() )
639     {
640         msg_Err( p_intf, "invalid accelerator table" );
641     }
642     else
643     {
644         SetAcceleratorTable( accel );
645     }
646
647     delete [] p_entries;
648 }
649
650 void Interface::SetIntfMinSize()
651 {
652     wxSize ms = main_min_size;
653
654     if( extra_frame && extra_frame->IsShown() )
655     {
656         ms.SetHeight( ms.GetHeight() + ext_min_size.GetHeight() );
657         if( ext_min_size.GetWidth() > ms.GetWidth() )
658             ms.SetWidth( ext_min_size.GetWidth() );
659     }
660
661     SetSizeHints( ms );
662 }
663
664 /*****************************************************************************
665  * Event Handlers.
666  *****************************************************************************/
667 void Interface::OnMenuOpen( wxMenuEvent& event )
668 {
669 #if defined( __WXMSW__ )
670 #   define GetEventObject GetMenu
671 #endif
672
673     if( event.GetEventObject() == p_settings_menu )
674     {
675         p_settings_menu = SettingsMenu( p_intf, this, p_settings_menu );
676
677         /* Add static items */
678         p_settings_menu->AppendCheckItem( Extended_Event,
679             wxU(_("Extended &GUI\tCtrl-G") ) );
680         if( b_extra ) p_settings_menu->Check( Extended_Event, TRUE );
681         p_settings_menu->Append( Bookmarks_Event,
682                                  wxU(_("&Bookmarks...\tCtrl-B") ) );
683         p_settings_menu->Append( Prefs_Event,
684                                  wxU(_("Preference&s...\tCtrl-S")) );
685     }
686
687     else if( event.GetEventObject() == p_audio_menu )
688     {
689         p_audio_menu = AudioMenu( p_intf, this, p_audio_menu );
690     }
691
692     else if( event.GetEventObject() == p_video_menu )
693     {
694         p_video_menu = VideoMenu( p_intf, this, p_video_menu );
695     }
696
697     else if( event.GetEventObject() == p_navig_menu )
698     {
699         p_navig_menu = NavigMenu( p_intf, this, p_navig_menu );
700     }
701
702 #if defined( __WXMSW__ )
703 #   undef GetEventObject
704 #endif
705 }
706
707 #if defined( __WXMSW__ ) || defined( __WXMAC__ )
708 void Interface::OnContextMenu2(wxContextMenuEvent& event)
709 {
710     /* Only show the context menu for the main interface */
711     if( GetId() != event.GetId() )
712     {
713         event.Skip();
714         return;
715     }
716
717     if( p_intf->p_sys->pf_show_dialog )
718         p_intf->p_sys->pf_show_dialog( p_intf, INTF_DIALOG_POPUPMENU, 1, 0 );
719 }
720 #endif
721 void Interface::OnContextMenu(wxMouseEvent& event)
722 {
723     if( p_intf->p_sys->pf_show_dialog )
724         p_intf->p_sys->pf_show_dialog( p_intf, INTF_DIALOG_POPUPMENU, 1, 0 );
725 }
726
727 void Interface::OnExit( wxCommandEvent& WXUNUSED(event) )
728 {
729     /* TRUE is to force the frame to close. */
730     Close(TRUE);
731 }
732
733 void Interface::OnAbout( wxCommandEvent& WXUNUSED(event) )
734 {
735     wxString msg;
736     msg.Printf( wxString(wxT("VLC media player " PACKAGE_VERSION)) +
737         wxU(_(" (wxWidgets interface)\n\n")) +
738         wxU(_("(c) 1996-2005 - the VideoLAN Team\n\n")) +
739        wxU(_("Compiled by "))+ wxU(VLC_CompileBy())+ wxU("@") +
740        wxU(VLC_CompileHost())+ wxT(".")+ wxU(VLC_CompileDomain())+ wxT(".\n") +
741        wxU(_("Compiler: "))+ wxU(VLC_Compiler())+wxT( ".\n") +
742        wxU(_("Based on SVN revision: "))+wxU(VLC_Changeset())+wxT(".\n\n") +
743 #ifdef __WXMSW__
744         wxU( vlc_wraptext(LICENSE_MSG,WRAPCOUNT,VLC_TRUE) ) + wxT("\n\n") +
745 #else
746         wxU( LICENSE_MSG ) + wxT("\n\n") +
747 #endif
748         wxU(_("The VideoLAN team <videolan@videolan.org>\n"
749               "http://www.videolan.org/\n\n")) );
750
751     wxMessageBox( msg, wxString::Format(wxU(_("About %s")),
752                   wxT("VLC media player")), wxOK | wxICON_INFORMATION, this );
753 }
754
755 void Interface::OnShowDialog( wxCommandEvent& event )
756 {
757     if( p_intf->p_sys->pf_show_dialog )
758     {
759         int i_id;
760
761         switch( event.GetId() )
762         {
763         case OpenFileSimple_Event:
764             i_id = INTF_DIALOG_FILE_SIMPLE;
765             break;
766         case OpenAdv_Event:
767             i_id = INTF_DIALOG_FILE;
768             break;
769         case OpenFile_Event:
770             i_id = INTF_DIALOG_FILE;
771             break;
772         case OpenDir_Event:
773             i_id = INTF_DIALOG_DIRECTORY;
774             break;
775         case OpenDisc_Event:
776             i_id = INTF_DIALOG_DISC;
777             break;
778         case OpenNet_Event:
779             i_id = INTF_DIALOG_NET;
780             break;
781         case OpenCapture_Event:
782             i_id = INTF_DIALOG_CAPTURE;
783             break;
784         case OpenSat_Event:
785             i_id = INTF_DIALOG_SAT;
786             break;
787         case Playlist_Event:
788             i_id = INTF_DIALOG_PLAYLIST;
789             break;
790         case Logs_Event:
791             i_id = INTF_DIALOG_MESSAGES;
792             break;
793         case FileInfo_Event:
794             i_id = INTF_DIALOG_FILEINFO;
795             break;
796         case Prefs_Event:
797             i_id = INTF_DIALOG_PREFS;
798             break;
799         case Wizard_Event:
800             i_id = INTF_DIALOG_WIZARD;
801             break;
802         case Bookmarks_Event:
803             i_id = INTF_DIALOG_BOOKMARKS;
804             break;
805         case UpdateVLC_Event:
806             i_id = INTF_DIALOG_UPDATEVLC;
807             break;
808         case VLM_Event:
809             i_id = INTF_DIALOG_VLM;
810             break;
811         default:
812             i_id = INTF_DIALOG_FILE;
813             break;
814         }
815
816         p_intf->p_sys->pf_show_dialog( p_intf, i_id, 1, 0 );
817     }
818 }
819
820 void Interface::OnExtended( wxCommandEvent& WXUNUSED(event) )
821 {
822     UpdateVideoWindow( p_intf, video_window );
823
824     if( !extra_frame )
825     {
826         /* Create the extra panel */
827         extra_frame = new ExtraPanel( p_intf, main_panel );
828         panel_sizer->Add( extra_frame, 0, wxEXPAND , 0 );
829         ext_min_size = extra_frame->GetBestSize();
830     }
831
832     b_extra = !b_extra;
833     panel_sizer->Show( extra_frame, b_extra );
834
835     SetIntfMinSize();
836     main_sizer->Layout();
837     main_sizer->Fit( this );
838 }
839
840 void Interface::OnPlayStream( wxCommandEvent& WXUNUSED(event) )
841 {
842     PlayStream();
843 }
844
845 void Interface::PlayStream()
846 {
847     wxCommandEvent dummy;
848     playlist_t *p_playlist =
849         (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
850                                        FIND_ANYWHERE );
851     if( p_playlist == NULL ) return;
852
853     if( p_playlist->i_size && p_playlist->i_enabled )
854     {
855         vlc_value_t state;
856
857         input_thread_t *p_input = (input_thread_t *)vlc_object_find( p_intf,
858                                                        VLC_OBJECT_INPUT,
859                                                        FIND_ANYWHERE );
860         if( p_input == NULL )
861         {
862             /* No stream was playing, start one */
863             playlist_Play( p_playlist );
864             vlc_object_release( p_playlist );
865             input_manager->Update();
866             return;
867         }
868
869         var_Get( p_input, "state", &state );
870         if( state.i_int != PAUSE_S )
871         {
872             /* A stream is being played, pause it */
873             state.i_int = PAUSE_S;
874         }
875         else
876         {
877             /* Stream is paused, resume it */
878             state.i_int = PLAYING_S;
879         }
880         var_Set( p_input, "state", state );
881
882         vlc_object_release( p_input );
883         vlc_object_release( p_playlist );
884         input_manager->Update();
885     }
886     else
887     {
888         /* If the playlist is empty, open a file requester instead */
889         vlc_object_release( p_playlist );
890         OnShowDialog( dummy );
891     }
892 }
893
894 void Interface::OnStopStream( wxCommandEvent& WXUNUSED(event) )
895 {
896     StopStream();
897 }
898 void Interface::StopStream()
899 {
900     playlist_t * p_playlist =
901         (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
902                                        FIND_ANYWHERE );
903     if( p_playlist == NULL )
904     {
905         return;
906     }
907
908     playlist_Stop( p_playlist );
909     vlc_object_release( p_playlist );
910     input_manager->Update();
911 }
912
913 void Interface::OnPrevStream( wxCommandEvent& WXUNUSED(event) )
914 {
915     PrevStream();
916 }
917
918 void Interface::PrevStream()
919 {
920     playlist_t * p_playlist =
921         (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
922                                        FIND_ANYWHERE );
923     if( p_playlist == NULL )
924     {
925         return;
926     }
927
928     playlist_Prev( p_playlist );
929     vlc_object_release( p_playlist );
930 }
931
932 void Interface::OnNextStream( wxCommandEvent& WXUNUSED(event) )
933 {
934     NextStream();
935 }
936
937 void Interface::NextStream()
938 {
939     playlist_t * p_playlist =
940         (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
941                                        FIND_ANYWHERE );
942     if( p_playlist == NULL )
943     {
944         return;
945     }
946     playlist_Next( p_playlist );
947     vlc_object_release( p_playlist );
948 }
949
950 void Interface::OnSlowStream( wxCommandEvent& WXUNUSED(event) )
951 {
952     input_thread_t *p_input =
953         (input_thread_t *)vlc_object_find( p_intf, VLC_OBJECT_INPUT,
954                                            FIND_ANYWHERE );
955     if( p_input )
956     {
957         vlc_value_t val; val.b_bool = VLC_TRUE;
958
959         var_Set( p_input, "rate-slower", val );
960         vlc_object_release( p_input );
961     }
962 }
963
964 void Interface::OnFastStream( wxCommandEvent& WXUNUSED(event) )
965 {
966     input_thread_t *p_input =
967         (input_thread_t *)vlc_object_find( p_intf, VLC_OBJECT_INPUT,
968                                            FIND_ANYWHERE );
969     if( p_input )
970     {
971         vlc_value_t val; val.b_bool = VLC_TRUE;
972
973         var_Set( p_input, "rate-faster", val );
974         vlc_object_release( p_input );
975     }
976 }
977
978 void Interface::TogglePlayButton( int i_playing_status )
979 {
980     wxToolBarToolBase *p_tool = (wxToolBarToolBase *)
981         GetToolBar()->GetToolClientData( PlayStream_Event );
982     if( !p_tool ) return;
983
984     if( i_playing_status == PLAYING_S )
985     {
986         p_tool->SetNormalBitmap( wxBitmap( pause_xpm ) );
987         p_tool->SetLabel( wxU(_("Pause")) );
988         p_tool->SetShortHelp( wxU(_(HELP_PAUSE)) );
989     }
990     else
991     {
992         p_tool->SetNormalBitmap( wxBitmap( play_xpm ) );
993         p_tool->SetLabel( wxU(_("Play")) );
994         p_tool->SetShortHelp( wxU(_(HELP_PLAY)) );
995     }
996
997     GetToolBar()->Realize();
998
999 #if defined( __WXMSW__ )
1000     /* Needed to work around a bug in wxToolBar::Realize() */
1001     GetToolBar()->SetSize( GetSize().GetWidth(),
1002                            GetToolBar()->GetSize().GetHeight() );
1003     GetToolBar()->Update();
1004 #endif
1005
1006     GetToolBar()->ToggleTool( PlayStream_Event, true );
1007     GetToolBar()->ToggleTool( PlayStream_Event, false );
1008 }
1009
1010 #if wxUSE_DRAG_AND_DROP
1011 /*****************************************************************************
1012  * Definition of DragAndDrop class.
1013  *****************************************************************************/
1014 DragAndDrop::DragAndDrop( intf_thread_t *_p_intf, vlc_bool_t _b_enqueue )
1015 {
1016     p_intf = _p_intf;
1017     b_enqueue = _b_enqueue;
1018 }
1019
1020 bool DragAndDrop::OnDropFiles( wxCoord, wxCoord,
1021                                const wxArrayString& filenames )
1022 {
1023     /* Add dropped files to the playlist */
1024
1025     playlist_t *p_playlist =
1026         (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
1027                                        FIND_ANYWHERE );
1028     if( p_playlist == NULL )
1029     {
1030         return FALSE;
1031     }
1032
1033     for( size_t i = 0; i < filenames.GetCount(); i++ )
1034     {
1035         char *psz_utf8 = wxFromLocale( filenames[i] );
1036
1037         playlist_Add( p_playlist, psz_utf8, psz_utf8,
1038                       PLAYLIST_APPEND | ((i | b_enqueue) ? 0 : PLAYLIST_GO),
1039                       PLAYLIST_END );
1040         wxLocaleFree( psz_utf8 );
1041     }
1042
1043     vlc_object_release( p_playlist );
1044
1045     return TRUE;
1046 }
1047 #endif
1048
1049 /*****************************************************************************
1050  * Definition of VolCtrl class.
1051  *****************************************************************************/
1052 class wxVolCtrl: public wxGauge
1053 {
1054 public:
1055     /* Constructor */
1056     wxVolCtrl( intf_thread_t *_p_intf, wxWindow* parent, wxWindowID id,
1057                wxPoint = wxDefaultPosition, wxSize = wxSize( 20, -1 ) );
1058     virtual ~wxVolCtrl() {};
1059
1060     void UpdateVolume();
1061     int GetVolume();
1062
1063     void OnChange( wxMouseEvent& event );
1064
1065 private:
1066     intf_thread_t *p_intf;
1067
1068     DECLARE_EVENT_TABLE();
1069 };
1070
1071 BEGIN_EVENT_TABLE(wxVolCtrl, wxWindow)
1072     /* Mouse events */
1073     EVT_LEFT_DOWN(wxVolCtrl::OnChange)
1074     EVT_MOTION(wxVolCtrl::OnChange)
1075 END_EVENT_TABLE()
1076
1077 wxVolCtrl::wxVolCtrl( intf_thread_t *_p_intf, wxWindow* parent, wxWindowID id,
1078                       wxPoint point, wxSize size )
1079   : wxGauge( parent, id, 200, point, size, wxGA_HORIZONTAL | wxGA_SMOOTH )
1080 {
1081     p_intf = _p_intf;
1082     UpdateVolume();
1083 }
1084
1085 void wxVolCtrl::OnChange( wxMouseEvent& event )
1086 {
1087     if( !event.LeftDown() && !event.LeftIsDown() ) return;
1088
1089     int i_volume = event.GetX() * 200 / GetClientSize().GetWidth();
1090     aout_VolumeSet( p_intf, i_volume * AOUT_VOLUME_MAX / 200 / 2 );
1091     UpdateVolume();
1092 }
1093
1094 void wxVolCtrl::UpdateVolume()
1095 {
1096     audio_volume_t i_volume;
1097     aout_VolumeGet( p_intf, &i_volume );
1098
1099     int i_gauge_volume = i_volume * 200 * 2 / AOUT_VOLUME_MAX;
1100     if( i_gauge_volume == GetValue() ) return;
1101
1102     SetValue( i_gauge_volume );
1103     SetToolTip( wxString::Format((wxString)wxU(_("Volume")) + wxT(" %d"),
1104                 i_gauge_volume / 2 ) );
1105 }
1106
1107 #if defined(__WXGTK__)
1108 #define VLCVOL_HEIGHT p_parent->GetSize().GetHeight()
1109 #else
1110 #define VLCVOL_HEIGHT TOOLBAR_BMP_HEIGHT
1111 #endif
1112 VLCVolCtrl::VLCVolCtrl( intf_thread_t *_p_intf, wxWindow *p_parent )
1113   :wxControl( p_parent, -1, wxDefaultPosition, wxSize(64, VLCVOL_HEIGHT ),
1114               wxBORDER_NONE ),
1115    i_y_offset((VLCVOL_HEIGHT - TOOLBAR_BMP_HEIGHT) / 2),
1116    b_mute(0), p_intf(_p_intf)
1117 {
1118     gauge = new wxVolCtrl( p_intf, this, -1, wxPoint( 18, i_y_offset ),
1119                            wxSize( 44, TOOLBAR_BMP_HEIGHT ) );
1120 }
1121
1122 void VLCVolCtrl::OnPaint( wxPaintEvent &evt )
1123 {
1124     wxPaintDC dc( this );
1125     wxBitmap mPlayBitmap( b_mute ? speaker_mute_xpm : speaker_xpm );
1126     dc.DrawBitmap( mPlayBitmap, 0, i_y_offset, TRUE );
1127 }
1128
1129 void VLCVolCtrl::OnChange( wxMouseEvent& event )
1130 {
1131     if( event.GetX() < TOOLBAR_BMP_WIDTH )
1132     {
1133         int i_volume;
1134         aout_VolumeMute( p_intf, (audio_volume_t *)&i_volume );
1135
1136         b_mute = !b_mute;
1137         Refresh();
1138     }
1139 }
1140
1141 void VLCVolCtrl::UpdateVolume()
1142 {
1143     gauge->UpdateVolume();
1144
1145     int i_volume = gauge->GetValue();
1146     if( !!i_volume == !b_mute ) return;
1147     b_mute = !b_mute;
1148     Refresh();
1149 }
1150
1151 /*****************************************************************************
1152  * Systray class.
1153  *****************************************************************************/
1154
1155 #ifdef wxHAS_TASK_BAR_ICON
1156
1157 BEGIN_EVENT_TABLE(Systray, wxTaskBarIcon)
1158     /* Mouse events */
1159 #ifdef WIN32
1160     EVT_TASKBAR_LEFT_DCLICK(Systray::OnLeftClick)
1161 #else
1162     EVT_TASKBAR_LEFT_DOWN(Systray::OnLeftClick)
1163 #endif
1164     /* Menu events */
1165     EVT_MENU(Iconize_Event, Systray::OnMenuIconize)
1166     EVT_MENU(Exit_Event, Systray::OnExit)
1167     EVT_MENU(PlayStream_Event, Systray::OnPlayStream)
1168     EVT_MENU(NextStream_Event, Systray::OnNextStream)
1169     EVT_MENU(PrevStream_Event, Systray::OnPrevStream)
1170     EVT_MENU(StopStream_Event, Systray::OnStopStream)
1171 END_EVENT_TABLE()
1172
1173 Systray::Systray( Interface *_p_main_interface, intf_thread_t *_p_intf )
1174 {
1175     p_main_interface = _p_main_interface;
1176     p_intf = _p_intf;
1177
1178     SetIcon( wxIcon( vlc16x16_xpm ), wxT("VLC media player") );
1179     if( !IsOk() || !IsIconInstalled() )
1180     {
1181         msg_Warn(p_intf, "cannot set systray icon, weird things may happen");
1182     }
1183 }
1184
1185 /* Event handlers */
1186 void Systray::OnMenuIconize( wxCommandEvent& event )
1187 {
1188     p_main_interface->Show( ! p_main_interface->IsShown() );
1189     if ( p_main_interface->IsShown() ) p_main_interface->Raise();
1190 }
1191
1192 void Systray::OnLeftClick( wxTaskBarIconEvent& event )
1193 {
1194     wxCommandEvent cevent;
1195     OnMenuIconize(cevent);
1196 }
1197
1198 void Systray::OnExit( wxCommandEvent& event )
1199 {
1200     p_main_interface->Close(TRUE);
1201 }
1202
1203 void Systray::OnPrevStream( wxCommandEvent& event )
1204 {
1205     p_main_interface->PrevStream();
1206 }
1207
1208 void Systray::OnNextStream( wxCommandEvent& event )
1209 {
1210     p_main_interface->NextStream();
1211 }
1212
1213 void Systray::OnPlayStream( wxCommandEvent& event )
1214 {
1215     p_main_interface->PlayStream();
1216 }
1217
1218 void Systray::OnStopStream( wxCommandEvent& event )
1219 {
1220     p_main_interface->StopStream();
1221 }
1222
1223 /* Systray popup menu */
1224 wxMenu* Systray::CreatePopupMenu()
1225 {
1226     int minimal = config_GetInt( p_intf, "wx-minimal" );
1227
1228     wxMenu* systray_menu = new wxMenu;
1229     systray_menu->Append( Exit_Event, wxU(_("Quit VLC")) );
1230     systray_menu->AppendSeparator();
1231     systray_menu->Append( PlayStream_Event, wxU(_("Play/Pause")) );
1232
1233     if (!minimal)
1234     {
1235     systray_menu->Append( PrevStream_Event, wxU(_("Previous")) );
1236     systray_menu->Append( NextStream_Event, wxU(_("Next")) );
1237     systray_menu->Append( StopStream_Event, wxU(_("Stop")) );
1238     }
1239     systray_menu->AppendSeparator();
1240     systray_menu->Append( Iconize_Event, wxU(_("Show/Hide interface")) );
1241     return systray_menu;
1242 }
1243
1244 void Systray::UpdateTooltip( const wxChar* tooltip )
1245 {
1246     SetIcon( wxIcon( vlc16x16_xpm ), tooltip );
1247 }
1248 #endif