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