wxMediaCtrl patch from Ryan:
[wxWidgets.git] / samples / mediaplayer / mediaplayer.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: mediaplayer.cpp
3 // Purpose: wxMediaCtrl sample
4 // Author: Ryan Norton
5 // Modified by:
6 // Created: 11/10/04
7 // RCS-ID: $Id$
8 // Copyright: (c) Ryan Norton
9 // Licence: wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
11
12 // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13 // MediaPlayer
14 //
15 // This is a somewhat comprehensive example of how to use all the funtionality
16 // of the wxMediaCtrl class in wxWidgets.
17 //
18 // To use this sample, simply select Open File from the file menu,
19 // select the file you want to play - and MediaPlayer will play the file in a
20 // the current notebook page, showing video if necessary.
21 //
22 // You can select one of the menu options, or move the slider around
23 // to manipulate what is playing.
24 // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
25
26 // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
27 // Known bugs with wxMediaCtrl:
28 //
29 // 1) Certain backends can't play the same media file at the same time (MCI,
30 // Cocoa NSMovieView-Quicktime).
31 // 2) Positioning on Mac Carbon is messed up if put in a sub-control like a
32 // Notebook (like this sample does) on OS versions < 10.2.
33 // 3) On unix the video may not work - it only checks for a few video
34 // sinks - xvimagesink, ximagesink and whatever gnome preferences has -
35 // if gnome preferences is not available or you have a different video
36 // sink then those two (such as sdlvideosink) then you'll get black video
37 // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
38
39 // ============================================================================
40 // Definitions
41 // ============================================================================
42
43 // ----------------------------------------------------------------------------
44 // Pre-compiled header stuff
45 // ----------------------------------------------------------------------------
46
47 #include "wx/wxprec.h"
48
49 #ifdef __BORLANDC__
50 #pragma hdrstop
51 #endif
52
53 #ifndef WX_PRECOMP
54 #include "wx/wx.h"
55 #endif
56
57 // ----------------------------------------------------------------------------
58 // Headers
59 // ----------------------------------------------------------------------------
60
61 #include "wx/mediactrl.h" //for wxMediaCtrl
62 #include "wx/filedlg.h" //for opening files from OpenFile
63 #include "wx/slider.h" //for a slider for seeking within media
64 #include "wx/sizer.h" //for positioning controls/wxBoxSizer
65 #include "wx/timer.h" //timer for updating status bar
66 #include "wx/textdlg.h" //for getting user text from OpenURL/Debug
67 #include "wx/notebook.h" //for wxNotebook and putting movies in pages
68 #include "wx/cmdline.h" //for wxCmdLineParser (optional)
69 #include "wx/listctrl.h" //for wxListCtrl
70 #include "wx/dnd.h" //drag and drop for the playlist
71 #include "wx/filename.h" //For wxFileName::GetName()
72 #include "wx/config.h" //for native wxConfig
73
74 // ----------------------------------------------------------------------------
75 // Bail out if the user doesn't want one of the
76 // things we need
77 // ----------------------------------------------------------------------------
78
79 // RN: I'm not sure why this is here - even minimal doesn't check for
80 // wxUSE_GUI. I may have added it myself though...
81 #if !wxUSE_GUI
82 #error "This is a GUI sample"
83 #endif
84
85 #if !wxUSE_MEDIACTRL || !wxUSE_MENUS || !wxUSE_SLIDER || !wxUSE_TIMER || \
86 !wxUSE_NOTEBOOK || !wxUSE_LISTCTRL || !wxUSE_DRAG_AND_DROP
87 #error "Not all required elements are enabled. Please modify setup.h!"
88 #endif
89
90 // ============================================================================
91 // Declarations
92 // ============================================================================
93
94 // ----------------------------------------------------------------------------
95 // Enumurations
96 // ----------------------------------------------------------------------------
97
98 // IDs for the controls and the menu commands
99 enum
100 {
101 // Menu event IDs
102 wxID_LOOP = 1,
103 wxID_OPENFILESAMEPAGE,
104 wxID_OPENFILENEWPAGE,
105 wxID_OPENURLSAMEPAGE,
106 wxID_OPENURLNEWPAGE,
107 wxID_CLOSECURRENTPAGE,
108 wxID_PLAY,
109 wxID_PAUSE,
110 wxID_NEXT,
111 wxID_PREV,
112 wxID_SELECTBACKEND,
113 wxID_SHOWINTERFACE,
114 // wxID_STOP, [built-in to wxWidgets]
115 // wxID_ABOUT, [built-in to wxWidgets]
116 // wxID_EXIT, [built-in to wxWidgets]
117 // Control event IDs
118 wxID_SLIDER,
119 wxID_NOTEBOOK,
120 wxID_MEDIACTRL,
121 wxID_BUTTONNEXT,
122 wxID_BUTTONPREV,
123 wxID_BUTTONSTOP,
124 wxID_BUTTONPLAY,
125 wxID_BUTTONVD,
126 wxID_BUTTONVU,
127 wxID_LISTCTRL,
128 wxID_GAUGE
129 };
130
131 // ----------------------------------------------------------------------------
132 // wxMediaPlayerApp
133 // ----------------------------------------------------------------------------
134
135 class wxMediaPlayerApp : public wxApp
136 {
137 public:
138 #ifdef __WXMAC__
139 virtual void MacOpenFile(const wxString & fileName );
140 #endif
141
142 virtual bool OnInit();
143
144 protected:
145 class wxMediaPlayerFrame* m_frame;
146 };
147
148 // ----------------------------------------------------------------------------
149 // wxMediaPlayerFrame
150 // ----------------------------------------------------------------------------
151
152 class wxMediaPlayerFrame : public wxFrame
153 {
154 public:
155 // Ctor/Dtor
156 wxMediaPlayerFrame(const wxString& title);
157 ~wxMediaPlayerFrame();
158
159 // Menu event handlers
160 void OnQuit(wxCommandEvent& event);
161 void OnAbout(wxCommandEvent& event);
162
163 void OnOpenFileSamePage(wxCommandEvent& event);
164 void OnOpenFileNewPage(wxCommandEvent& event);
165 void OnOpenURLSamePage(wxCommandEvent& event);
166 void OnOpenURLNewPage(wxCommandEvent& event);
167 void OnCloseCurrentPage(wxCommandEvent& event);
168
169 void OnPlay(wxCommandEvent& event);
170 void OnPause(wxCommandEvent& event);
171 void OnStop(wxCommandEvent& event);
172 void OnNext(wxCommandEvent& event);
173 void OnPrev(wxCommandEvent& event);
174 void OnVolumeDown(wxCommandEvent& event);
175 void OnVolumeUp(wxCommandEvent& event);
176
177 void OnLoop(wxCommandEvent& event);
178 void OnShowInterface(wxCommandEvent& event);
179
180 void OnSelectBackend(wxCommandEvent& event);
181
182 // Notebook event handlers
183 void OnPageChange(wxNotebookEvent& event);
184
185 // Key event handlers
186 void OnKeyDown(wxKeyEvent& event);
187
188 // Quickie for playing from command line
189 void AddToPlayList(const wxString& szString);
190
191 // ListCtrl event handlers
192 void OnChangeSong(wxListEvent& event);
193
194 // Media event handlers
195 void OnMediaLoaded(wxMediaEvent& event);
196
197 // Close event handlers
198 void OnClose(wxCloseEvent& event);
199
200 private:
201 // Rebuild base status string (see Implementation)
202 void ResetStatus();
203
204 // Common open file code
205 void OpenFile(bool bNewPage);
206 void OpenURL(bool bNewPage);
207 void DoOpenFile(const wxString& path, bool bNewPage);
208 void DoPlayFile(const wxString& path);
209
210 class wxMediaPlayerTimer* m_timer; //Timer to write info to status bar
211 wxString m_basestatus; //Base status string (see ResetStatus())
212 wxNotebook* m_notebook; //Notebook containing our pages
213
214 // Maybe I should use more accessors, but for simplicity
215 // I'll allow the other classes access to our members
216 friend class wxMediaPlayerApp;
217 friend class wxMediaPlayerNotebookPage;
218 friend class wxMediaPlayerTimer;
219 };
220
221
222
223 // ----------------------------------------------------------------------------
224 // wxMediaPlayerNotebookPage
225 // ----------------------------------------------------------------------------
226
227 class wxMediaPlayerNotebookPage : public wxPanel
228 {
229 wxMediaPlayerNotebookPage(wxMediaPlayerFrame* parentFrame,
230 wxNotebook* book, const wxString& be = wxEmptyString);
231
232 // Slider event handlers
233 void OnBeginSeek(wxScrollEvent& event);
234 void OnEndSeek(wxScrollEvent& event);
235
236 // Media event handlers
237 void OnMediaFinished(wxMediaEvent& event);
238
239 public:
240 bool IsBeingDragged(); //accessor for m_bIsBeingDragged
241
242 //make wxMediaPlayerFrame able to access the private members
243 friend class wxMediaPlayerFrame;
244
245 int m_nLastFileId; //List ID of played file in listctrl
246 wxString m_szFile; //Name of currently playing file/location
247
248 wxMediaCtrl* m_mediactrl; //Our media control
249 class wxMediaPlayerListCtrl* m_playlist; //Our playlist
250 wxSlider* m_slider; //The slider below our media control
251 int m_nLoops; //Number of times media has looped
252 bool m_bLoop; //Whether we are looping or not
253 bool m_bIsBeingDragged; //Whether the user is dragging the scroll bar
254 wxMediaPlayerFrame* m_parentFrame; //Main wxFrame of our sample
255 wxButton* m_prevButton; //Go to previous file button
256 wxButton* m_playButton; //Play/pause file button
257 wxButton* m_stopButton; //Stop playing file button
258 wxButton* m_nextButton; //Next file button
259 wxButton* m_vdButton; //Volume down button
260 wxButton* m_vuButton; //Volume up button
261 wxGauge* m_gauge; //Gauge to keep in line with slider
262 };
263
264 // ----------------------------------------------------------------------------
265 // wxMediaPlayerTimer
266 // ----------------------------------------------------------------------------
267
268 class wxMediaPlayerTimer : public wxTimer
269 {
270 public:
271 //Ctor
272 wxMediaPlayerTimer(wxMediaPlayerFrame* frame) {m_frame = frame;}
273
274 //Called each time the timer's timeout expires
275 void Notify();
276
277 wxMediaPlayerFrame* m_frame; //The wxMediaPlayerFrame
278 };
279
280 // ----------------------------------------------------------------------------
281 // wxMediaPlayerListCtrl
282 // ----------------------------------------------------------------------------
283 class wxMediaPlayerListCtrl : public wxListCtrl
284 {
285 public:
286 void AddToPlayList(const wxString& szString)
287 {
288 wxListItem kNewItem;
289 kNewItem.SetAlign(wxLIST_FORMAT_LEFT);
290
291 int nID = this->GetItemCount();
292 kNewItem.SetId(nID);
293 kNewItem.SetMask(wxLIST_MASK_DATA);
294 kNewItem.SetData(new wxString(szString));
295
296 this->InsertItem(kNewItem);
297 this->SetItem(nID, 0, wxT("*"));
298 this->SetItem(nID, 1, wxFileName(szString).GetName());
299
300 if (nID % 2)
301 {
302 kNewItem.SetBackgroundColour(wxColour(192,192,192));
303 this->SetItem(kNewItem);
304 }
305 }
306
307 void GetSelectedItem(wxListItem& listitem)
308 {
309 listitem.SetMask(wxLIST_MASK_TEXT | wxLIST_MASK_DATA);
310 int nLast = -1, nLastSelected = -1;
311 while ((nLast = this->GetNextItem(nLast,
312 wxLIST_NEXT_ALL,
313 wxLIST_STATE_SELECTED)) != -1)
314 {
315 listitem.SetId(nLast);
316 this->GetItem(listitem);
317 if ((listitem.GetState() & wxLIST_STATE_FOCUSED) )
318 break;
319 nLastSelected = nLast;
320 }
321 if (nLast == -1 && nLastSelected == -1)
322 return;
323 listitem.SetId(nLastSelected == -1 ? nLast : nLastSelected);
324 this->GetItem(listitem);
325 }
326 };
327
328 // ----------------------------------------------------------------------------
329 // wxPlayListDropTarget
330 //
331 // Drop target for playlist (i.e. user drags a file from explorer unto
332 // playlist it adds the file)
333 // ----------------------------------------------------------------------------
334 class wxPlayListDropTarget : public wxFileDropTarget
335 {
336 public:
337 wxPlayListDropTarget(wxMediaPlayerListCtrl& list) : m_list(list) {}
338 ~wxPlayListDropTarget(){}
339 virtual bool OnDropFiles(wxCoord WXUNUSED(x), wxCoord WXUNUSED(y),
340 const wxArrayString& files)
341 {
342 for (size_t i = 0; i < files.GetCount(); ++i)
343 {
344 m_list.AddToPlayList(files[i]);
345 }
346 return true;
347 }
348 wxMediaPlayerListCtrl& m_list;
349 };
350
351 // ============================================================================
352 //
353 // Implementation
354 //
355 // ============================================================================
356
357 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
358 //
359 // [Functions]
360 //
361 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
362
363 // ----------------------------------------------------------------------------
364 // wxGetMediaStateText
365 //
366 // Converts a wxMediaCtrl state into something useful that we can display
367 // to the user
368 // ----------------------------------------------------------------------------
369 const wxChar* wxGetMediaStateText(int nState)
370 {
371 switch(nState)
372 {
373 case wxMEDIASTATE_PLAYING:
374 return wxT("Playing");
375 case wxMEDIASTATE_STOPPED:
376 return wxT("Stopped");
377 ///case wxMEDIASTATE_PAUSED:
378 default:
379 return wxT("Paused");
380 }
381 }
382
383 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
384 //
385 // wxMediaPlayerApp
386 //
387 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
388
389 // ----------------------------------------------------------------------------
390 // This sets up this wxApp as the global wxApp that gui calls in wxWidgets
391 // use. For example, if you were to be in windows and use a file dialog,
392 // wxWidgets would use wxTheApp->GetHInstance() which would get the instance
393 // handle of the application. These routines in wx _DO NOT_ check to see if
394 // the wxApp exists, and thus will crash the application if you try it.
395 //
396 // IMPLEMENT_APP does this, and also implements the platform-specific entry
397 // routine, such as main or WinMain(). Use IMPLEMENT_APP_NO_MAIN if you do
398 // not desire this behavior.
399 // ----------------------------------------------------------------------------
400 IMPLEMENT_APP(wxMediaPlayerApp)
401
402 // ----------------------------------------------------------------------------
403 // wxMediaPlayerApp::OnInit
404 //
405 // Where execution starts - akin to a main or WinMain.
406 // 1) Create the frame and show it to the user
407 // 2) Process filenames from the commandline
408 // 3) return true specifying that we want execution to continue past OnInit
409 // ----------------------------------------------------------------------------
410 bool wxMediaPlayerApp::OnInit()
411 {
412 wxMediaPlayerFrame *frame =
413 new wxMediaPlayerFrame(wxT("MediaPlayer wxWidgets Sample"));
414 frame->Show(true);
415
416 #if wxUSE_CMDLINE_PARSER
417 //
418 // What this does is get all the command line arguments
419 // and treat each one as a file to put to the initial playlist
420 //
421 wxCmdLineEntryDesc cmdLineDesc[2];
422 cmdLineDesc[0].kind = wxCMD_LINE_PARAM;
423 cmdLineDesc[0].shortName = NULL;
424 cmdLineDesc[0].longName = NULL;
425 cmdLineDesc[0].description = wxT("input files");
426 cmdLineDesc[0].type = wxCMD_LINE_VAL_STRING;
427 cmdLineDesc[0].flags = wxCMD_LINE_PARAM_OPTIONAL | wxCMD_LINE_PARAM_MULTIPLE;
428
429 cmdLineDesc[1].kind = wxCMD_LINE_NONE;
430
431 //gets the passed media files from cmd line
432 wxCmdLineParser parser (cmdLineDesc, argc, argv);
433
434 // get filenames from the commandline
435 if (parser.Parse() == 0)
436 {
437 for (size_t paramNr=0; paramNr < parser.GetParamCount(); ++paramNr)
438 {
439 frame->AddToPlayList((parser.GetParam (paramNr)));
440 }
441 wxCommandEvent emptyevt;
442 frame->OnNext(emptyevt);
443 }
444 #endif
445
446 return true;
447 }
448
449 #ifdef __WXMAC__
450
451 void wxMediaPlayerApp::MacOpenFile(const wxString & fileName )
452 {
453 //Called when a user drags a file over our app
454 m_frame->DoOpenFile(fileName, true /* new page */);
455 }
456
457 #endif // __WXMAC__
458
459 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
460 //
461 // wxMediaPlayerFrame
462 //
463 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
464
465 // ----------------------------------------------------------------------------
466 // wxMediaPlayerFrame Constructor
467 //
468 // 1) Create our menus
469 // 2) Create our notebook control and add it to the frame
470 // 3) Create our status bar
471 // 4) Connect our events
472 // 5) Start our timer
473 // ----------------------------------------------------------------------------
474
475 wxMediaPlayerFrame::wxMediaPlayerFrame(const wxString& title)
476 : wxFrame(NULL, wxID_ANY, title, wxDefaultPosition, wxSize(600,600))
477 {
478 //
479 // Create Menus
480 //
481 wxMenu *fileMenu = new wxMenu;
482 wxMenu *controlsMenu = new wxMenu;
483 wxMenu *optionsMenu = new wxMenu;
484 wxMenu *helpMenu = new wxMenu;
485 wxMenu *debugMenu = new wxMenu;
486
487 fileMenu->Append(wxID_OPENFILESAMEPAGE, wxT("&Open File\tCtrl-Shift-O"),
488 wxT("Open a File in the current notebook page"));
489 fileMenu->Append(wxID_OPENFILENEWPAGE, wxT("&Open File in a new page"),
490 wxT("Open a File in a new notebook page"));
491 fileMenu->Append(wxID_OPENURLSAMEPAGE, wxT("&Open URL"),
492 wxT("Open a URL in the current notebook page"));
493 fileMenu->Append(wxID_OPENURLNEWPAGE, wxT("&Open URL in a new page"),
494 wxT("Open a URL in a new notebook page"));
495 fileMenu->AppendSeparator();
496 fileMenu->Append(wxID_CLOSECURRENTPAGE, wxT("&Close Current Page\tCtrl-C"),
497 wxT("Close current notebook page"));
498 fileMenu->AppendSeparator();
499 fileMenu->Append(wxID_EXIT,
500 wxT("E&xit\tAlt-X"),
501 wxT("Quit this program"));
502
503 controlsMenu->Append(wxID_PLAY, wxT("&Play/Pause\tCtrl-P"), wxT("Resume/Pause playback"));
504 controlsMenu->Append(wxID_STOP, wxT("&Stop\tCtrl-S"), wxT("Stop playback"));
505 controlsMenu->AppendSeparator();
506 controlsMenu->Append(wxID_PREV, wxT("&Previous\tCtrl-B"), wxT("Go to previous track"));
507 controlsMenu->Append(wxID_NEXT, wxT("&Next\tCtrl-N"), wxT("Skip to next track"));
508
509 optionsMenu->AppendCheckItem(wxID_LOOP,
510 wxT("&Loop\tCtrl-L"),
511 wxT("Loop Selected Media"));
512 optionsMenu->AppendCheckItem(wxID_SHOWINTERFACE,
513 wxT("&Show Interface\tCtrl-I"),
514 wxT("Show wxMediaCtrl native controls"));
515
516 debugMenu->Append(wxID_SELECTBACKEND,
517 wxT("&Select Backend...\tCtrl-D"),
518 wxT("Select a backend manually"));
519
520 helpMenu->Append(wxID_ABOUT,
521 wxT("&About...\tF1"),
522 wxT("Show about dialog"));
523
524
525 wxMenuBar *menuBar = new wxMenuBar();
526 menuBar->Append(fileMenu, wxT("&File"));
527 menuBar->Append(controlsMenu, wxT("&Controls"));
528 menuBar->Append(optionsMenu, wxT("&Options"));
529 menuBar->Append(debugMenu, wxT("&Debug"));
530 menuBar->Append(helpMenu, wxT("&Help"));
531 SetMenuBar(menuBar);
532
533 //
534 // Create our notebook - using wxNotebook is luckily pretty
535 // simple and self-explanatory in most cases
536 //
537 m_notebook = new wxNotebook(this, wxID_NOTEBOOK);
538
539 //
540 // Create our status bar
541 //
542 #if wxUSE_STATUSBAR
543 // create a status bar just for fun (by default with 1 pane only)
544 CreateStatusBar(1);
545 #endif // wxUSE_STATUSBAR
546
547 //
548 // Connect events.
549 //
550 // There are two ways in wxWidgets to use events -
551 // Message Maps and Connections.
552 //
553 // Message Maps are implemented by putting
554 // DECLARE_MESSAGE_MAP in your wxEvtHandler-derived
555 // class you want to use for events, such as wxMediaPlayerFrame.
556 //
557 // Then after your class declaration you put
558 // BEGIN_EVENT_TABLE(wxMediaPlayerFrame, wxFrame)
559 // EVT_XXX(XXX)...
560 // END_EVENT_TABLE()
561 //
562 // Where wxMediaPlayerFrame is the class with the DECLARE_MESSAGE_MAP
563 // in it. EVT_XXX(XXX) are each of your handlers, such
564 // as EVT_MENU for menu events and the XXX inside
565 // is the parameters to the event macro - in the case
566 // of EVT_MENU the menu id and then the function to call.
567 //
568 // However, with wxEvtHandler::Connect you can avoid a
569 // global message map for your class and those annoying
570 // macros. You can also change the context in which
571 // the call the handler (more later).
572 //
573 // The downside is that due to the limitation that
574 // wxWidgets doesn't use templates in certain areas,
575 // You have to triple-cast the event function.
576 //
577 // There are five parameters to wxEvtHandler::Connect -
578 //
579 // The first is the id of the instance whose events
580 // you want to handle - i.e. a menu id for menus,
581 // a control id for controls (wxControl::GetId())
582 // and so on.
583 //
584 // The second is the event id. This is the same
585 // as the message maps (EVT_MENU) except prefixed
586 // with "wx" (wxEVT_MENU).
587 //
588 // The third is the function handler for the event -
589 // You need to cast it to the specific event handler
590 // type, then to a wxEventFunction, then to a
591 // wxObjectEventFunction - I.E.
592 // (wxObjectEventFunction)(wxEventFunction)
593 // (wxCommandEventFunction) &wxMediaPlayerFrame::MyHandler
594 //
595 // Or, you can use the new (2.5.5+) event handler
596 // conversion macros - for instance the above could
597 // be done as
598 // wxCommandEventHandler(wxMediaPlayerFrame::MyHandler)
599 // pretty simple, eh?
600 //
601 // The fourth is an optional userdata param -
602 // this is of historical relevance only and is
603 // there only for backwards compatibility.
604 //
605 // The fifth is the context in which to call the
606 // handler - by default (this param is optional)
607 // this. For example in your event handler
608 // if you were to call "this->MyFunc()"
609 // it would literally do this->MyFunc. However,
610 // if you were to pass myHandler as the fifth
611 // parameter, for instance, you would _really_
612 // be calling myHandler->MyFunc, even though
613 // the compiler doesn't really know it.
614 //
615
616 //
617 // Menu events
618 //
619 this->Connect(wxID_EXIT, wxEVT_COMMAND_MENU_SELECTED,
620 wxCommandEventHandler(wxMediaPlayerFrame::OnQuit));
621
622 this->Connect(wxID_ABOUT, wxEVT_COMMAND_MENU_SELECTED,
623 wxCommandEventHandler(wxMediaPlayerFrame::OnAbout));
624
625 this->Connect(wxID_LOOP, wxEVT_COMMAND_MENU_SELECTED,
626 wxCommandEventHandler(wxMediaPlayerFrame::OnLoop));
627
628 this->Connect(wxID_SHOWINTERFACE, wxEVT_COMMAND_MENU_SELECTED,
629 wxCommandEventHandler(wxMediaPlayerFrame::OnShowInterface));
630
631 this->Connect(wxID_OPENFILENEWPAGE, wxEVT_COMMAND_MENU_SELECTED,
632 wxCommandEventHandler(wxMediaPlayerFrame::OnOpenFileNewPage));
633
634 this->Connect(wxID_OPENFILESAMEPAGE, wxEVT_COMMAND_MENU_SELECTED,
635 wxCommandEventHandler(wxMediaPlayerFrame::OnOpenFileSamePage));
636
637 this->Connect(wxID_OPENURLNEWPAGE, wxEVT_COMMAND_MENU_SELECTED,
638 wxCommandEventHandler(wxMediaPlayerFrame::OnOpenURLNewPage));
639
640 this->Connect(wxID_OPENURLSAMEPAGE, wxEVT_COMMAND_MENU_SELECTED,
641 wxCommandEventHandler(wxMediaPlayerFrame::OnOpenURLSamePage));
642
643 this->Connect(wxID_CLOSECURRENTPAGE, wxEVT_COMMAND_MENU_SELECTED,
644 wxCommandEventHandler(wxMediaPlayerFrame::OnCloseCurrentPage));
645
646 this->Connect(wxID_PLAY, wxEVT_COMMAND_MENU_SELECTED,
647 wxCommandEventHandler(wxMediaPlayerFrame::OnPlay));
648
649 this->Connect(wxID_STOP, wxEVT_COMMAND_MENU_SELECTED,
650 wxCommandEventHandler(wxMediaPlayerFrame::OnStop));
651
652 this->Connect(wxID_NEXT, wxEVT_COMMAND_MENU_SELECTED,
653 wxCommandEventHandler(wxMediaPlayerFrame::OnNext));
654
655 this->Connect(wxID_PREV, wxEVT_COMMAND_MENU_SELECTED,
656 wxCommandEventHandler(wxMediaPlayerFrame::OnPrev));
657
658 this->Connect(wxID_SELECTBACKEND, wxEVT_COMMAND_MENU_SELECTED,
659 wxCommandEventHandler(wxMediaPlayerFrame::OnSelectBackend));
660
661 //
662 // Notebook events
663 //
664 this->Connect(wxID_NOTEBOOK, wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED,
665 wxNotebookEventHandler(wxMediaPlayerFrame::OnPageChange));
666
667 //
668 // Key events
669 //
670 wxTheApp->Connect(wxID_ANY, wxEVT_KEY_DOWN,
671 wxKeyEventHandler(wxMediaPlayerFrame::OnKeyDown),
672 (wxObject*)0, this);
673
674 //
675 // Close events
676 //
677 this->Connect(wxID_ANY, wxEVT_CLOSE_WINDOW,
678 wxCloseEventHandler(wxMediaPlayerFrame::OnClose));
679
680 //
681 // End of Events
682 //
683
684 //
685 // Create an initial notebook page so the user has something
686 // to work with without having to go file->open every time :).
687 //
688 wxMediaPlayerNotebookPage* page =
689 new wxMediaPlayerNotebookPage(this, m_notebook);
690 m_notebook->AddPage(page,
691 wxT(""),
692 true);
693
694 //
695 // Here we load the our configuration -
696 // in our case we load all the files that were left in
697 // the playlist the last time the user closed our application
698 //
699 // As an exercise to the reader try modifying it so that
700 // it properly loads the playlist for each page without
701 // conflicting (loading the same data) with the other ones.
702 //
703 wxConfigBase* conf = wxConfigBase::Get();
704 wxString key, outstring;
705 for(int i = 0; ; ++i)
706 {
707 key.clear();
708 key << i;
709 if(!conf->Read(key, &outstring))
710 break;
711 page->m_playlist->AddToPlayList(outstring);
712 }
713
714 //
715 // Create a timer to update our status bar
716 //
717 m_timer = new wxMediaPlayerTimer(this);
718 m_timer->Start(100);
719 }
720
721 // ----------------------------------------------------------------------------
722 // wxMediaPlayerFrame Destructor
723 //
724 // 1) Deletes child objects implicitly
725 // 2) Delete our timer explicitly
726 // ----------------------------------------------------------------------------
727 wxMediaPlayerFrame::~wxMediaPlayerFrame()
728 {
729 //
730 // Here we save our info to the registry or whatever
731 // mechanism the OS uses.
732 //
733 // This makes it so that when mediaplayer loads up again
734 // it restores the same files that were in the playlist
735 // this time, rather than the user manually re-adding them.
736 //
737 // We need to do conf->DeleteAll() here because by default
738 // the config still contains the same files as last time
739 // so we need to clear it before writing our new ones.
740 //
741 // TODO: Maybe you could add a menu option to the
742 // options menu to delete the configuration on exit -
743 // all you'd need to do is just remove everything after
744 // conf->DeleteAll() here
745 //
746 // As an exercise to the reader, try modifying this so
747 // that it saves the data for each notebook page
748 //
749 wxMediaPlayerListCtrl* playlist =
750 ((wxMediaPlayerNotebookPage*)m_notebook->GetPage(0))->m_playlist;
751
752 wxConfigBase* conf = wxConfigBase::Get();
753 conf->DeleteAll();
754
755 for(int i = 0; i < playlist->GetItemCount(); ++i)
756 {
757 wxString* pData = (wxString*) playlist->GetItemData(i);
758 wxString s;
759 s << i;
760 conf->Write(s, *(pData));
761 delete pData;
762 }
763
764 delete m_timer;
765 }
766
767 // ----------------------------------------------------------------------------
768 // wxMediaPlayerFrame::OnClose
769 // ----------------------------------------------------------------------------
770 void wxMediaPlayerFrame::OnClose(wxCloseEvent& event)
771 {
772 event.Skip(); //really close the frame
773 }
774
775 // ----------------------------------------------------------------------------
776 // wxMediaPlayerFrame::AddToPlayList
777 // ----------------------------------------------------------------------------
778 void wxMediaPlayerFrame::AddToPlayList(const wxString& szString)
779 {
780 wxMediaPlayerNotebookPage* currentpage =
781 ((wxMediaPlayerNotebookPage*)m_notebook->GetCurrentPage());
782
783 currentpage->m_playlist->AddToPlayList(szString);
784 }
785
786
787 // ----------------------------------------------------------------------------
788 // wxMediaPlayerFrame::ResetStatus
789 //
790 // Here we just make a simple status string with some useful info about
791 // the media that we won't change later - such as the length of the media.
792 //
793 // We then append some other info that changes in wxMediaPlayerTimer::Notify, then
794 // set the status bar to this text.
795 //
796 // In real applications, you'd want to find a better way to do this,
797 // such as static text controls (wxStaticText).
798 //
799 // We display info here in seconds (wxMediaCtrl uses milliseconds - that's why
800 // we divide by 1000).
801 //
802 // We also reset our loop counter here.
803 // ----------------------------------------------------------------------------
804 void wxMediaPlayerFrame::ResetStatus()
805 {
806 wxMediaCtrl* currentMediaCtrl =
807 ((wxMediaPlayerNotebookPage*)m_notebook->GetCurrentPage())->m_mediactrl;
808
809 m_basestatus = wxString::Format(wxT("Size(x,y):%i,%i ")
810 wxT("Length(Seconds):%u Speed:%1.1fx"),
811 currentMediaCtrl->GetBestSize().x,
812 currentMediaCtrl->GetBestSize().y,
813 (unsigned)((currentMediaCtrl->Length() / 1000)),
814 currentMediaCtrl->GetPlaybackRate()
815 );
816 }
817
818 // ----------------------------------------------------------------------------
819 // wxMediaPlayerFrame::OnQuit
820 //
821 // Called from file->quit.
822 // Closes this application.
823 // ----------------------------------------------------------------------------
824 void wxMediaPlayerFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
825 {
826 // true is to force the frame to close
827 Close(true);
828 }
829
830 // ----------------------------------------------------------------------------
831 // wxMediaPlayerFrame::OnAbout
832 //
833 // Called from help->about.
834 // Gets some info about this application.
835 // ----------------------------------------------------------------------------
836 void wxMediaPlayerFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
837 {
838 wxString msg;
839 msg.Printf( wxT("This is a test of wxMediaCtrl.\n")
840 wxT("Welcome to %s"), wxVERSION_STRING);
841
842 wxMessageBox(msg, wxT("About wxMediaCtrl test"), wxOK | wxICON_INFORMATION, this);
843 }
844
845 // ----------------------------------------------------------------------------
846 // wxMediaPlayerFrame::OnLoop
847 //
848 // Called from file->loop.
849 // Changes the state of whether we want to loop or not.
850 // ----------------------------------------------------------------------------
851 void wxMediaPlayerFrame::OnLoop(wxCommandEvent& WXUNUSED(event))
852 {
853 wxMediaPlayerNotebookPage* currentpage =
854 ((wxMediaPlayerNotebookPage*)m_notebook->GetCurrentPage());
855
856 currentpage->m_bLoop = !currentpage->m_bLoop;
857 }
858
859 // ----------------------------------------------------------------------------
860 // wxMediaPlayerFrame::OnLoop
861 //
862 // Called from file->loop.
863 // Changes the state of whether we want to loop or not.
864 // ----------------------------------------------------------------------------
865 void wxMediaPlayerFrame::OnShowInterface(wxCommandEvent& event)
866 {
867 wxMediaPlayerNotebookPage* currentpage =
868 ((wxMediaPlayerNotebookPage*)m_notebook->GetCurrentPage());
869
870 if( !currentpage->m_mediactrl->ShowPlayerControls(event.IsChecked() ?
871 wxMEDIACTRLPLAYERCONTROLS_DEFAULT :
872 wxMEDIACTRLPLAYERCONTROLS_NONE) )
873 {
874 //error - uncheck and warn user
875 wxMenuItem* pSIItem = GetMenuBar()->FindItem(wxID_SHOWINTERFACE);
876 wxASSERT(pSIItem);
877 pSIItem->Check(!event.IsChecked());
878
879 if(event.IsChecked())
880 wxMessageBox(wxT("Could not show player controls"));
881 else
882 wxMessageBox(wxT("Could not hide player controls"));
883 }
884 }
885
886 // ----------------------------------------------------------------------------
887 // wxMediaPlayerFrame::OnOpenFileSamePage
888 //
889 // Called from file->openfile.
890 // Opens and plays a media file in the current notebook page
891 // ----------------------------------------------------------------------------
892 void wxMediaPlayerFrame::OnOpenFileSamePage(wxCommandEvent& WXUNUSED(event))
893 {
894 OpenFile(false);
895 }
896
897 // ----------------------------------------------------------------------------
898 // wxMediaPlayerFrame::OnOpenFileNewPage
899 //
900 // Called from file->openfileinnewpage.
901 // Opens and plays a media file in a new notebook page
902 // ----------------------------------------------------------------------------
903 void wxMediaPlayerFrame::OnOpenFileNewPage(wxCommandEvent& WXUNUSED(event))
904 {
905 OpenFile(true);
906 }
907
908 // ----------------------------------------------------------------------------
909 // wxMediaPlayerFrame::OpenFile
910 //
911 // Opens a file dialog asking the user for a filename, then
912 // calls DoOpenFile which will add the file to the playlist and play it
913 // ----------------------------------------------------------------------------
914 void wxMediaPlayerFrame::OpenFile(bool bNewPage)
915 {
916 wxFileDialog fd(this);
917
918 if(fd.ShowModal() == wxID_OK)
919 {
920 DoOpenFile(fd.GetPath(), bNewPage);
921 }
922 }
923
924 // ----------------------------------------------------------------------------
925 // wxMediaPlayerFrame::DoOpenFile
926 //
927 // Adds the file to our playlist, selects it in the playlist,
928 // and then calls DoPlayFile to play it
929 // ----------------------------------------------------------------------------
930 void wxMediaPlayerFrame::DoOpenFile(const wxString& path, bool bNewPage)
931 {
932 if(bNewPage)
933 {
934 m_notebook->AddPage(
935 new wxMediaPlayerNotebookPage(this, m_notebook),
936 path,
937 true);
938 }
939
940 wxMediaPlayerNotebookPage* currentpage =
941 (wxMediaPlayerNotebookPage*) m_notebook->GetCurrentPage();
942
943 if(currentpage->m_nLastFileId != -1)
944 currentpage->m_playlist->SetItemState(currentpage->m_nLastFileId,
945 0, wxLIST_STATE_SELECTED);
946
947 wxListItem newlistitem;
948 newlistitem.SetAlign(wxLIST_FORMAT_LEFT);
949
950 int nID;
951
952 newlistitem.SetId(nID = currentpage->m_playlist->GetItemCount());
953 newlistitem.SetMask(wxLIST_MASK_DATA | wxLIST_MASK_STATE);
954 newlistitem.SetState(wxLIST_STATE_SELECTED);
955 newlistitem.SetData(new wxString(path));
956
957 currentpage->m_playlist->InsertItem(newlistitem);
958 currentpage->m_playlist->SetItem(nID, 0, wxT("*"));
959 currentpage->m_playlist->SetItem(nID, 1, wxFileName(path).GetName());
960
961 if (nID % 2)
962 {
963 newlistitem.SetBackgroundColour(wxColour(192,192,192));
964 currentpage->m_playlist->SetItem(newlistitem);
965 }
966
967 DoPlayFile(path);
968 }
969
970 // ----------------------------------------------------------------------------
971 // wxMediaPlayerFrame::DoPlayFile
972 //
973 // Pauses the file if its the currently playing file,
974 // otherwise it plays the file
975 // ----------------------------------------------------------------------------
976 void wxMediaPlayerFrame::DoPlayFile(const wxString& path)
977 {
978 wxMediaPlayerNotebookPage* currentpage =
979 (wxMediaPlayerNotebookPage*) m_notebook->GetCurrentPage();
980
981 wxListItem listitem;
982 currentpage->m_playlist->GetSelectedItem(listitem);
983
984 if( ( listitem.GetData() &&
985 currentpage->m_nLastFileId == listitem.GetId() &&
986 currentpage->m_szFile.compare(path) == 0 ) ||
987 ( !listitem.GetData() &&
988 currentpage->m_nLastFileId != -1 &&
989 currentpage->m_szFile.compare(path) == 0)
990 )
991 {
992 if(currentpage->m_mediactrl->GetState() == wxMEDIASTATE_PLAYING)
993 {
994 if( !currentpage->m_mediactrl->Pause() )
995 wxMessageBox(wxT("Couldn't pause movie!"));
996 else
997 currentpage->m_playlist->SetItem(
998 currentpage->m_nLastFileId, 0, wxT("||"));
999 }
1000 else
1001 {
1002 if( !currentpage->m_mediactrl->Play() )
1003 wxMessageBox(wxT("Couldn't play movie!"));
1004 else
1005 currentpage->m_playlist->SetItem(
1006 currentpage->m_nLastFileId, 0, wxT(">"));
1007 }
1008 }
1009 else
1010 {
1011 int nNewId = listitem.GetData() ? listitem.GetId() :
1012 currentpage->m_playlist->GetItemCount()-1;
1013 m_notebook->SetPageText(m_notebook->GetSelection(),
1014 wxFileName(path).GetName());
1015
1016 if(currentpage->m_nLastFileId != -1)
1017 currentpage->m_playlist->SetItem(
1018 currentpage->m_nLastFileId, 0, wxT("*"));
1019
1020 wxURI uripath(path);
1021 if( uripath.IsReference() )
1022 {
1023 if( !currentpage->m_mediactrl->Load(path) )
1024 {
1025 wxMessageBox(wxT("Couldn't load file!"));
1026 currentpage->m_playlist->SetItem(nNewId, 0, wxT("E"));
1027 }
1028 else
1029 {
1030 currentpage->m_playlist->SetItem(nNewId, 0, wxT("O"));
1031 }
1032 }
1033 else
1034 {
1035 if( !currentpage->m_mediactrl->Load(uripath) )
1036 {
1037 wxMessageBox(wxT("Couldn't load URL!"));
1038 currentpage->m_playlist->SetItem(nNewId, 0, wxT("E"));
1039 }
1040 else
1041 {
1042 currentpage->m_playlist->SetItem(nNewId, 0, wxT("O"));
1043 }
1044 }
1045
1046 currentpage->m_nLastFileId = nNewId;
1047 currentpage->m_szFile = path;
1048 currentpage->m_playlist->SetItem(currentpage->m_nLastFileId,
1049 1, wxFileName(path).GetName());
1050 currentpage->m_playlist->SetItem(currentpage->m_nLastFileId,
1051 2, wxT(""));
1052 }
1053 }
1054
1055 // ----------------------------------------------------------------------------
1056 // wxMediaPlayerFrame::OnMediaLoaded
1057 //
1058 // Called when the media is ready to be played - and does
1059 // so, also gets the length of media and shows that in the list control
1060 // ----------------------------------------------------------------------------
1061 void wxMediaPlayerFrame::OnMediaLoaded(wxMediaEvent& WXUNUSED(evt))
1062 {
1063 wxMediaPlayerNotebookPage* currentpage =
1064 (wxMediaPlayerNotebookPage*) m_notebook->GetCurrentPage();
1065
1066 if( !currentpage->m_mediactrl->Play() )
1067 {
1068 wxMessageBox(wxT("Couldn't play movie!"));
1069 currentpage->m_playlist->SetItem(currentpage->m_nLastFileId, 0, wxT("E"));
1070 }
1071 else
1072 {
1073 currentpage->m_playlist->SetItem(currentpage->m_nLastFileId, 0, wxT(">"));
1074 }
1075
1076 currentpage->m_playlist->SetItem(currentpage->m_nLastFileId,
1077 2, wxString::Format(wxT("%u"),
1078 (unsigned) currentpage->m_mediactrl->Length() / 1000)
1079 );
1080
1081 ResetStatus();
1082
1083 currentpage->m_slider->SetRange(0,
1084 (int)(currentpage->m_mediactrl->Length() / 1000));
1085 currentpage->m_gauge->SetRange((int)(currentpage->m_mediactrl->Length() / 1000));
1086 }
1087
1088 // ----------------------------------------------------------------------------
1089 // wxMediaPlayerFrame::OnSelectBackend
1090 //
1091 // Little debugging routine - enter the class name of a backend and it
1092 // will use that instead of letting wxMediaCtrl search the wxMediaBackend
1093 // RTTI class list.
1094 // ----------------------------------------------------------------------------
1095 void wxMediaPlayerFrame::OnSelectBackend(wxCommandEvent& WXUNUSED(evt))
1096 {
1097 wxString sBackend = wxGetTextFromUser(wxT("Enter backend to use"));
1098
1099 if(sBackend.empty() == false) //could have been cancelled by the user
1100 {
1101 int sel = m_notebook->GetSelection();
1102
1103 if (sel != wxNOT_FOUND)
1104 {
1105 m_notebook->DeletePage(sel);
1106 }
1107
1108 m_notebook->AddPage(new wxMediaPlayerNotebookPage(this, m_notebook,
1109 sBackend
1110 ), wxT(""), true);
1111
1112 DoOpenFile(
1113 ((wxMediaPlayerNotebookPage*) m_notebook->GetCurrentPage())->m_szFile,
1114 false);
1115 }
1116 }
1117
1118 // ----------------------------------------------------------------------------
1119 // wxMediaPlayerFrame::OnOpenURLSamePage
1120 //
1121 // Called from file->openurl.
1122 // Opens and plays a media file from a URL in the current notebook page
1123 // ----------------------------------------------------------------------------
1124 void wxMediaPlayerFrame::OnOpenURLSamePage(wxCommandEvent& WXUNUSED(event))
1125 {
1126 OpenURL(false);
1127 }
1128
1129 // ----------------------------------------------------------------------------
1130 // wxMediaPlayerFrame::OnOpenURLNewPage
1131 //
1132 // Called from file->openurlinnewpage.
1133 // Opens and plays a media file from a URL in a new notebook page
1134 // ----------------------------------------------------------------------------
1135 void wxMediaPlayerFrame::OnOpenURLNewPage(wxCommandEvent& WXUNUSED(event))
1136 {
1137 OpenURL(true);
1138 }
1139
1140 // ----------------------------------------------------------------------------
1141 // wxMediaPlayerFrame::OpenURL
1142 //
1143 // Just calls DoOpenFile with the url path - which calls DoPlayFile
1144 // which handles the real dirty work
1145 // ----------------------------------------------------------------------------
1146 void wxMediaPlayerFrame::OpenURL(bool bNewPage)
1147 {
1148 wxString sUrl = wxGetTextFromUser(
1149 wxT("Enter the URL that has the movie to play")
1150 );
1151
1152 if(sUrl.empty() == false) //could have been cancelled by user
1153 {
1154 DoOpenFile(sUrl, bNewPage);
1155 }
1156 }
1157
1158 // ----------------------------------------------------------------------------
1159 // wxMediaPlayerFrame::OnCloseCurrentPage
1160 //
1161 // Called when the user wants to close the current notebook page
1162 //
1163 // 1) Get the current page number (wxControl::GetSelection)
1164 // 2) If there is no current page, break out
1165 // 3) Delete the current page
1166 // ----------------------------------------------------------------------------
1167 void wxMediaPlayerFrame::OnCloseCurrentPage(wxCommandEvent& WXUNUSED(event))
1168 {
1169 if( m_notebook->GetPageCount() > 1 )
1170 {
1171 int sel = m_notebook->GetSelection();
1172
1173 if (sel != wxNOT_FOUND)
1174 {
1175 m_notebook->DeletePage(sel);
1176 }
1177 }
1178 else
1179 {
1180 wxMessageBox(wxT("Cannot close main page"));
1181 }
1182 }
1183
1184 // ----------------------------------------------------------------------------
1185 // wxMediaPlayerFrame::OnPlay
1186 //
1187 // Called from file->play.
1188 // Resumes the media if it is paused or stopped.
1189 // ----------------------------------------------------------------------------
1190 void wxMediaPlayerFrame::OnPlay(wxCommandEvent& WXUNUSED(event))
1191 {
1192 wxMediaPlayerNotebookPage* currentpage =
1193 (wxMediaPlayerNotebookPage*) m_notebook->GetCurrentPage();
1194
1195 wxListItem listitem;
1196 currentpage->m_playlist->GetSelectedItem(listitem);
1197 if ( !listitem.GetData() )
1198 {
1199 int nLast = -1;
1200 if ((nLast = currentpage->m_playlist->GetNextItem(nLast,
1201 wxLIST_NEXT_ALL,
1202 wxLIST_STATE_DONTCARE)) == -1)
1203 {
1204 //no items in list
1205 wxMessageBox(wxT("No items in playlist!"));
1206 }
1207 else
1208 {
1209 listitem.SetId(nLast);
1210 currentpage->m_playlist->GetItem(listitem);
1211 listitem.SetMask(listitem.GetMask() | wxLIST_MASK_STATE);
1212 listitem.SetState(listitem.GetState() | wxLIST_STATE_SELECTED);
1213 currentpage->m_playlist->SetItem(listitem);
1214 wxASSERT(listitem.GetData());
1215 DoPlayFile((*((wxString*) listitem.GetData())));
1216 }
1217 }
1218 else
1219 {
1220 wxASSERT(listitem.GetData());
1221 DoPlayFile((*((wxString*) listitem.GetData())));
1222 }
1223 }
1224
1225 // ----------------------------------------------------------------------------
1226 // wxMediaPlayerFrame::OnKeyDown
1227 //
1228 // Deletes all selected files from the playlist if the backspace key is pressed
1229 // ----------------------------------------------------------------------------
1230 void wxMediaPlayerFrame::OnKeyDown(wxKeyEvent& event)
1231 {
1232 if(event.GetKeyCode() == WXK_BACK/*DELETE*/)
1233 {
1234 wxMediaPlayerNotebookPage* currentpage =
1235 (wxMediaPlayerNotebookPage*) m_notebook->GetCurrentPage();
1236 //delete all selected items
1237 while(true)
1238 {
1239 wxInt32 nSelectedItem = currentpage->m_playlist->GetNextItem(
1240 -1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
1241 if (nSelectedItem == -1)
1242 break;
1243
1244 wxListItem listitem;
1245 listitem.SetId(nSelectedItem);
1246 currentpage->m_playlist->GetItem(listitem);
1247 delete (wxString*) listitem.GetData();
1248
1249 currentpage->m_playlist->DeleteItem(nSelectedItem);
1250 }
1251 }
1252
1253 //Could be wxGetTextFromUser or something else important
1254 if(event.GetEventObject() != this)
1255 event.Skip();
1256 }
1257
1258 // ----------------------------------------------------------------------------
1259 // wxMediaPlayerFrame::OnStop
1260 //
1261 // Called from file->stop.
1262 // Where it stops depends on whether you can seek in the
1263 // media control or not - if you can it stops and seeks to the beginning,
1264 // otherwise it will appear to be at the end - but it will start over again
1265 // when Play() is called
1266 // ----------------------------------------------------------------------------
1267 void wxMediaPlayerFrame::OnStop(wxCommandEvent& WXUNUSED(evt))
1268 {
1269 wxMediaPlayerNotebookPage* currentpage =
1270 (wxMediaPlayerNotebookPage*) m_notebook->GetCurrentPage();
1271
1272 if( !currentpage->m_mediactrl->Stop() )
1273 wxMessageBox(wxT("Couldn't stop movie!"));
1274 else
1275 currentpage->m_playlist->SetItem(
1276 currentpage->m_nLastFileId, 0, wxT("[]"));
1277 }
1278
1279
1280 // ----------------------------------------------------------------------------
1281 // wxMediaPlayerFrame::OnChangeSong
1282 //
1283 // Routine that plays the currently selected file in the playlist.
1284 // Called when the user actives the song from the playlist,
1285 // and from other various places in the sample
1286 // ----------------------------------------------------------------------------
1287 void wxMediaPlayerFrame::OnChangeSong(wxListEvent& WXUNUSED(evt))
1288 {
1289 wxMediaPlayerNotebookPage* currentpage =
1290 (wxMediaPlayerNotebookPage*) m_notebook->GetCurrentPage();
1291
1292 wxListItem listitem;
1293 currentpage->m_playlist->GetSelectedItem(listitem);
1294 if(listitem.GetData())
1295 DoPlayFile((*((wxString*) listitem.GetData())));
1296 else
1297 wxMessageBox(wxT("No selected item!"));
1298 }
1299
1300 // ----------------------------------------------------------------------------
1301 // wxMediaPlayerFrame::OnPrev
1302 //
1303 // Tedious wxListCtrl stuff. Goes to prevous song in list, or if at the
1304 // beginning goes to the last in the list.
1305 // ----------------------------------------------------------------------------
1306 void wxMediaPlayerFrame::OnPrev(wxCommandEvent& WXUNUSED(event))
1307 {
1308 wxMediaPlayerNotebookPage* currentpage =
1309 (wxMediaPlayerNotebookPage*) m_notebook->GetCurrentPage();
1310
1311 if (currentpage->m_playlist->GetItemCount() == 0)
1312 return;
1313
1314 wxInt32 nLastSelectedItem = -1;
1315 while(true)
1316 {
1317 wxInt32 nSelectedItem = currentpage->m_playlist->GetNextItem(nLastSelectedItem,
1318 wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
1319 if (nSelectedItem == -1)
1320 break;
1321 nLastSelectedItem = nSelectedItem;
1322 currentpage->m_playlist->SetItemState(nSelectedItem, 0, wxLIST_STATE_SELECTED);
1323 }
1324
1325 if (nLastSelectedItem == -1)
1326 {
1327 //nothing selected, default to the file before the currently playing one
1328 if(currentpage->m_nLastFileId == 0)
1329 nLastSelectedItem = currentpage->m_playlist->GetItemCount() - 1;
1330 else
1331 nLastSelectedItem = currentpage->m_nLastFileId - 1;
1332 }
1333 else if (nLastSelectedItem == 0)
1334 nLastSelectedItem = currentpage->m_playlist->GetItemCount() - 1;
1335 else
1336 nLastSelectedItem -= 1;
1337
1338 if(nLastSelectedItem == currentpage->m_nLastFileId)
1339 return; //already playing... nothing to do
1340
1341 wxListItem listitem;
1342 listitem.SetId(nLastSelectedItem);
1343 listitem.SetMask(wxLIST_MASK_TEXT | wxLIST_MASK_DATA);
1344 currentpage->m_playlist->GetItem(listitem);
1345 listitem.SetMask(listitem.GetMask() | wxLIST_MASK_STATE);
1346 listitem.SetState(listitem.GetState() | wxLIST_STATE_SELECTED);
1347 currentpage->m_playlist->SetItem(listitem);
1348
1349 wxASSERT(listitem.GetData());
1350 DoPlayFile((*((wxString*) listitem.GetData())));
1351 }
1352
1353 // ----------------------------------------------------------------------------
1354 // wxMediaPlayerFrame::OnNext
1355 //
1356 // Tedious wxListCtrl stuff. Goes to next song in list, or if at the
1357 // end goes to the first in the list.
1358 // ----------------------------------------------------------------------------
1359 void wxMediaPlayerFrame::OnNext(wxCommandEvent& WXUNUSED(event))
1360 {
1361 wxMediaPlayerNotebookPage* currentpage =
1362 (wxMediaPlayerNotebookPage*) m_notebook->GetCurrentPage();
1363
1364 if (currentpage->m_playlist->GetItemCount() == 0)
1365 return;
1366
1367 wxInt32 nLastSelectedItem = -1;
1368 while(true)
1369 {
1370 wxInt32 nSelectedItem = currentpage->m_playlist->GetNextItem(nLastSelectedItem,
1371 wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
1372 if (nSelectedItem == -1)
1373 break;
1374 nLastSelectedItem = nSelectedItem;
1375 currentpage->m_playlist->SetItemState(nSelectedItem, 0, wxLIST_STATE_SELECTED);
1376 }
1377
1378 if (nLastSelectedItem == -1)
1379 {
1380 if(currentpage->m_nLastFileId == currentpage->m_playlist->GetItemCount() - 1)
1381 nLastSelectedItem = 0;
1382 else
1383 nLastSelectedItem = currentpage->m_nLastFileId + 1;
1384 }
1385 else if (nLastSelectedItem == currentpage->m_playlist->GetItemCount() - 1)
1386 nLastSelectedItem = 0;
1387 else
1388 nLastSelectedItem += 1;
1389
1390 if(nLastSelectedItem == currentpage->m_nLastFileId)
1391 return; //already playing... nothing to do
1392
1393 wxListItem listitem;
1394 listitem.SetMask(wxLIST_MASK_TEXT | wxLIST_MASK_DATA);
1395 listitem.SetId(nLastSelectedItem);
1396 currentpage->m_playlist->GetItem(listitem);
1397 listitem.SetMask(listitem.GetMask() | wxLIST_MASK_STATE);
1398 listitem.SetState(listitem.GetState() | wxLIST_STATE_SELECTED);
1399 currentpage->m_playlist->SetItem(listitem);
1400
1401 wxASSERT(listitem.GetData());
1402 DoPlayFile((*((wxString*) listitem.GetData())));
1403 }
1404
1405
1406 // ----------------------------------------------------------------------------
1407 // wxMediaPlayerFrame::OnVolumeDown
1408 //
1409 // Lowers the volume of the media control by 10%
1410 // ----------------------------------------------------------------------------
1411 void wxMediaPlayerFrame::OnVolumeDown(wxCommandEvent& WXUNUSED(event))
1412 {
1413 wxMediaPlayerNotebookPage* currentpage =
1414 (wxMediaPlayerNotebookPage*) m_notebook->GetCurrentPage();
1415
1416 double dVolume = currentpage->m_mediactrl->GetVolume();
1417 currentpage->m_mediactrl->SetVolume(dVolume < 0.1 ? 0.0 : dVolume - .1);
1418 }
1419
1420 // ----------------------------------------------------------------------------
1421 // wxMediaPlayerFrame::OnVolumeUp
1422 //
1423 // Increases the volume of the media control by 10%
1424 // ----------------------------------------------------------------------------
1425 void wxMediaPlayerFrame::OnVolumeUp(wxCommandEvent& WXUNUSED(event))
1426 {
1427 wxMediaPlayerNotebookPage* currentpage =
1428 (wxMediaPlayerNotebookPage*) m_notebook->GetCurrentPage();
1429
1430 double dVolume = currentpage->m_mediactrl->GetVolume();
1431 currentpage->m_mediactrl->SetVolume(dVolume > 0.9 ? 1.0 : dVolume + .1);
1432 }
1433
1434 // ----------------------------------------------------------------------------
1435 // wxMediaPlayerFrame::OnPageChange
1436 //
1437 // Called when the user changes the current notebook page shown
1438 // ----------------------------------------------------------------------------
1439 void wxMediaPlayerFrame::OnPageChange(wxNotebookEvent& WXUNUSED(event))
1440 {
1441 ResetStatus();
1442 }
1443
1444 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1445 //
1446 // wxMediaPlayerTimer
1447 //
1448 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1449
1450 // ----------------------------------------------------------------------------
1451 // wxMediaPlayerTimer::Notify
1452 //
1453 // 1) Update our slider with the position were are in in the media
1454 // 2) Update our status bar with the base text from wxMediaPlayerFrame::ResetStatus,
1455 // append some non-static (changing) info to it, then set the
1456 // status bar text to that result
1457 // ----------------------------------------------------------------------------
1458 void wxMediaPlayerTimer::Notify()
1459 {
1460 wxMediaPlayerNotebookPage* currentpage =
1461 (wxMediaPlayerNotebookPage*) m_frame->m_notebook->GetCurrentPage();
1462
1463 if(currentpage)
1464 {
1465 // if the slider is being dragged then update it with the song position
1466 if(currentpage->IsBeingDragged() == false)
1467 {
1468 long lPosition = (long)( currentpage->m_mediactrl->Tell() / 1000 );
1469 currentpage->m_slider->SetValue(lPosition);
1470 }
1471
1472 // update guage with value from slider
1473 currentpage->m_gauge->SetValue(currentpage->m_slider->GetValue());
1474 #if wxUSE_STATUSBAR
1475 m_frame->SetStatusText(wxString::Format(
1476 wxT("%s Pos:%u State:%s Loops:%i D/T:[%i]/[%i] V:%i%%"),
1477 m_frame->m_basestatus.c_str(),
1478 currentpage->m_slider->GetValue(),
1479 wxGetMediaStateText(currentpage->m_mediactrl->GetState()),
1480 currentpage->m_nLoops,
1481 (int)currentpage->m_mediactrl->GetDownloadProgress(),
1482 (int)currentpage->m_mediactrl->GetDownloadTotal(),
1483 (int)(currentpage->m_mediactrl->GetVolume() * 100)));
1484 #endif // wxUSE_STATUSBAR
1485 }
1486 }
1487
1488
1489 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1490 //
1491 // wxMediaPlayerNotebookPage
1492 //
1493 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1494
1495 // ----------------------------------------------------------------------------
1496 // wxMediaPlayerNotebookPage Constructor
1497 //
1498 // Creates a media control and slider and adds it to this panel,
1499 // along with some sizers for positioning
1500 // ----------------------------------------------------------------------------
1501 wxMediaPlayerNotebookPage::wxMediaPlayerNotebookPage(wxMediaPlayerFrame* parentFrame,
1502 wxNotebook* theBook,
1503 const wxString& szBackend)
1504 : wxPanel(theBook, wxID_ANY),
1505 m_nLastFileId(-1),
1506 m_nLoops(0),
1507 m_bLoop(false),
1508 m_bIsBeingDragged(false),
1509 m_parentFrame(parentFrame)
1510 {
1511
1512 //
1513 // Layout
1514 //
1515 // [wxMediaCtrl]
1516 // [playlist]
1517 // [5 control buttons]
1518 // [slider]
1519 // [gauge]
1520 //
1521
1522 //
1523 // Create and attach the sizer
1524 //
1525 wxFlexGridSizer* sizer = new wxFlexGridSizer(2, 1, 0, 0);
1526 this->SetSizer(sizer);
1527 this->SetAutoLayout(true);
1528 sizer->AddGrowableRow(0);
1529 sizer->AddGrowableCol(0);
1530
1531 //
1532 // Create our media control
1533 //
1534 m_mediactrl = new wxMediaCtrl();
1535
1536 // Make sure creation was successful
1537 bool bOK = m_mediactrl->Create(this, wxID_MEDIACTRL, wxEmptyString,
1538 wxDefaultPosition, wxDefaultSize, 0,
1539 //you could specify a macrod backend here like
1540 //wxMEDIABACKEND_QUICKTIME);
1541 szBackend);
1542 //you could change the cursor here like
1543 // m_mediactrl->SetCursor(wxCURSOR_BLANK);
1544 //note that this may not effect it if SetPlayerControls
1545 //is set to something else than wxMEDIACTRLPLAYERCONTROLS_NONE
1546 wxASSERT_MSG(bOK, wxT("Could not create media control!"));
1547 wxUnusedVar(bOK);
1548
1549 sizer->Add(m_mediactrl, 0, wxALIGN_CENTER_HORIZONTAL|wxALL|wxEXPAND, 5);
1550
1551 //
1552 // Create the playlist/listctrl
1553 //
1554 m_playlist = new wxMediaPlayerListCtrl();
1555 m_playlist->Create(this, wxID_LISTCTRL, wxDefaultPosition,
1556 wxDefaultSize,
1557 wxLC_REPORT //wxLC_LIST
1558 | wxSUNKEN_BORDER);
1559
1560 // Set the background of our listctrl to white
1561 m_playlist->SetBackgroundColour(wxColour(255,255,255));
1562
1563 // The layout of the headers of the listctrl are like
1564 // | | File | Length
1565 //
1566 // Where Column one is a character representing the state the file is in:
1567 // * - not the current file
1568 // E - Error has occured
1569 // > - Currently Playing
1570 // [] - Stopped
1571 // || - Paused
1572 // (( - Volume Down 10%
1573 // )) - Volume Up 10%
1574 //
1575 // Column two is the name of the file
1576 //
1577 // Column three is the length in seconds of the file
1578 m_playlist->InsertColumn(0,_(""), wxLIST_FORMAT_CENTER, 20);
1579 m_playlist->InsertColumn(1,_("File"), wxLIST_FORMAT_LEFT, /*wxLIST_AUTOSIZE_USEHEADER*/305);
1580 m_playlist->InsertColumn(2,_("Length"), wxLIST_FORMAT_CENTER, 75);
1581
1582 m_playlist->SetDropTarget(new wxPlayListDropTarget(*m_playlist));
1583 sizer->Add(m_playlist, 0, wxALIGN_CENTER_HORIZONTAL|wxALL|wxEXPAND, 5);
1584
1585 //
1586 // Create the control buttons
1587 // TODO/FIXME/HACK: This part about sizers is really a nice hack
1588 // and probably isn't proper
1589 //
1590 wxBoxSizer* horsizer1 = new wxBoxSizer(wxHORIZONTAL);
1591 wxBoxSizer* vertsizer = new wxBoxSizer(wxHORIZONTAL);
1592
1593 m_prevButton = new wxButton();
1594 m_playButton = new wxButton();
1595 m_stopButton = new wxButton();
1596 m_nextButton = new wxButton();
1597 m_vdButton = new wxButton();
1598 m_vuButton = new wxButton();
1599
1600 m_prevButton->Create(this, wxID_BUTTONPREV, wxT("|<"));
1601 m_playButton->Create(this, wxID_BUTTONPLAY, wxT(">"));
1602 m_stopButton->Create(this, wxID_BUTTONSTOP, wxT("[]"));
1603 m_nextButton->Create(this, wxID_BUTTONNEXT, wxT(">|"));
1604 m_vdButton->Create(this, wxID_BUTTONVD, wxT("(("));
1605 m_vuButton->Create(this, wxID_BUTTONVU, wxT("))"));
1606 vertsizer->Add(m_prevButton, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5);
1607 vertsizer->Add(m_playButton, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5);
1608 vertsizer->Add(m_stopButton, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5);
1609 vertsizer->Add(m_nextButton, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5);
1610 vertsizer->Add(m_vdButton, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5);
1611 vertsizer->Add(m_vuButton, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5);
1612 horsizer1->Add(vertsizer, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5);
1613 sizer->Add(horsizer1, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5);
1614
1615
1616 //
1617 // Create our slider
1618 //
1619 m_slider = new wxSlider(this, wxID_SLIDER, 0, //init
1620 0, //start
1621 0, //end
1622 wxDefaultPosition, wxDefaultSize,
1623 wxSL_HORIZONTAL );
1624 sizer->Add(m_slider, 0, wxALIGN_CENTER_HORIZONTAL|wxALL|wxEXPAND , 5);
1625
1626
1627 //
1628 // Create the gauge
1629 //
1630 m_gauge = new wxGauge();
1631 m_gauge->Create(this, wxID_GAUGE, 0, wxDefaultPosition, wxDefaultSize,
1632 wxGA_HORIZONTAL | wxGA_SMOOTH);
1633 sizer->Add(m_gauge, 0, wxALIGN_CENTER_HORIZONTAL|wxALL|wxEXPAND , 5);
1634
1635 //
1636 // ListCtrl events
1637 //
1638 this->Connect( wxID_LISTCTRL, wxEVT_COMMAND_LIST_ITEM_ACTIVATED,
1639 wxListEventHandler(wxMediaPlayerFrame::OnChangeSong),
1640 (wxObject*)0, parentFrame);
1641
1642 //
1643 // Slider events
1644 //
1645 this->Connect(wxID_SLIDER, wxEVT_SCROLL_THUMBTRACK,
1646 wxScrollEventHandler(wxMediaPlayerNotebookPage::OnBeginSeek));
1647 this->Connect(wxID_SLIDER, wxEVT_SCROLL_THUMBRELEASE,
1648 wxScrollEventHandler(wxMediaPlayerNotebookPage::OnEndSeek));
1649
1650 //
1651 // Media Control events
1652 //
1653 this->Connect(wxID_MEDIACTRL, wxEVT_MEDIA_FINISHED,
1654 wxMediaEventHandler(wxMediaPlayerNotebookPage::OnMediaFinished));
1655 this->Connect(wxID_MEDIACTRL, wxEVT_MEDIA_LOADED,
1656 wxMediaEventHandler(wxMediaPlayerFrame::OnMediaLoaded),
1657 (wxObject*)0, parentFrame);
1658
1659 //
1660 // Button events
1661 //
1662 this->Connect( wxID_BUTTONPREV, wxEVT_COMMAND_BUTTON_CLICKED,
1663 wxCommandEventHandler(wxMediaPlayerFrame::OnPrev),
1664 (wxObject*)0, parentFrame);
1665 this->Connect( wxID_BUTTONPLAY, wxEVT_COMMAND_BUTTON_CLICKED,
1666 wxCommandEventHandler(wxMediaPlayerFrame::OnPlay),
1667 (wxObject*)0, parentFrame);
1668 this->Connect( wxID_BUTTONSTOP, wxEVT_COMMAND_BUTTON_CLICKED,
1669 wxCommandEventHandler(wxMediaPlayerFrame::OnStop),
1670 (wxObject*)0, parentFrame);
1671 this->Connect( wxID_BUTTONNEXT, wxEVT_COMMAND_BUTTON_CLICKED,
1672 wxCommandEventHandler(wxMediaPlayerFrame::OnNext),
1673 (wxObject*)0, parentFrame);
1674 this->Connect( wxID_BUTTONVD, wxEVT_COMMAND_BUTTON_CLICKED,
1675 wxCommandEventHandler(wxMediaPlayerFrame::OnVolumeDown),
1676 (wxObject*)0, parentFrame);
1677 this->Connect( wxID_BUTTONVU, wxEVT_COMMAND_BUTTON_CLICKED,
1678 wxCommandEventHandler(wxMediaPlayerFrame::OnVolumeUp),
1679 (wxObject*)0, parentFrame);
1680 }
1681
1682 // ----------------------------------------------------------------------------
1683 // MyNotebook::OnBeginSeek
1684 //
1685 // Sets m_bIsBeingDragged to true to stop the timer from changing the position
1686 // of our slider
1687 // ----------------------------------------------------------------------------
1688 void wxMediaPlayerNotebookPage::OnBeginSeek(wxScrollEvent& WXUNUSED(event))
1689 {
1690 m_bIsBeingDragged = true;
1691 }
1692
1693 // ----------------------------------------------------------------------------
1694 // MyNotebook::OnEndSeek
1695 //
1696 // Called from file->seek.
1697 // Called when the user moves the slider -
1698 // seeks to a position within the media
1699 // then sets m_bIsBeingDragged to false to ok the timer to change the position
1700 // ----------------------------------------------------------------------------
1701 void wxMediaPlayerNotebookPage::OnEndSeek(wxScrollEvent& WXUNUSED(event))
1702 {
1703 if( m_mediactrl->Seek(
1704 m_slider->GetValue() * 1000
1705 ) == wxInvalidOffset )
1706 wxMessageBox(wxT("Couldn't seek in movie!"));
1707
1708 m_bIsBeingDragged = false;
1709 }
1710
1711 // ----------------------------------------------------------------------------
1712 // wxMediaPlayerNotebookPage::IsBeingDragged
1713 //
1714 // Returns true if the user is dragging the slider
1715 // ----------------------------------------------------------------------------
1716 bool wxMediaPlayerNotebookPage::IsBeingDragged()
1717 {
1718 return m_bIsBeingDragged;
1719 }
1720
1721 // ----------------------------------------------------------------------------
1722 // OnMediaFinished
1723 //
1724 // Called when the media stops playing.
1725 // Here we loop it if the user wants to (has been selected from file menu)
1726 // ----------------------------------------------------------------------------
1727 void wxMediaPlayerNotebookPage::OnMediaFinished(wxMediaEvent& WXUNUSED(event))
1728 {
1729 if(m_bLoop)
1730 {
1731 if ( !m_mediactrl->Play() )
1732 {
1733 wxMessageBox(wxT("Couldn't loop movie!"));
1734 m_playlist->SetItem(m_nLastFileId, 0, wxT("E"));
1735 }
1736 else
1737 ++m_nLoops;
1738 }
1739 else
1740 {
1741 m_playlist->SetItem(m_nLastFileId, 0, wxT("[]"));
1742 }
1743 }
1744
1745 //
1746 // End of MediaPlayer sample
1747 //