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