X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/eaf0d558dcdde82e9278d2d8be7f3eb97232fdb5..520a495c5972c9e966ba91cb7923bbd5b20f7197:/samples/mediaplayer/mediaplayer.cpp diff --git a/samples/mediaplayer/mediaplayer.cpp b/samples/mediaplayer/mediaplayer.cpp index badca7d6dd..c7128dcdf0 100644 --- a/samples/mediaplayer/mediaplayer.cpp +++ b/samples/mediaplayer/mediaplayer.cpp @@ -1,5 +1,5 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: mediactrltest. +/////////////////////////////////////////////////////////////////////////////// +// Name: mediaplayer.cpp // Purpose: wxMediaCtrl sample // Author: Ryan Norton // Modified by: @@ -7,120 +7,239 @@ // RCS-ID: $Id$ // Copyright: (c) Ryan Norton // Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + +// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +// MediaPlayer +// +// This is a simple example of how to use all the funtionality of +// the wxMediaCtrl class in wxWidgets. +// +// To use this sample, simply select Open File from the file menu, +// select the file you want to play - and MediaPlayer will play the file in a +// new notebook page, showing video if neccessary. +// +// You can select one of the menu options, or move the slider around +// to manipulate what is playing. +// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +// Known bugs with wxMediaCtrl: +// +// 1) Certain backends can't play the same media file at the same time (MCI, +// Cocoa NSMovieView-Quicktime). +// 2) Positioning on Mac Carbon is messed up if put in a sub-control like a +// Notebook (like this sample does) on OS versions < 10.2. +// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% // ============================================================================ -// declarations +// Definitions // ============================================================================ // ---------------------------------------------------------------------------- -// headers +// Pre-compiled header stuff // ---------------------------------------------------------------------------- -// For compilers that support precompilation, includes "wx/wx.h". #include "wx/wxprec.h" #ifdef __BORLANDC__ #pragma hdrstop #endif -// for all others, include the necessary headers (this file is usually all you -// need because it includes almost all "standard" wxWidgets headers) #ifndef WX_PRECOMP #include "wx/wx.h" #endif // ---------------------------------------------------------------------------- -// resources +// Headers // ---------------------------------------------------------------------------- -// the application icon (under Windows and OS/2 it is in resources and even -// though we could still include the XPM here it would be unused) -#if !defined(__WXMSW__) && !defined(__WXPM__) -// #include "../sample.xpm" +#include "wx/mediactrl.h" //for wxMediaCtrl +#include "wx/filedlg.h" //for opening files from OpenFile +#include "wx/slider.h" //for a slider for seeking within media +#include "wx/sizer.h" //for positioning controls/wxBoxSizer +#include "wx/timer.h" //timer for updating status bar +#include "wx/textdlg.h" //for getting user text from OpenURL +#include "wx/notebook.h" //for wxNotebook and putting movies in pages + +// Use some stuff that's not part of the current API, such as loading +// media from a URL, etc. +#define wxUSE_UNOFFICIALSTUFF 0 + +//Libraries for MSVC with optional backends +#ifdef _MSC_VER + #if wxUSE_DIRECTSHOW + #pragma comment(lib,"strmiids.lib") + #endif + #if wxUSE_QUICKTIME + #pragma comment(lib,"qtmlClient.lib") + #endif #endif -#include "wx/mediactrl.h" -#include "wx/filedlg.h" -#include "wx/slider.h" -#include "wx/sizer.h" - -#include "wx/timer.h" +// ---------------------------------------------------------------------------- +// Bail out if the user doesn't want one of the +// things we need +// ---------------------------------------------------------------------------- +#if !wxUSE_GUI +#error "This is a GUI sample" +#endif -#if !wxUSE_MEDIACTRL -#error "wxUSE_MEDIACTRL must be enabled to use this sample!" +#if !wxUSE_MEDIACTRL || !wxUSE_MENUS || !wxUSE_SLIDER || !wxUSE_TIMER || !wxUSE_NOTEBOOK +#error "menus, slider, mediactrl, notebook, and timers must all be enabled for this sample!" #endif +// ============================================================================ +// Declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// Enumurations +// ---------------------------------------------------------------------------- + +// IDs for the controls and the menu commands +enum +{ + // menu items + wxID_LOOP = 1, + wxID_OPENFILESAMEPAGE, + wxID_OPENFILENEWPAGE, + wxID_OPENURLSAMEPAGE, + wxID_OPENURLNEWPAGE, + wxID_CLOSECURRENTPAGE, + wxID_PLAY, + wxID_PAUSE, +// wxID_STOP, [built-in to wxWidgets] +// wxID_ABOUT, [built-in to wxWidgets] +// wxID_EXIT, [built-in to wxWidgets] + + // event id for our slider + wxID_SLIDER, + + // event id for our notebook + wxID_NOTEBOOK, + + // event id for our wxMediaCtrl + wxID_MEDIACTRL +}; + // ---------------------------------------------------------------------------- -// private classes +// MyApp // ---------------------------------------------------------------------------- -// Define a new application type, each program should derive a class from wxApp class MyApp : public wxApp { public: - // override base class virtuals - // ---------------------------- - - // this one is called on application startup and is a good place for the app - // initialization (doing it here and not in the ctor allows to have an error - // return: if OnInit() returns false, the application terminates) virtual bool OnInit(); }; +// ---------------------------------------------------------------------------- +// MyFrame +// ---------------------------------------------------------------------------- - -// Define a new frame type: this is going to be our main frame class MyFrame : public wxFrame { public: - // ctor(s) + // Ctor/Dtor MyFrame(const wxString& title); ~MyFrame(); - // event handlers (these functions should _not_ be virtual) + // Menu event handlers void OnQuit(wxCommandEvent& event); void OnAbout(wxCommandEvent& event); void OnLoop(wxCommandEvent& event); - void OnOpenFile(wxCommandEvent& event); - void OnOpenURL(wxCommandEvent& event); + void OnOpenFileSamePage(wxCommandEvent& event); + void OnOpenFileNewPage(wxCommandEvent& event); + void OnOpenURLSamePage(wxCommandEvent& event); + void OnOpenURLNewPage(wxCommandEvent& event); + void OnCloseCurrentPage(wxCommandEvent& event); void OnPlay(wxCommandEvent& event); void OnPause(wxCommandEvent& event); void OnStop(wxCommandEvent& event); - void OnSeek(wxCommandEvent& event); - - void OnMediaFinished(wxMediaEvent& event); + // Notebook event handlers + void OnPageChange(wxNotebookEvent& event); private: - void ResetStatus() - { - m_basestatus = wxString::Format(_T("Size(x,y):%i,%i Length(Seconds):%u Speed:%1.1fx"), - m_movie->GetBestSize().x, - m_movie->GetBestSize().y, - m_movie->GetDuration() / 1000, - m_movie->GetPlaybackRate() - ); - - m_slider->SetRange(0, m_movie->GetDuration() / 1000); - } + // Rebuild base status string (see Implementation) + void ResetStatus(); + + // Common open file code + void OpenFile(bool bNewPage); + void OpenURL(bool bNewPage); - wxMediaCtrl* m_movie; - wxSlider* m_slider; - wxBoxSizer* m_sizer; - class MyTimer* m_timer; + // Get the media control and slider of current notebook page + wxMediaCtrl* GetCurrentMediaCtrl(); + wxSlider* GetCurrentSlider(); + + class MyTimer* m_timer; //Timer to write info to status bar + wxString m_basestatus; //Base status string (see ResetStatus()) + wxNotebook* m_notebook; + + // So that mytimer can access MyFrame's members friend class MyTimer; - wxString m_basestatus; +}; + + + +// ---------------------------------------------------------------------------- +// MyNotebookPage +// ---------------------------------------------------------------------------- - bool m_bLoop; +class MyNotebookPage : public wxPanel +{ + MyNotebookPage(wxNotebook* book); + + // Slider event handlers + void OnSeek(wxCommandEvent& event); - // any class wishing to process wxWidgets events must use this macro - DECLARE_EVENT_TABLE() + // Media event handlers + void OnMediaFinished(wxMediaEvent& event); + +public: + friend class MyFrame; //make MyFrame able to access private members + wxMediaCtrl* m_mediactrl; //Our media control + wxSlider* m_slider; //The slider below our media control + int m_nLoops; //Number of times media has looped + bool m_bLoop; //Whether we are looping or not }; +// ---------------------------------------------------------------------------- +// MyTimer +// ---------------------------------------------------------------------------- + +class MyTimer : public wxTimer +{ +public: + //Ctor + MyTimer(MyFrame* frame) {m_frame = frame;} + + //Called each time the timer's timeout expires + void Notify(); + + MyFrame* m_frame; //The MyFrame +}; + +// ============================================================================ +// +// Implementation +// +// ============================================================================ + +// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// +// [Functions] +// +// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +// ---------------------------------------------------------------------------- +// wxGetMediaStateText +// +// Converts a wxMediaCtrl state into something useful that we can display +// to the user +// ---------------------------------------------------------------------------- const wxChar* wxGetMediaStateText(int nState) { switch(nState) @@ -135,192 +254,328 @@ const wxChar* wxGetMediaStateText(int nState) } } -class MyTimer : public wxTimer -{ -public: - MyTimer(MyFrame* frame) {m_frame = frame;} - - void Notify() - { - long lPosition = m_frame->m_movie->GetPosition() / 1000; - m_frame->m_slider->SetValue(lPosition); - - - m_frame->SetStatusText(wxString::Format(_T("%s Pos:%u State:%s"), - m_frame->m_basestatus.c_str(), - lPosition, - wxGetMediaStateText(m_frame->m_movie->GetState()) - ) - ); - - } - - MyFrame* m_frame; -}; - +// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// +// MyApp +// +// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // ---------------------------------------------------------------------------- -// constants +// This sets up this wxApp as the global wxApp that gui calls in wxWidgets +// use. For example, if you were to be in windows and use a file dialog, +// wxWidgets would use wxTheApp->GetHInstance() which would get the instance +// handle of the application. These routines in wx _DO NOT_ check to see if +// the wxApp exists, and thus will crash the application if you try it. +// +// IMPLEMENT_APP does this, and also implements the platform-specific entry +// routine, such as main or WinMain(). Use IMPLEMENT_APP_NO_MAIN if you do +// not desire this behavior. // ---------------------------------------------------------------------------- - -// IDs for the controls and the menu commands -enum -{ - // menu items - Minimal_Quit = wxID_EXIT, - - // it is important for the id corresponding to the "About" command to have - // this standard value as otherwise it won't be handled properly under Mac - // (where it is special and put into the "Apple" menu) - Minimal_About = wxID_ABOUT, - - Minimal_Slider = 1, - Minimal_Media, - Minimal_Loop, - Minimal_OpenFile, - Minimal_OpenURL, - Minimal_Play, - Minimal_Pause, - Minimal_Stop -}; - -// ---------------------------------------------------------------------------- -// event tables and other macros for wxWidgets -// ---------------------------------------------------------------------------- - -// the event tables connect the wxWidgets events with the functions (event -// handlers) which process them. It can be also done at run-time, but for the -// simple menu events like this the static method is much simpler. -BEGIN_EVENT_TABLE(MyFrame, wxFrame) - EVT_MENU(Minimal_Quit, MyFrame::OnQuit) - EVT_MENU(Minimal_About, MyFrame::OnAbout) - EVT_MENU(Minimal_Loop, MyFrame::OnLoop) - EVT_MENU(Minimal_OpenFile, MyFrame::OnOpenFile) - EVT_MENU(Minimal_OpenURL, MyFrame::OnOpenURL) - EVT_MENU(Minimal_Play, MyFrame::OnPlay) - EVT_MENU(Minimal_Pause, MyFrame::OnPause) - EVT_MENU(Minimal_Stop, MyFrame::OnStop) - EVT_SLIDER(Minimal_Slider, MyFrame::OnSeek) - EVT_MEDIA_FINISHED(Minimal_Media, MyFrame::OnMediaFinished) -END_EVENT_TABLE() - -// Create a new application object: this macro will allow wxWidgets to create -// the application object during program execution (it's better than using a -// static object for many reasons) and also implements the accessor function -// wxGetApp() which will return the reference of the right type (i.e. MyApp and -// not wxApp) IMPLEMENT_APP(MyApp) -// ============================================================================ -// implementation -// ============================================================================ // ---------------------------------------------------------------------------- -// the application class +// MyApp::OnInit +// +// Where execution starts - akin to a main or WinMain. +// 1) Create the frame and show it to the user +// 2) return true specifying that we want execution to continue past OnInit // ---------------------------------------------------------------------------- - -// 'Main program' equivalent: the program execution "starts" here bool MyApp::OnInit() { - // create the main application window - MyFrame *frame = new MyFrame(_T("Minimal wxWidgets App")); - - // and show it (the frames, unlike simple controls, are not shown when - // created initially) + MyFrame *frame = new MyFrame(_T("MediaPlayer wxWidgets Sample")); frame->Show(true); - // success: wxApp::OnRun() will be called which will enter the main message - // loop and the application will run. If we returned false here, the - // application would exit immediately. return true; } + +// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// +// MyFrame +// +// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + // ---------------------------------------------------------------------------- -// main frame +// MyFrame Constructor +// +// 1) Create our menus +// 2) Create our notebook control and add it to the frame +// 3) Create our status bar +// 4) Connect our events +// 5) Start our timer // ---------------------------------------------------------------------------- -// frame constructor MyFrame::MyFrame(const wxString& title) - : wxFrame(NULL, wxID_ANY, title), m_timer(NULL) + : wxFrame(NULL, wxID_ANY, title) { - // set the frame icon -// SetIcon(wxICON(sample)); - -#if wxUSE_MENUS - // create a menu bar + // + // Create Menus + // wxMenu *menuFile = new wxMenu; - // the "About" item should be in the help menu wxMenu *helpMenu = new wxMenu; - helpMenu->Append(Minimal_About, _T("&About...\tF1"), _T("Show about dialog")); - - menuFile->Append(Minimal_OpenFile, _T("&Open File"), _T("Open a File")); - menuFile->Append(Minimal_OpenURL, _T("Open &URL"), _T("Open a URL")); + helpMenu->Append(wxID_ABOUT, + _T("&About...\tF1"), + _T("Show about dialog")); + + menuFile->Append(wxID_OPENFILESAMEPAGE, _T("&Open File"), + _T("Open a File in the current notebook page")); + menuFile->Append(wxID_OPENFILENEWPAGE, _T("&Open File in a new page"), + _T("Open a File in a new notebook page")); +#if wxUSE_UNOFFICIALSTUFF + menuFile->Append(wxID_OPENURLSAMEPAGE, _T("&Open URL"), + _T("Open a URL in the current notebook page")); + menuFile->Append(wxID_OPENURLNEWPAGE, _T("&Open URL in a new page"), + _T("Open a URL in a new notebook page")); +#endif + menuFile->AppendSeparator(); + menuFile->Append(wxID_CLOSECURRENTPAGE, _T("&Close Current Page"), + _T("Close current notebook page")); menuFile->AppendSeparator(); - menuFile->Append(Minimal_Play, _T("&Play"), _T("Resume playback")); - menuFile->Append(Minimal_Pause, _T("P&ause"), _T("Pause playback")); - menuFile->Append(Minimal_Stop, _T("&Stop"), _T("Stop playback")); + menuFile->Append(wxID_PLAY, _T("&Play"), _T("Resume playback")); + menuFile->Append(wxID_PAUSE, _T("P&ause"), _T("Pause playback")); + menuFile->Append(wxID_STOP, _T("&Stop"), _T("Stop playback")); menuFile->AppendSeparator(); - menuFile->AppendCheckItem(Minimal_Loop, _T("&Loop"), _T("Loop Selected Media")); + menuFile->AppendCheckItem(wxID_LOOP, + _T("&Loop"), + _T("Loop Selected Media")); menuFile->AppendSeparator(); - menuFile->Append(Minimal_Quit, _T("E&xit\tAlt-X"), _T("Quit this program")); + menuFile->Append(wxID_EXIT, + _T("E&xit\tAlt-X"), + _T("Quit this program")); - // now append the freshly created menu to the menu bar... wxMenuBar *menuBar = new wxMenuBar(); menuBar->Append(menuFile, _T("&File")); menuBar->Append(helpMenu, _T("&Help")); - // ... and attach this menu bar to the frame SetMenuBar(menuBar); -#endif // wxUSE_MENUS - m_sizer = new wxBoxSizer(wxVERTICAL); - this->SetSizer(m_sizer); - this->SetAutoLayout(true); - -// m_sizer->SetSizeHints(this); -// m_sizer->Fit(this); - - m_movie = new wxMediaCtrl(this, Minimal_Media, wxT("")); - m_sizer->Add(m_movie, 0, wxALIGN_CENTER_HORIZONTAL|wxALL, 5); - - m_slider = new wxSlider(this, Minimal_Slider, 0, //init - 0, //start - 0, //end - wxDefaultPosition, wxDefaultSize, - wxSL_HORIZONTAL ); - m_sizer->Add(m_slider, 0, wxALIGN_CENTER_HORIZONTAL|wxALL|wxEXPAND , 5); - - wxBoxSizer* horzsizer = new wxBoxSizer(wxHORIZONTAL); - m_sizer->Add(horzsizer, 0, wxALIGN_CENTER_HORIZONTAL|wxALL, 5); - - m_bLoop = false; - - m_timer = new MyTimer(this); - m_timer->Start(100); + // + // Create our notebook - using wxNotebook is luckily pretty + // simple and self-explanatory in most cases + // + m_notebook = new wxNotebook(this, wxID_NOTEBOOK); + // + // Create our status bar + // #if wxUSE_STATUSBAR // create a status bar just for fun (by default with 1 pane only) CreateStatusBar(1); - ResetStatus(); - SetStatusText(m_basestatus); #endif // wxUSE_STATUSBAR + + // + // Connect events. + // + // There are two ways in wxWidgets to use events - + // Message Maps and Connections. + // + // Message Maps are implemented by putting + // DECLARE_MESSAGE_MAP in your wxEvtHandler-derived + // class you want to use for events, such as MyFrame. + // + // Then after your class declaration you put + // BEGIN_EVENT_TABLE(MyFrame, wxFrame) + // EVT_XXX(XXX)... + // END_EVENT_TABLE() + // + // Where MyFrame is the class with the DECLARE_MESSAGE_MAP + // in it. EVT_XXX(XXX) are each of your handlers, such + // as EVT_MENU for menu events and the XXX inside + // is the parameters to the event macro - in the case + // of EVT_MENU the menu id and then the function to call. + // + // However, with wxEvtHandler::Connect you can avoid a + // global message map for your class and those annoying + // macros. You can also change the context in which + // the call the handler (more later). + // + // The downside is that due to the limitation that + // wxWidgets doesn't use templates in certain areas, + // You have to triple-cast the event function. + // + // There are five parameters to wxEvtHandler::Connect - + // + // The first is the id of the instance whose events + // you want to handle - i.e. a menu id for menus, + // a control id for controls (wxControl::GetId()) + // and so on. + // + // The second is the event id. This is the same + // as the message maps (EVT_MENU) except prefixed + // with "wx" (wxEVT_MENU). + // + // The third is the function handler for the event - + // You need to cast it to the specific event handler + // type, then to a wxEventFunction, then to a + // wxObjectEventFunction - I.E. + // (wxObjectEventFunction)(wxEventFunction) + // (wxCommandEventFunction) &MyFrame::MyHandler + // + // The fourth is an optional userdata param - + // this is of historical relevance only and is + // there only for backwards compatibility. + // + // The fifth is the context in which to call the + // handler - by default (this param is optional) + // this. For example in your event handler + // if you were to call "this->MyFunc()" + // it would literally do this->MyFunc. However, + // if you were to pass myHandler as the fifth + // parameter, for instance, you would _really_ + // be calling myHandler->MyFunc, even though + // the compiler doesn't really know it. + // + + // + // Menu events + // + this->Connect(wxID_EXIT, wxEVT_COMMAND_MENU_SELECTED, + (wxObjectEventFunction) (wxEventFunction) + (wxCommandEventFunction) &MyFrame::OnQuit); + + this->Connect(wxID_ABOUT, wxEVT_COMMAND_MENU_SELECTED, + (wxObjectEventFunction) (wxEventFunction) + (wxCommandEventFunction) &MyFrame::OnAbout); + + this->Connect(wxID_LOOP, wxEVT_COMMAND_MENU_SELECTED, + (wxObjectEventFunction) (wxEventFunction) + (wxCommandEventFunction) &MyFrame::OnLoop); + + this->Connect(wxID_OPENFILENEWPAGE, wxEVT_COMMAND_MENU_SELECTED, + (wxObjectEventFunction) (wxEventFunction) + (wxCommandEventFunction) &MyFrame::OnOpenFileNewPage); + + this->Connect(wxID_OPENFILESAMEPAGE, wxEVT_COMMAND_MENU_SELECTED, + (wxObjectEventFunction) (wxEventFunction) + (wxCommandEventFunction) &MyFrame::OnOpenFileSamePage); + + this->Connect(wxID_OPENURLNEWPAGE, wxEVT_COMMAND_MENU_SELECTED, + (wxObjectEventFunction) (wxEventFunction) + (wxCommandEventFunction) &MyFrame::OnOpenURLNewPage); + + this->Connect(wxID_OPENURLSAMEPAGE, wxEVT_COMMAND_MENU_SELECTED, + (wxObjectEventFunction) (wxEventFunction) + (wxCommandEventFunction) &MyFrame::OnOpenURLSamePage); + + this->Connect(wxID_CLOSECURRENTPAGE, wxEVT_COMMAND_MENU_SELECTED, + (wxObjectEventFunction) (wxEventFunction) + (wxCommandEventFunction) &MyFrame::OnCloseCurrentPage); + + this->Connect(wxID_PLAY, wxEVT_COMMAND_MENU_SELECTED, + (wxObjectEventFunction) (wxEventFunction) + (wxCommandEventFunction) &MyFrame::OnPlay); + + this->Connect(wxID_PAUSE, wxEVT_COMMAND_MENU_SELECTED, + (wxObjectEventFunction) (wxEventFunction) + (wxCommandEventFunction) &MyFrame::OnPause); + + this->Connect(wxID_STOP, wxEVT_COMMAND_MENU_SELECTED, + (wxObjectEventFunction) (wxEventFunction) + (wxCommandEventFunction) &MyFrame::OnStop); + + // + // Notebook events + // + this->Connect(wxID_NOTEBOOK, wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED, + (wxObjectEventFunction) (wxEventFunction) + (wxNotebookEventFunction) &MyFrame::OnPageChange); + + // + // End of Events + // + + // + // Create a timer to update our status bar + // + m_timer = new MyTimer(this); + m_timer->Start(100); } +// ---------------------------------------------------------------------------- +// MyFrame Destructor +// +// 1) Deletes child objects implicitly +// 2) Delete our timer explicitly +// ---------------------------------------------------------------------------- MyFrame::~MyFrame() { - if (m_timer) - delete m_timer; + delete m_timer; } -// event handlers +// ---------------------------------------------------------------------------- +// MyFrame::ResetStatus +// +// Here we just make a simple status string with some useful info about +// the media that we won't change later - such as the length of the media. +// +// We then append some other info that changes in MyTimer::Notify, then +// set the status bar to this text. +// +// In real applications, you'd want to find a better way to do this, +// such as static text controls (wxStaticText). +// +// We display info here in seconds (wxMediaCtrl uses milliseconds - that's why +// we divide by 1000). +// +// We also reset our loop counter here. +// ---------------------------------------------------------------------------- +void MyFrame::ResetStatus() +{ + wxMediaCtrl* currentMediaCtrl = GetCurrentMediaCtrl(); + + m_basestatus = wxString::Format(_T("Size(x,y):%i,%i ") + _T("Length(Seconds):%u Speed:%1.1fx"), + currentMediaCtrl->GetBestSize().x, + currentMediaCtrl->GetBestSize().y, + (unsigned)((currentMediaCtrl->Length() / 1000)), + currentMediaCtrl->GetPlaybackRate() + ); +} + +// ---------------------------------------------------------------------------- +// MyFrame::GetCurrentMediaCtrl +// +// Obtains the media control of the current page, or NULL if there are no +// pages open +// ---------------------------------------------------------------------------- +wxMediaCtrl* MyFrame::GetCurrentMediaCtrl() +{ + wxASSERT(m_notebook->GetCurrentPage() != NULL); + return ((MyNotebookPage*)m_notebook->GetCurrentPage())->m_mediactrl; +} +// ---------------------------------------------------------------------------- +// MyFrame::GetCurrentSlider +// +// Obtains the slider of the current page, or NULL if there are no +// pages open +// ---------------------------------------------------------------------------- +wxSlider* MyFrame::GetCurrentSlider() +{ + wxASSERT(m_notebook->GetCurrentPage() != NULL); + return ((MyNotebookPage*)m_notebook->GetCurrentPage())->m_slider; +} + +// ---------------------------------------------------------------------------- +// MyFrame::OnQuit +// +// Called from file->quit. +// Closes this application. +// ---------------------------------------------------------------------------- void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event)) { // true is to force the frame to close Close(true); } +// ---------------------------------------------------------------------------- +// MyFrame::OnAbout +// +// Called from help->about. +// Gets some info about this application. +// ---------------------------------------------------------------------------- void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event)) { wxString msg; @@ -330,74 +585,369 @@ void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event)) wxMessageBox(msg, _T("About wxMediaCtrl test"), wxOK | wxICON_INFORMATION, this); } +// ---------------------------------------------------------------------------- +// MyFrame::OnLoop +// +// Called from file->loop. +// Changes the state of whether we want to loop or not. +// ---------------------------------------------------------------------------- void MyFrame::OnLoop(wxCommandEvent& WXUNUSED(event)) { - m_bLoop = !m_bLoop; + if(!m_notebook->GetCurrentPage()) + { + wxMessageBox(wxT("No files are currently open!")); + return; + } + + ((MyNotebookPage*)m_notebook->GetCurrentPage())->m_bLoop = + !((MyNotebookPage*)m_notebook->GetCurrentPage())->m_bLoop; +} + +// ---------------------------------------------------------------------------- +// MyFrame::OnOpenFileSamePage +// +// Called from file->openfile. +// Opens and plays a media file in the current notebook page +// ---------------------------------------------------------------------------- +void MyFrame::OnOpenFileSamePage(wxCommandEvent& WXUNUSED(event)) +{ + OpenFile(false); +} + +// ---------------------------------------------------------------------------- +// MyFrame::OnOpenFileNewPage +// +// Called from file->openfileinnewpage. +// Opens and plays a media file in a new notebook page +// ---------------------------------------------------------------------------- +void MyFrame::OnOpenFileNewPage(wxCommandEvent& WXUNUSED(event)) +{ + OpenFile(true); } -void MyFrame::OnOpenFile(wxCommandEvent& WXUNUSED(event)) +// ---------------------------------------------------------------------------- +// MyFrame::OpenFile +// +// Code to actually open the media file +// +// 1) Create file dialog and ask the user for input file +// 2) If the user didn't want anything, break out +// 3) Create a new page if the user wanted one or there isn't a current page +// 4) Load the media +// 5) Play the media +// 6) Reset the text on the status bar +// 7) Set the slider of the current page to accurately reflect media length +// ---------------------------------------------------------------------------- +void MyFrame::OpenFile(bool bNewPage) { wxFileDialog fd(this); if(fd.ShowModal() == wxID_OK) { - if( !m_movie->Load(fd.GetPath()) ) + if(bNewPage || !m_notebook->GetCurrentPage()) + m_notebook->AddPage(new MyNotebookPage(m_notebook), fd.GetPath(), true); + + if( !GetCurrentMediaCtrl()->Load(fd.GetPath()) ) wxMessageBox(wxT("Couldn't load file!")); - if( !m_movie->Play() ) - wxMessageBox(wxT("Couldn't play movie!")); - + if( !GetCurrentMediaCtrl()->Play() ) + wxMessageBox(wxT("Couldn't play movie!")); + ResetStatus(); + + GetCurrentSlider()->SetRange(0, + (int)(GetCurrentMediaCtrl()->Length() / 1000)); + } } -#include "wx/textdlg.h" +// ---------------------------------------------------------------------------- +// MyFrame::OnOpenURLSamePage +// +// Called from file->openurl. +// Opens and plays a media file from a URL in the current notebook page +// ---------------------------------------------------------------------------- +void MyFrame::OnOpenURLSamePage(wxCommandEvent& WXUNUSED(event)) +{ + OpenURL(false); +} -void MyFrame::OnOpenURL(wxCommandEvent& WXUNUSED(event)) +// ---------------------------------------------------------------------------- +// MyFrame::OnOpenURLNewPage +// +// Called from file->openurlinnewpage. +// Opens and plays a media file from a URL in a new notebook page +// ---------------------------------------------------------------------------- +void MyFrame::OnOpenURLNewPage(wxCommandEvent& WXUNUSED(event)) +{ + OpenURL(true); +} + +// ---------------------------------------------------------------------------- +// MyFrame::OpenURL +// +// Code to actually open the media file from a URL +// +// 1) Create text input dialog and ask the user for an input URL +// 2) If the user didn't want anything, break out +// 3) Create a new page if the user wanted one or there isn't a current page +// 4) Load the media +// 5) Play the media +// 6) Reset the text on the status bar +// 7) Set the slider of the current page to accurately reflect media length +// ---------------------------------------------------------------------------- +void MyFrame::OpenURL(bool bNewPage) { - wxString theURL = wxGetTextFromUser(wxT("Enter the URL that has the movie to play")); + wxString theURL = wxGetTextFromUser(wxT("Enter the URL that has the movie to play")); if(!theURL.empty()) { - if( !m_movie->Load(wxURI(theURL)) ) + if(bNewPage || !m_notebook->GetCurrentPage()) + m_notebook->AddPage(new MyNotebookPage(m_notebook), theURL, true); + + if( !GetCurrentMediaCtrl()->Load(wxURI(theURL)) ) wxMessageBox(wxT("Couldn't load URL!")); - if( !m_movie->Play() ) - wxMessageBox(wxT("Couldn't play movie!")); + if( !GetCurrentMediaCtrl()->Play() ) + wxMessageBox(wxT("Couldn't play movie!")); ResetStatus(); + + GetCurrentSlider()->SetRange(0, + (int)(GetCurrentMediaCtrl()->Length() / 1000)); } } +// ---------------------------------------------------------------------------- +// MyFrame::OnCloseCurrentPage +// +// Called when the user wants to close the current notebook page +// +// 1) Get the current page number (wxControl::GetSelection) +// 2) If there is no current page, break out +// 3) Delete the current page +// ---------------------------------------------------------------------------- +void MyFrame::OnCloseCurrentPage(wxCommandEvent& WXUNUSED(event)) +{ + int sel = m_notebook->GetSelection(); + + if (sel != wxNOT_FOUND) + { + m_notebook->DeletePage(sel); + } +} + +// ---------------------------------------------------------------------------- +// MyFrame::OnPlay +// +// Called from file->play. +// Resumes the media if it is paused or stopped. +// ---------------------------------------------------------------------------- void MyFrame::OnPlay(wxCommandEvent& WXUNUSED(event)) { - if( !m_movie->Play() ) + if(!m_notebook->GetCurrentPage()) + { + wxMessageBox(wxT("No files are currently open!")); + return; + } + + if( !GetCurrentMediaCtrl()->Play() ) wxMessageBox(wxT("Couldn't play movie!")); } +// ---------------------------------------------------------------------------- +// MyFrame::OnPause +// +// Called from file->pause. +// Pauses the media in-place. +// ---------------------------------------------------------------------------- void MyFrame::OnPause(wxCommandEvent& WXUNUSED(event)) { - if( !m_movie->Pause() ) + if(!m_notebook->GetCurrentPage()) + { + wxMessageBox(wxT("No files are currently open!")); + return; + } + + if( !GetCurrentMediaCtrl()->Pause() ) wxMessageBox(wxT("Couldn't pause movie!")); } +// ---------------------------------------------------------------------------- +// MyFrame::OnStop +// +// Called from file->stop. +// Where it stops depends on whether you can seek in the +// media control or not - if you can it stops and seeks to the beginning, +// otherwise it will appear to be at the end - but it will start over again +// when Play() is called +// ---------------------------------------------------------------------------- void MyFrame::OnStop(wxCommandEvent& WXUNUSED(event)) { - if( !m_movie->Stop() ) + if(!m_notebook->GetCurrentPage()) + { + wxMessageBox(wxT("No files are currently open!")); + return; + } + + if( !GetCurrentMediaCtrl()->Stop() ) wxMessageBox(wxT("Couldn't stop movie!")); } -void MyFrame::OnSeek(wxCommandEvent& WXUNUSED(event)) +// ---------------------------------------------------------------------------- +// MyFrame::OnCloseCurrentPage +// +// Called when the user wants to closes the current notebook page +// ---------------------------------------------------------------------------- + +void MyFrame::OnPageChange(wxNotebookEvent& WXUNUSED(event)) +{ + ResetStatus(); +} + +// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// +// MyTimer +// +// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +// ---------------------------------------------------------------------------- +// MyTimer::Notify +// +// 1) Update our slider with the position were are in in the media +// 2) Update our status bar with the base text from MyFrame::ResetStatus, +// append some non-static (changing) info to it, then set the +// status bar text to that result +// ---------------------------------------------------------------------------- +void MyTimer::Notify() +{ + if (!m_frame->m_notebook->GetCurrentPage()) return; + wxMediaCtrl* m_mediactrl = ((MyNotebookPage*)m_frame->m_notebook->GetCurrentPage())->m_mediactrl; + wxSlider* m_slider = ((MyNotebookPage*)m_frame->m_notebook->GetCurrentPage())->m_slider; + if (!m_mediactrl) return; + + long lPosition = (long)( m_mediactrl->Tell() / 1000 ); + m_slider->SetValue(lPosition); + +#if wxUSE_STATUSBAR + m_frame->SetStatusText(wxString::Format( + _T("%s Pos:%u State:%s Loops:%i"), + m_frame->m_basestatus.c_str(), + (unsigned int)lPosition, + wxGetMediaStateText(m_mediactrl->GetState()), + ((MyNotebookPage*)m_frame->m_notebook->GetCurrentPage())->m_nLoops + + ) + ); +#endif + +} + + +// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// +// MyNotebookPage +// +// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +// ---------------------------------------------------------------------------- +// MyNotebookPage Constructor +// +// Creates a media control and slider and adds it to this panel, +// along with some sizers for positioning +// ---------------------------------------------------------------------------- + +MyNotebookPage::MyNotebookPage(wxNotebook* theBook) : + wxPanel(theBook, wxID_ANY), m_nLoops(0), m_bLoop(false) { - if( !m_movie->SetPosition( m_slider->GetValue() * 1000 ) ) + // + // Create and attach the first/main sizer + // + wxBoxSizer* vertsizer = new wxBoxSizer(wxVERTICAL); + this->SetSizer(vertsizer); + this->SetAutoLayout(true); + + // + // Create our media control + // + m_mediactrl = new wxMediaCtrl(); + + // Make sure creation was successful + bool bOK = m_mediactrl->Create(this, wxID_MEDIACTRL); + wxASSERT_MSG(bOK, wxT("Could not create media control!")); + + vertsizer->Add(m_mediactrl, 0, wxALIGN_CENTER_HORIZONTAL|wxALL, 5); + + // + // Create our slider + // + m_slider = new wxSlider(this, wxID_SLIDER, 0, //init + 0, //start + 0, //end + wxDefaultPosition, wxDefaultSize, + wxSL_HORIZONTAL ); + vertsizer->Add(m_slider, 0, wxALIGN_CENTER_HORIZONTAL|wxALL|wxEXPAND , 5); + + + // + // Create the second sizer which will position things + // vertically - + // + // -------Menu---------- + // [m_mediactrl] + // + // [m_slider] + // + wxBoxSizer* horzsizer = new wxBoxSizer(wxHORIZONTAL); + vertsizer->Add(horzsizer, 0, wxALIGN_CENTER_HORIZONTAL|wxALL, 5); + + // + // Slider events + // + this->Connect(wxID_SLIDER, wxEVT_COMMAND_SLIDER_UPDATED, + (wxObjectEventFunction) (wxEventFunction) + (wxCommandEventFunction) &MyNotebookPage::OnSeek); + + // + // Media Control events + // + this->Connect(wxID_MEDIACTRL, wxEVT_MEDIA_FINISHED, + (wxObjectEventFunction) (wxEventFunction) + (wxMediaEventFunction) &MyNotebookPage::OnMediaFinished); +} + +// ---------------------------------------------------------------------------- +// MyNotebook::OnSeek +// +// Called from file->seek. +// Called when the user moves the slider - +// seeks to a position within the media +// ---------------------------------------------------------------------------- +void MyNotebookPage::OnSeek(wxCommandEvent& WXUNUSED(event)) +{ + if( m_mediactrl->Seek( + m_slider->GetValue() * 1000 + ) == wxInvalidOffset ) wxMessageBox(wxT("Couldn't seek in movie!")); } -void MyFrame::OnMediaFinished(wxMediaEvent& WXUNUSED(event)) +// ---------------------------------------------------------------------------- +// OnMediaFinished +// +// Called when the media stops playing. +// Here we loop it if the user wants to (has been selected from file menu) +// ---------------------------------------------------------------------------- +void MyNotebookPage::OnMediaFinished(wxMediaEvent& WXUNUSED(event)) { if(m_bLoop) { - if ( !m_movie->SetPosition(0) || !m_movie->Play() ) - wxMessageBox(wxT("Couldn't seek or play to loop movie!")); + if ( !m_mediactrl->Play() ) + wxMessageBox(wxT("Couldn't loop movie!")); + else + ++m_nLoops; } -} \ No newline at end of file +} + +// +// End of MediaPlayer sample +//