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