]> git.saurik.com Git - wxWidgets.git/blame_incremental - samples/mediaplayer/mediaplayer.cpp
avoid asserts from calling isprint(c) with non ASCII c
[wxWidgets.git] / samples / mediaplayer / mediaplayer.cpp
... / ...
CommitLineData
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
98enum
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
121class MyApp : public wxApp
122{
123public:
124 virtual bool OnInit();
125};
126
127// ----------------------------------------------------------------------------
128// MyFrame
129// ----------------------------------------------------------------------------
130
131class MyFrame : public wxFrame
132{
133public:
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
156private:
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
182class 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
192public:
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
204class MyTimer : public wxTimer
205{
206public:
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// ----------------------------------------------------------------------------
234const 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// ----------------------------------------------------------------------------
265IMPLEMENT_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// ----------------------------------------------------------------------------
275bool 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
300MyFrame::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// ----------------------------------------------------------------------------
487MyFrame::~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// ----------------------------------------------------------------------------
509void 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// ----------------------------------------------------------------------------
528wxMediaCtrl* 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// ----------------------------------------------------------------------------
540wxSlider* 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// ----------------------------------------------------------------------------
552void 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// ----------------------------------------------------------------------------
564void 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// ----------------------------------------------------------------------------
579void 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// ----------------------------------------------------------------------------
597void 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// ----------------------------------------------------------------------------
608void 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// ----------------------------------------------------------------------------
626void 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// ----------------------------------------------------------------------------
656void 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// ----------------------------------------------------------------------------
667void 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// ----------------------------------------------------------------------------
685void 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// ----------------------------------------------------------------------------
718void 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// ----------------------------------------------------------------------------
734void 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// ----------------------------------------------------------------------------
752void 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// ----------------------------------------------------------------------------
773void 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
791void 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// ----------------------------------------------------------------------------
810void 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
848MyNotebookPage::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// ----------------------------------------------------------------------------
913void 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// ----------------------------------------------------------------------------
927void 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//