Massive commenting/professionalize and add some other new fun stuff to mediaplayer...
[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 simple example of how to use all the funtionality of
16 // 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 // new notebook page, showing video if neccessary.
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) Not available on Unix :\.
30 // 2) Certain backends can't play the same media file at the same time (MCI,
31 // Cocoa NSMovieView/Quicktime).
32 // 3) Positioning on Mac Carbon is messed up if put in a sub-control like a
33 // Notebook (like this sample does).
34 // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35
36 // ============================================================================
37 // Definitions
38 // ============================================================================
39
40 // ----------------------------------------------------------------------------
41 // Pre-compiled header stuff
42 // ----------------------------------------------------------------------------
43
44 #include "wx/wxprec.h"
45
46 #ifdef __BORLANDC__
47 #pragma hdrstop
48 #endif
49
50 #ifndef WX_PRECOMP
51 #include "wx/wx.h"
52 #endif
53
54 // ----------------------------------------------------------------------------
55 // Headers
56 // ----------------------------------------------------------------------------
57
58 #include "wx/mediactrl.h" //for wxMediaCtrl
59 #include "wx/filedlg.h" //for opening files from OpenFile
60 #include "wx/slider.h" //for a slider for seeking within media
61 #include "wx/sizer.h" //for positioning controls/wxBoxSizer
62 #include "wx/timer.h" //timer for updating status bar
63 #include "wx/textdlg.h" //for getting user text from OpenURL
64 #include "wx/notebook.h" //for wxNotebook and putting movies in pages
65
66 // Use some stuff that's not part of the current API, such as loading
67 // media from a URL, etc.
68 #define wxUSE_UNOFFICIALSTUFF 0
69
70 //Libraries for MSVC with optional backends
71 #ifdef _MSC_VER
72 #if wxUSE_DIRECTSHOW
73 #pragma comment(lib,"strmiids.lib")
74 #endif
75 #if wxUSE_QUICKTIME
76 #pragma comment(lib,"qtmlClient.lib")
77 #endif
78 #endif
79
80 // ----------------------------------------------------------------------------
81 // Bail out if the user doesn't want one of the
82 // things we need
83 // ----------------------------------------------------------------------------
84
85 #if !wxUSE_GUI
86 #error "This is a GUI sample"
87 #endif
88
89 #if !wxUSE_MEDIACTRL || !wxUSE_MENUS || !wxUSE_SLIDER || !wxUSE_TIMER || !wxUSE_NOTEBOOK
90 #error "menus, slider, mediactrl, notebook, and timers must all be enabled for this sample!"
91 #endif
92
93 // ============================================================================
94 // Declarations
95 // ============================================================================
96
97 // ----------------------------------------------------------------------------
98 // Enumurations
99 // ----------------------------------------------------------------------------
100
101 // IDs for the controls and the menu commands
102 enum
103 {
104 // menu items
105 wxID_LOOP = 1,
106 wxID_OPENFILESAMEPAGE,
107 wxID_OPENFILENEWPAGE,
108 wxID_OPENURLSAMEPAGE,
109 wxID_OPENURLNEWPAGE,
110 wxID_CLOSECURRENTPAGE,
111 wxID_PLAY,
112 wxID_PAUSE,
113 // wxID_STOP, [built-in to wxWidgets]
114 // wxID_ABOUT, [built-in to wxWidgets]
115 // wxID_EXIT, [built-in to wxWidgets]
116
117 // event id for our slider
118 wxID_SLIDER,
119
120 // event id for our notebook
121 wxID_NOTEBOOK,
122
123 // event id for our wxMediaCtrl
124 wxID_MEDIACTRL
125 };
126
127 // ----------------------------------------------------------------------------
128 // MyApp
129 // ----------------------------------------------------------------------------
130
131 class MyApp : public wxApp
132 {
133 public:
134 virtual bool OnInit();
135 };
136
137 // ----------------------------------------------------------------------------
138 // MyFrame
139 // ----------------------------------------------------------------------------
140
141 class MyFrame : public wxFrame
142 {
143 public:
144 // Ctor/Dtor
145 MyFrame(const wxString& title);
146 ~MyFrame();
147
148 // Menu event handlers
149 void OnQuit(wxCommandEvent& event);
150 void OnAbout(wxCommandEvent& event);
151 void OnLoop(wxCommandEvent& event);
152
153 void OnOpenFileSamePage(wxCommandEvent& event);
154 void OnOpenFileNewPage(wxCommandEvent& event);
155 void OnOpenURLSamePage(wxCommandEvent& event);
156 void OnOpenURLNewPage(wxCommandEvent& event);
157 void OnCloseCurrentPage(wxCommandEvent& event);
158
159 void OnPlay(wxCommandEvent& event);
160 void OnPause(wxCommandEvent& event);
161 void OnStop(wxCommandEvent& event);
162
163 // Notebook event handlers
164 void OnPageChange(wxNotebookEvent& event);
165
166 private:
167 // Rebuild base status string (see Implementation)
168 void ResetStatus();
169
170 // Common open file code
171 void OpenFile(bool bNewPage);
172 void OpenURL(bool bNewPage);
173
174 // Get the media control and slider of current notebook page
175 wxMediaCtrl* GetCurrentMediaCtrl();
176 wxSlider* GetCurrentSlider();
177
178 class MyTimer* m_timer; //Timer to write info to status bar
179 wxString m_basestatus; //Base status string (see ResetStatus())
180 wxNotebook* m_notebook;
181
182 // So that mytimer can access MyFrame's members
183 friend class MyTimer;
184 };
185
186
187
188 // ----------------------------------------------------------------------------
189 // MyNotebookPage
190 // ----------------------------------------------------------------------------
191
192 class MyNotebookPage : public wxPanel
193 {
194 MyNotebookPage(wxNotebook* book);
195
196 // Slider event handlers
197 void OnSeek(wxCommandEvent& event);
198
199 // Media event handlers
200 void OnMediaStop(wxMediaEvent& event);
201
202 public:
203 friend class MyFrame; //make MyFrame able to access private members
204 wxMediaCtrl* m_mediactrl; //Our media control
205 wxSlider* m_slider; //The slider below our media control
206 int m_nLoops; //Number of times media has looped
207 };
208
209 // ----------------------------------------------------------------------------
210 // MyTimer
211 // ----------------------------------------------------------------------------
212
213 class MyTimer : public wxTimer
214 {
215 public:
216 //Ctor
217 MyTimer(MyFrame* frame) {m_frame = frame;}
218
219 //Called each time the timer's timeout expires
220 void Notify();
221
222 MyFrame* m_frame; //The MyFrame
223 };
224
225 // ============================================================================
226 //
227 // Implementation
228 //
229 // ============================================================================
230
231 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
232 //
233 // [Functions]
234 //
235 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
236
237 // ----------------------------------------------------------------------------
238 // wxGetMediaStateText
239 //
240 // Converts a wxMediaCtrl state into something useful that we can display
241 // to the user
242 // ----------------------------------------------------------------------------
243 const wxChar* wxGetMediaStateText(int nState)
244 {
245 switch(nState)
246 {
247 case wxMEDIASTATE_PLAYING:
248 return wxT("Playing");
249 case wxMEDIASTATE_STOPPED:
250 return wxT("Stopped");
251 ///case wxMEDIASTATE_PAUSED:
252 default:
253 return wxT("Paused");
254 }
255 }
256
257 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
258 //
259 // MyApp
260 //
261 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
262
263 // ----------------------------------------------------------------------------
264 // This sets up this wxApp as the global wxApp that gui calls in wxWidgets
265 // use. For example, if you were to be in windows and use a file dialog,
266 // wxWidgets would use wxTheApp->GetHInstance() which would get the instance
267 // handle of the application. These routines in wx _DO NOT_ check to see if
268 // the wxApp exists, and thus will crash the application if you try it.
269 //
270 // IMPLEMENT_APP does this, and also implements the platform-specific entry
271 // routine, such as main or WinMain(). Use IMPLEMENT_APP_NO_MAIN if you do
272 // not desire this behavior.
273 // ----------------------------------------------------------------------------
274 IMPLEMENT_APP(MyApp)
275
276
277 // ----------------------------------------------------------------------------
278 // MyApp::OnInit
279 //
280 // Where execution starts - akin to a main or WinMain.
281 // 1) Create the frame and show it to the user
282 // 2) return true specifying that we want execution to continue past OnInit
283 // ----------------------------------------------------------------------------
284 bool MyApp::OnInit()
285 {
286 MyFrame *frame = new MyFrame(_T("MediaPlayer wxWidgets Sample"));
287 frame->Show(true);
288
289 return true;
290 }
291
292
293 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
294 //
295 // MyFrame
296 //
297 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
298
299 // ----------------------------------------------------------------------------
300 // MyFrame Constructor
301 //
302 // 1) Create our menus
303 // 2) Create our notebook control and add it to the frame
304 // 3) Create our status bar
305 // 4) Connect our events
306 // 5) Start our timer
307 // ----------------------------------------------------------------------------
308
309 MyFrame::MyFrame(const wxString& title)
310 : wxFrame(NULL, wxID_ANY, title)
311 {
312 //
313 // Create Menus
314 //
315 wxMenu *menuFile = new wxMenu;
316
317 wxMenu *helpMenu = new wxMenu;
318 helpMenu->Append(wxID_ABOUT,
319 _T("&About...\tF1"),
320 _T("Show about dialog"));
321
322 menuFile->Append(wxID_OPENFILESAMEPAGE, _T("&Open File"),
323 _T("Open a File in the current notebook page"));
324 menuFile->Append(wxID_OPENFILENEWPAGE, _T("&Open File in a new page"),
325 _T("Open a File in a new notebook page"));
326 #if wxUSE_UNOFFICIALSTUFF
327 menuFile->Append(wxID_OPENURLSAMEPAGE, _T("&Open URL"),
328 _T("Open a URL in the current notebook page"));
329 menuFile->Append(wxID_OPENURLNEWPAGE, _T("&Open URL in a new page"),
330 _T("Open a URL in a new notebook page"));
331 #endif
332 menuFile->AppendSeparator();
333 menuFile->Append(wxID_CLOSECURRENTPAGE, _T("&Close Current Page"),
334 _T("Close current notebook page"));
335 menuFile->AppendSeparator();
336 menuFile->Append(wxID_PLAY, _T("&Play"), _T("Resume playback"));
337 menuFile->Append(wxID_PAUSE, _T("P&ause"), _T("Pause playback"));
338 menuFile->Append(wxID_STOP, _T("&Stop"), _T("Stop playback"));
339 menuFile->AppendSeparator();
340 menuFile->AppendCheckItem(wxID_LOOP,
341 _T("&Loop"),
342 _T("Loop Selected Media"));
343 menuFile->AppendSeparator();
344 menuFile->Append(wxID_EXIT,
345 _T("E&xit\tAlt-X"),
346 _T("Quit this program"));
347
348 wxMenuBar *menuBar = new wxMenuBar();
349 menuBar->Append(menuFile, _T("&File"));
350 menuBar->Append(helpMenu, _T("&Help"));
351
352 SetMenuBar(menuBar);
353
354 //
355 // Create our notebook - using wxNotebook is luckily pretty
356 // simple and self-explanatory in most cases
357 //
358 m_notebook = new wxNotebook(this, wxID_NOTEBOOK);
359
360 //
361 // Create our status bar
362 //
363 #if wxUSE_STATUSBAR
364 // create a status bar just for fun (by default with 1 pane only)
365 CreateStatusBar(1);
366 #endif // wxUSE_STATUSBAR
367
368 //
369 // Connect events.
370 //
371 // There are two ways in wxWidgets to use events -
372 // Message Maps and Connections.
373 //
374 // Message Maps are implemented by putting
375 // DECLARE_MESSAGE_MAP in your wxEvtHandler-derived
376 // class you want to use for events, such as MyFrame.
377 //
378 // Then after your class declaration you put
379 // BEGIN_EVENT_TABLE(MyFrame, wxFrame)
380 // EVT_XXX(XXX)...
381 // END_EVENT_TABLE()
382 //
383 // Where MyFrame is the class with the DECLARE_MESSAGE_MAP
384 // in it. EVT_XXX(XXX) are each of your handlers, such
385 // as EVT_MENU for menu events and the XXX inside
386 // is the parameters to the event macro - in the case
387 // of EVT_MENU the menu id and then the function to call.
388 //
389 // However, with wxEvtHandler::Connect you can avoid a
390 // global message map for your class and those annoying
391 // macros. You can also change the context in which
392 // the call the handler (more later).
393 //
394 // The downside is that due to the limitation that
395 // wxWidgets doesn't use templates in certain areas,
396 // You have to triple-cast the event function.
397 //
398 // There are five parameters to wxEvtHandler::Connect -
399 //
400 // The first is the id of the instance whose events
401 // you want to handle - i.e. a menu id for menus,
402 // a control id for controls (wxControl::GetId())
403 // and so on.
404 //
405 // The second is the event id. This is the same
406 // as the message maps (EVT_MENU) except prefixed
407 // with "wx" (wxEVT_MENU).
408 //
409 // The third is the function handler for the event -
410 // You need to cast it to the specific event handler
411 // type, then to a wxEventFunction, then to a
412 // wxObjectEventFunction - I.E.
413 // (wxObjectEventFunction)(wxEventFunction)
414 // (wxCommandEventFunction) &MyFrame::MyHandler
415 //
416 // The fourth is an optional userdata param -
417 // this is of historical relevance only and is
418 // there only for backwards compatability.
419 //
420 // The fifth is the context in which to call the
421 // handler - by default (this param is optional)
422 // this. For example in your event handler
423 // if you were to call "this->MyFunc()"
424 // it would literally do this->MyFunc. However,
425 // if you were to pass myHandler as the fifth
426 // parameter, for instance, you would _really_
427 // be calling myHandler->MyFunc, even though
428 // the compiler doesn't really know it.
429 //
430
431 //
432 // Menu events
433 //
434 this->Connect(wxID_EXIT, wxEVT_COMMAND_MENU_SELECTED,
435 (wxObjectEventFunction) (wxEventFunction)
436 (wxCommandEventFunction) &MyFrame::OnQuit);
437
438 this->Connect(wxID_ABOUT, wxEVT_COMMAND_MENU_SELECTED,
439 (wxObjectEventFunction) (wxEventFunction)
440 (wxCommandEventFunction) &MyFrame::OnAbout);
441
442 this->Connect(wxID_LOOP, wxEVT_COMMAND_MENU_SELECTED,
443 (wxObjectEventFunction) (wxEventFunction)
444 (wxCommandEventFunction) &MyFrame::OnLoop);
445
446 this->Connect(wxID_OPENFILENEWPAGE, wxEVT_COMMAND_MENU_SELECTED,
447 (wxObjectEventFunction) (wxEventFunction)
448 (wxCommandEventFunction) &MyFrame::OnOpenFileNewPage);
449
450 this->Connect(wxID_OPENFILESAMEPAGE, wxEVT_COMMAND_MENU_SELECTED,
451 (wxObjectEventFunction) (wxEventFunction)
452 (wxCommandEventFunction) &MyFrame::OnOpenFileSamePage);
453
454 this->Connect(wxID_OPENURLNEWPAGE, wxEVT_COMMAND_MENU_SELECTED,
455 (wxObjectEventFunction) (wxEventFunction)
456 (wxCommandEventFunction) &MyFrame::OnOpenURLNewPage);
457
458 this->Connect(wxID_OPENURLSAMEPAGE, wxEVT_COMMAND_MENU_SELECTED,
459 (wxObjectEventFunction) (wxEventFunction)
460 (wxCommandEventFunction) &MyFrame::OnOpenURLSamePage);
461
462 this->Connect(wxID_CLOSECURRENTPAGE, wxEVT_COMMAND_MENU_SELECTED,
463 (wxObjectEventFunction) (wxEventFunction)
464 (wxCommandEventFunction) &MyFrame::OnCloseCurrentPage);
465
466 this->Connect(wxID_PLAY, wxEVT_COMMAND_MENU_SELECTED,
467 (wxObjectEventFunction) (wxEventFunction)
468 (wxCommandEventFunction) &MyFrame::OnPlay);
469
470 this->Connect(wxID_PAUSE, wxEVT_COMMAND_MENU_SELECTED,
471 (wxObjectEventFunction) (wxEventFunction)
472 (wxCommandEventFunction) &MyFrame::OnPause);
473
474 this->Connect(wxID_STOP, wxEVT_COMMAND_MENU_SELECTED,
475 (wxObjectEventFunction) (wxEventFunction)
476 (wxCommandEventFunction) &MyFrame::OnStop);
477
478 //
479 // Notebook events
480 //
481 this->Connect(wxID_NOTEBOOK, wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED,
482 (wxObjectEventFunction) (wxEventFunction)
483 (wxNotebookEventFunction) &MyFrame::OnPageChange);
484
485 //
486 // End of Events
487 //
488
489 //
490 // Create a timer to update our status bar
491 //
492 m_timer = new MyTimer(this);
493 m_timer->Start(100);
494 }
495
496 // ----------------------------------------------------------------------------
497 // MyFrame Destructor
498 //
499 // 1) Deletes child objects implicitly
500 // 2) Delete our timer explicitly
501 // ----------------------------------------------------------------------------
502 MyFrame::~MyFrame()
503 {
504 delete m_timer;
505 }
506
507 // ----------------------------------------------------------------------------
508 // MyFrame::ResetStatus
509 //
510 // Here we just make a simple status string with some useful info about
511 // the media that we won't change later - such as the length of the media.
512 //
513 // We then append some other info that changes in MyTimer::Notify, then
514 // set the status bar to this text.
515 //
516 // In real applications, you'd want to find a better way to do this,
517 // such as static text controls (wxStaticText).
518 //
519 // We display info here in seconds (wxMediaCtrl uses milliseconds - that's why
520 // we divide by 1000).
521 //
522 // We also reset our loop counter here.
523 // ----------------------------------------------------------------------------
524 void MyFrame::ResetStatus()
525 {
526 wxMediaCtrl* currentMediaCtrl = GetCurrentMediaCtrl();
527
528 m_basestatus = wxString::Format(_T("Size(x,y):%i,%i ")
529 _T("Length(Seconds):%u Speed:%1.1fx"),
530 currentMediaCtrl->GetBestSize().x,
531 currentMediaCtrl->GetBestSize().y,
532 (unsigned)((currentMediaCtrl->Length() / 1000)),
533 currentMediaCtrl->GetPlaybackRate()
534 );
535 }
536
537 // ----------------------------------------------------------------------------
538 // MyFrame::GetCurrentMediaCtrl
539 //
540 // Obtains the media control of the current page, or NULL if there are no
541 // pages open
542 // ----------------------------------------------------------------------------
543 wxMediaCtrl* MyFrame::GetCurrentMediaCtrl()
544 {
545 wxASSERT(m_notebook->GetCurrentPage() != NULL);
546 return ((MyNotebookPage*)m_notebook->GetCurrentPage())->m_mediactrl;
547 }
548
549 // ----------------------------------------------------------------------------
550 // MyFrame::GetCurrentSlider
551 //
552 // Obtains the slider of the current page, or NULL if there are no
553 // pages open
554 // ----------------------------------------------------------------------------
555 wxSlider* MyFrame::GetCurrentSlider()
556 {
557 wxASSERT(m_notebook->GetCurrentPage() != NULL);
558 return ((MyNotebookPage*)m_notebook->GetCurrentPage())->m_slider;
559 }
560
561 // ----------------------------------------------------------------------------
562 // MyFrame::OnQuit
563 //
564 // Called from file->quit.
565 // Closes this application.
566 // ----------------------------------------------------------------------------
567 void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
568 {
569 // true is to force the frame to close
570 Close(true);
571 }
572
573 // ----------------------------------------------------------------------------
574 // MyFrame::OnAbout
575 //
576 // Called from help->about.
577 // Gets some info about this application.
578 // ----------------------------------------------------------------------------
579 void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
580 {
581 wxString msg;
582 msg.Printf( _T("This is a test of wxMediaCtrl.\n")
583 _T("Welcome to %s"), wxVERSION_STRING);
584
585 wxMessageBox(msg, _T("About wxMediaCtrl test"), wxOK | wxICON_INFORMATION, this);
586 }
587
588 // ----------------------------------------------------------------------------
589 // MyFrame::OnLoop
590 //
591 // Called from file->loop.
592 // Changes the state of whether we want to loop or not.
593 // ----------------------------------------------------------------------------
594 void MyFrame::OnLoop(wxCommandEvent& WXUNUSED(event))
595 {
596 if(!m_notebook->GetCurrentPage())
597 {
598 wxMessageBox(wxT("No files are currently open!"));
599 return;
600 }
601 GetCurrentMediaCtrl()->Loop( !GetCurrentMediaCtrl()->IsLooped() );
602 }
603
604 // ----------------------------------------------------------------------------
605 // MyFrame::OnOpenFileSamePage
606 //
607 // Called from file->openfile.
608 // Opens and plays a media file in the current notebook page
609 // ----------------------------------------------------------------------------
610 void MyFrame::OnOpenFileSamePage(wxCommandEvent& WXUNUSED(event))
611 {
612 OpenFile(false);
613 }
614
615 // ----------------------------------------------------------------------------
616 // MyFrame::OnOpenFileNewPage
617 //
618 // Called from file->openfileinnewpage.
619 // Opens and plays a media file in a new notebook page
620 // ----------------------------------------------------------------------------
621 void MyFrame::OnOpenFileNewPage(wxCommandEvent& WXUNUSED(event))
622 {
623 OpenFile(true);
624 }
625
626 // ----------------------------------------------------------------------------
627 // MyFrame::OpenFile
628 //
629 // Code to actually open the media file
630 //
631 // 1) Create file dialog and ask the user for input file
632 // 2) If the user didn't want anything, break out
633 // 3) Create a new page if the user wanted one or there isn't a current page
634 // 4) Load the media
635 // 5) Play the media
636 // 6) Reset the text on the status bar
637 // 7) Set the slider of the current page to accurately reflect media length
638 // ----------------------------------------------------------------------------
639 void MyFrame::OpenFile(bool bNewPage)
640 {
641 wxFileDialog fd(this);
642
643 if(fd.ShowModal() == wxID_OK)
644 {
645 if(bNewPage || !m_notebook->GetCurrentPage())
646 m_notebook->AddPage(new MyNotebookPage(m_notebook), fd.GetPath(), true);
647
648 if( !GetCurrentMediaCtrl()->Load(fd.GetPath()) )
649 wxMessageBox(wxT("Couldn't load file!"));
650
651 if( !GetCurrentMediaCtrl()->Play() )
652 wxMessageBox(wxT("Couldn't play movie!"));
653
654 ResetStatus();
655
656 GetCurrentSlider()->SetRange(0,
657 (int)(GetCurrentMediaCtrl()->Length() / 1000));
658
659 }
660 }
661
662 // ----------------------------------------------------------------------------
663 // MyFrame::OnOpenURLSamePage
664 //
665 // Called from file->openurl.
666 // Opens and plays a media file from a URL in the current notebook page
667 // ----------------------------------------------------------------------------
668 void MyFrame::OnOpenURLSamePage(wxCommandEvent& WXUNUSED(event))
669 {
670 OpenURL(false);
671 }
672
673 // ----------------------------------------------------------------------------
674 // MyFrame::OnOpenURLNewPage
675 //
676 // Called from file->openurlinnewpage.
677 // Opens and plays a media file from a URL in a new notebook page
678 // ----------------------------------------------------------------------------
679 void MyFrame::OnOpenURLNewPage(wxCommandEvent& WXUNUSED(event))
680 {
681 OpenURL(true);
682 }
683
684 // ----------------------------------------------------------------------------
685 // MyFrame::OpenURL
686 //
687 // Code to actually open the media file from a URL
688 //
689 // 1) Create text input dialog and ask the user for an input URL
690 // 2) If the user didn't want anything, break out
691 // 3) Create a new page if the user wanted one or there isn't a current page
692 // 4) Load the media
693 // 5) Play the media
694 // 6) Reset the text on the status bar
695 // 7) Set the slider of the current page to accurately reflect media length
696 // ----------------------------------------------------------------------------
697 void MyFrame::OpenURL(bool bNewPage)
698 {
699 wxString theURL = wxGetTextFromUser(wxT("Enter the URL that has the movie to play"));
700
701 if(!theURL.empty())
702 {
703 if(bNewPage || !m_notebook->GetCurrentPage())
704 m_notebook->AddPage(new MyNotebookPage(m_notebook), theURL, true);
705
706 if( !GetCurrentMediaCtrl()->Load(wxURI(theURL)) )
707 wxMessageBox(wxT("Couldn't load URL!"));
708
709 if( !GetCurrentMediaCtrl()->Play() )
710 wxMessageBox(wxT("Couldn't play movie!"));
711
712 ResetStatus();
713
714 GetCurrentSlider()->SetRange(0,
715 (int)(GetCurrentMediaCtrl()->Length() / 1000));
716 }
717 }
718
719 // ----------------------------------------------------------------------------
720 // MyFrame::OnCloseCurrentPage
721 //
722 // Called when the user wants to close the current notebook page
723 //
724 // 1) Get the current page number (wxControl::GetSelection)
725 // 2) If there is no current page, break out
726 // 3) Delete the current page
727 // ----------------------------------------------------------------------------
728 void MyFrame::OnCloseCurrentPage(wxCommandEvent& WXUNUSED(event))
729 {
730 int sel = m_notebook->GetSelection();
731
732 if (sel != wxNOT_FOUND)
733 {
734 m_notebook->DeletePage(sel);
735 }
736 }
737
738 // ----------------------------------------------------------------------------
739 // MyFrame::OnPlay
740 //
741 // Called from file->play.
742 // Resumes the media if it is paused or stopped.
743 // ----------------------------------------------------------------------------
744 void MyFrame::OnPlay(wxCommandEvent& WXUNUSED(event))
745 {
746 if(!m_notebook->GetCurrentPage())
747 {
748 wxMessageBox(wxT("No files are currently open!"));
749 return;
750 }
751
752 if( !GetCurrentMediaCtrl()->Play() )
753 wxMessageBox(wxT("Couldn't play movie!"));
754 }
755
756 // ----------------------------------------------------------------------------
757 // MyFrame::OnPause
758 //
759 // Called from file->pause.
760 // Pauses the media in-place.
761 // ----------------------------------------------------------------------------
762 void MyFrame::OnPause(wxCommandEvent& WXUNUSED(event))
763 {
764 if(!m_notebook->GetCurrentPage())
765 {
766 wxMessageBox(wxT("No files are currently open!"));
767 return;
768 }
769
770 if( !GetCurrentMediaCtrl()->Pause() )
771 wxMessageBox(wxT("Couldn't pause movie!"));
772 }
773
774 // ----------------------------------------------------------------------------
775 // MyFrame::OnStop
776 //
777 // Called from file->stop.
778 // Where it stops depends on whether you can seek in the
779 // media control or not - if you can it stops and seeks to the beginning,
780 // otherwise it will appear to be at the end - but it will start over again
781 // when Play() is called
782 // ----------------------------------------------------------------------------
783 void MyFrame::OnStop(wxCommandEvent& WXUNUSED(event))
784 {
785 if(!m_notebook->GetCurrentPage())
786 {
787 wxMessageBox(wxT("No files are currently open!"));
788 return;
789 }
790
791 if( !GetCurrentMediaCtrl()->Stop() )
792 wxMessageBox(wxT("Couldn't stop movie!"));
793 }
794
795 // ----------------------------------------------------------------------------
796 // MyFrame::OnCloseCurrentPage
797 //
798 // Called when the user wants to closes the current notebook page
799 // ----------------------------------------------------------------------------
800
801 void MyFrame::OnPageChange(wxNotebookEvent& WXUNUSED(event))
802 {
803 ResetStatus();
804 }
805
806 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
807 //
808 // MyTimer
809 //
810 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
811
812 // ----------------------------------------------------------------------------
813 // MyTimer::Notify
814 //
815 // 1) Update our slider with the position were are in in the media
816 // 2) Update our status bar with the base text from MyFrame::ResetStatus,
817 // append some non-static (changing) info to it, then set the
818 // status bar text to that result
819 // ----------------------------------------------------------------------------
820 void MyTimer::Notify()
821 {
822 if (!m_frame->m_notebook->GetCurrentPage()) return;
823 wxMediaCtrl* m_mediactrl = ((MyNotebookPage*)m_frame->m_notebook->GetCurrentPage())->m_mediactrl;
824 wxSlider* m_slider = ((MyNotebookPage*)m_frame->m_notebook->GetCurrentPage())->m_slider;
825 if (!m_mediactrl) return;
826
827 long lPosition = (long)( m_mediactrl->Tell() / 1000 );
828 m_slider->SetValue(lPosition);
829
830 #if wxUSE_STATUSBAR
831 m_frame->SetStatusText(wxString::Format(
832 _T("%s Pos:%u State:%s Loops:%i"),
833 m_frame->m_basestatus.c_str(),
834 (unsigned int)lPosition,
835 wxGetMediaStateText(m_mediactrl->GetState()),
836 ((MyNotebookPage*)m_frame->m_notebook->GetCurrentPage())->m_nLoops
837
838 )
839 );
840 #endif
841
842 }
843
844
845 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
846 //
847 // MyNotebookPage
848 //
849 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
850
851 // ----------------------------------------------------------------------------
852 // MyNotebookPage Constructor
853 //
854 // Creates a media control and slider and adds it to this panel,
855 // along with some sizers for positioning
856 // ----------------------------------------------------------------------------
857
858 MyNotebookPage::MyNotebookPage(wxNotebook* theBook) :
859 wxPanel(theBook, wxID_ANY), m_nLoops(0)
860 {
861 //
862 // Create and attach the first/main sizer
863 //
864 wxBoxSizer* vertsizer = new wxBoxSizer(wxVERTICAL);
865 this->SetSizer(vertsizer);
866 this->SetAutoLayout(true);
867
868 //
869 // Create our media control
870 //
871 m_mediactrl = new wxMediaCtrl(this, wxID_MEDIACTRL);
872 vertsizer->Add(m_mediactrl, 0, wxALIGN_CENTER_HORIZONTAL|wxALL, 5);
873
874 //
875 // Create our slider
876 //
877 m_slider = new wxSlider(this, wxID_SLIDER, 0, //init
878 0, //start
879 0, //end
880 wxDefaultPosition, wxDefaultSize,
881 wxSL_HORIZONTAL );
882 vertsizer->Add(m_slider, 0, wxALIGN_CENTER_HORIZONTAL|wxALL|wxEXPAND , 5);
883
884
885 //
886 // Create the second sizer which will position things
887 // vertically -
888 //
889 // -------Menu----------
890 // [m_mediactrl]
891 //
892 // [m_slider]
893 //
894 wxBoxSizer* horzsizer = new wxBoxSizer(wxHORIZONTAL);
895 vertsizer->Add(horzsizer, 0, wxALIGN_CENTER_HORIZONTAL|wxALL, 5);
896
897 //
898 // Slider events
899 //
900 this->Connect(wxID_SLIDER, wxEVT_COMMAND_SLIDER_UPDATED,
901 (wxObjectEventFunction) (wxEventFunction)
902 (wxCommandEventFunction) &MyNotebookPage::OnSeek);
903
904 //
905 // Media Control events
906 //
907 this->Connect(wxID_MEDIACTRL, wxEVT_MEDIA_STOP,
908 (wxObjectEventFunction) (wxEventFunction)
909 (wxMediaEventFunction) &MyNotebookPage::OnMediaStop);
910 }
911
912 // ----------------------------------------------------------------------------
913 // MyNotebook::OnSeek
914 //
915 // Called from file->seek.
916 // Called when the user moves the slider -
917 // seeks to a position within the media
918 // ----------------------------------------------------------------------------
919 void MyNotebookPage::OnSeek(wxCommandEvent& WXUNUSED(event))
920 {
921 if( m_mediactrl->Seek(
922 m_slider->GetValue() * 1000
923 ) == wxInvalidOffset )
924 wxMessageBox(wxT("Couldn't seek in movie!"));
925 }
926
927 // ----------------------------------------------------------------------------
928 // MyNotebookPage::OnMediaStop
929 //
930 // Called when the media is about to stop playing.
931 // ----------------------------------------------------------------------------
932 void MyNotebookPage::OnMediaStop(wxMediaEvent& WXUNUSED(event))
933 {
934 if(m_mediactrl->IsLooped())
935 ++m_nLoops;
936 }
937
938 //
939 // End of MediaPlayer sample
940 //