MythTV  master
musiccommon.cpp
Go to the documentation of this file.
1 // ANSI C includes
2 #include <cstdlib>
3 
4 // C++ includes
5 #include <iostream>
6 using namespace std;
7 
8 // Qt includes
9 #include <QApplication>
10 #include <QLocale>
11 
12 // mythtv
13 #include <mythuitextedit.h>
14 #include <mythuistatetype.h>
15 #include <mythuiprogressbar.h>
16 #include <mythuibutton.h>
17 #include <mythuiimage.h>
18 #include <mythdialogbox.h>
19 #include <mythuibuttonlist.h>
20 #include <mythuibuttontree.h>
21 #include <mythuicheckbox.h>
22 #include <mythuivideo.h>
23 #include <mythuitext.h>
24 #include <audiooutput.h>
25 #include <compat.h>
26 #include <lcddevice.h>
27 #include <musicmetadata.h>
28 
29 // MythMusic includes
30 #include "musicdata.h"
31 #include "constants.h"
32 #include "decoder.h"
33 #include "mainvisual.h"
34 #include "smartplaylist.h"
35 #include "playlistcontainer.h"
36 #include "search.h"
37 #include "editmetadata.h"
38 #include "playlist.h"
39 
40 #include "musiccommon.h"
41 #include "playlistview.h"
42 #include "playlisteditorview.h"
43 #include "streamview.h"
44 #include "visualizerview.h"
45 #include "searchview.h"
46 #include "lyricsview.h"
47 
49  const QString &name)
50  : MythScreenType(parent, name),
51  m_parentScreen(parentScreen),
52  m_currentView()
53 {
54  m_cycleVisualizer = gCoreContext->GetBoolSetting("VisualCycleOnSongChange", false);
55 
56  if (LCD *lcd = LCD::Get())
57  {
58  lcd->switchToTime();
59  lcd->setFunctionLEDs(FUNC_MUSIC, true);
60  }
61 }
62 
64 {
65  gPlayer->removeListener(this);
66 
67  if (m_mainvisual)
68  {
70  delete m_mainvisual;
71  m_mainvisual = nullptr;
72  }
73 
74  if (LCD *lcd = LCD::Get())
75  {
76  lcd->switchToTime();
77  lcd->setFunctionLEDs(FUNC_MUSIC, false);
78  }
79 }
80 
82 {
83  bool err = false;
84  UIUtilW::Assign(this, m_timeText, "time", &err);
85  UIUtilW::Assign(this, m_infoText, "info", &err);
86  UIUtilW::Assign(this, m_visualText, "visualizername", &err);
87  UIUtilW::Assign(this, m_noTracksText, "notracks", &err);
88 
89  UIUtilW::Assign(this, m_shuffleState, "shufflestate", &err);
90  UIUtilW::Assign(this, m_repeatState, "repeatstate", &err);
91  UIUtilW::Assign(this, m_movingTracksState, "movingtracksstate", &err);
92 
93  UIUtilW::Assign(this, m_ratingState, "ratingstate", &err);
94 
95  UIUtilW::Assign(this, m_trackProgress, "progress", &err);
96  UIUtilW::Assign(this, m_trackProgressText, "trackprogress", &err);
97  UIUtilW::Assign(this, m_trackSpeedText, "trackspeed", &err);
98  UIUtilW::Assign(this, m_trackState, "trackstate", &err);
99 
100  UIUtilW::Assign(this, m_volumeText, "volume", &err);
101  UIUtilW::Assign(this, m_muteState, "mutestate", &err);
102 
103  UIUtilW::Assign(this, m_playlistProgress, "playlistprogress", &err);
104 
105  UIUtilW::Assign(this, m_prevButton, "prev", &err);
106  UIUtilW::Assign(this, m_rewButton, "rew", &err);
107  UIUtilW::Assign(this, m_pauseButton, "pause", &err);
108  UIUtilW::Assign(this, m_playButton, "play", &err);
109  UIUtilW::Assign(this, m_stopButton, "stop", &err);
110  UIUtilW::Assign(this, m_ffButton, "ff", &err);
111  UIUtilW::Assign(this, m_nextButton, "next", &err);
112 
113  UIUtilW::Assign(this, m_coverartImage, "coverart", &err);
114 
115  UIUtilW::Assign(this, m_currentPlaylist, "currentplaylist", &err);
116  UIUtilW::Assign(this, m_playedTracksList, "playedtrackslist", &err);
117 
118  UIUtilW::Assign(this, m_visualizerVideo, "visualizer", &err);
119 
120  if (m_prevButton)
121  connect(m_prevButton, SIGNAL(Clicked()), this, SLOT(previous()));
122 
123  if (m_rewButton)
124  connect(m_rewButton, SIGNAL(Clicked()), this, SLOT(seekback()));
125 
126  if (m_pauseButton)
127  {
128  m_pauseButton->SetLockable(true);
129  connect(m_pauseButton, SIGNAL(Clicked()), this, SLOT(pause()));
130  }
131 
132  if (m_playButton)
133  {
134  m_playButton->SetLockable(true);
135  connect(m_playButton, SIGNAL(Clicked()), this, SLOT(play()));
136  }
137 
138  if (m_stopButton)
139  {
140  m_stopButton->SetLockable(true);
141  connect(m_stopButton, SIGNAL(Clicked()), this, SLOT(stop()));
142  }
143 
144  if (m_ffButton)
145  connect(m_ffButton, SIGNAL(Clicked()), this, SLOT(seekforward()));
146 
147  if (m_nextButton)
148  connect(m_nextButton, SIGNAL(Clicked()), this, SLOT(next()));
149 
150  if (m_currentPlaylist)
151  {
152  connect(m_currentPlaylist, SIGNAL(itemClicked(MythUIButtonListItem*)),
154  connect(m_currentPlaylist, SIGNAL(itemVisible(MythUIButtonListItem*)),
156 
157  m_currentPlaylist->SetSearchFields("**search**");
158  }
159 
160  init();
161 
162  return err;
163 }
164 
166 {
167  gPlayer->addListener(this);
168 
169  if (startPlayback)
170  {
171  if (!gPlayer->isPlaying())
172  {
173  if (m_currentView == MV_RADIO)
177  else
179 
181  }
182  else
183  {
184  // if we are playing but we are switching to a view from a different playmode
185  // we need to restart playback in the new mode
187  {
188  // these views can be used in both play modes
189  }
191  {
192  gPlayer->stop(true);
193 
196  else
198 
200  }
202  {
203  gPlayer->stop(true);
206  }
207  }
208  }
209 
211 
213  if (curMeta)
214  updateTrackInfo(curMeta);
215 
217 
218  if (m_currentPlaylist)
220 
221  if (m_visualizerVideo)
222  {
224 
226 
227  m_fullscreenBlank = false;
228 
229  m_randomVisualizer = gCoreContext->GetBoolSetting("VisualRandomize", false);
230 
232 
233  // sanity check
234  if (m_currentVisual >= static_cast<uint>(m_visualModes.count()))
235  {
236  LOG(VB_GENERAL, LOG_ERR, QString("MusicCommon: Got a bad saved visualizer: %1").arg(m_currentVisual));
237  m_currentVisual = 0;
238  }
239 
241 
242  if (gPlayer->isPlaying())
243  startVisualizer();
244  }
245 
246  m_controlVolume = gCoreContext->GetBoolSetting("MythControlsVolume", false);
247  updateVolume();
248 
251 
252  if (m_stopButton)
254  if (m_playButton)
256  if (m_pauseButton)
258  if (m_trackState)
259  {
260  if (gPlayer->isPlaying())
261  m_trackState->DisplayState("playing");
262  else if (gPlayer->isPaused())
263  m_trackState->DisplayState("paused");
264  else
265  m_trackState->DisplayState("stopped");
266 
267  }
268 
271 
275 
276  if (m_playlistProgress)
277  {
280  }
281 
283 
285 }
286 
288 {
289  if (m_repeatState)
290  {
291  switch (gPlayer->getRepeatMode())
292  {
294  m_repeatState->DisplayState("off");
295  if (class LCD *lcd = LCD::Get())
296  lcd->setMusicRepeat (LCD::MUSIC_REPEAT_NONE);
297  break;
299  m_repeatState->DisplayState("track");
300  if (class LCD *lcd = LCD::Get())
301  lcd->setMusicRepeat (LCD::MUSIC_REPEAT_TRACK);
302  break;
304  m_repeatState->DisplayState("all");
305  if (class LCD *lcd = LCD::Get())
306  lcd->setMusicRepeat (LCD::MUSIC_REPEAT_ALL);
307  break;
308  default:
309  m_repeatState->DisplayState("off");
310  if (class LCD *lcd = LCD::Get())
311  lcd->setMusicRepeat (LCD::MUSIC_REPEAT_NONE);
312  break;
313  }
314  }
315 
316  // need this to update the next track info
318  if (curMeta)
319  updateTrackInfo(curMeta);
320 }
321 
322 void MusicCommon::updateShuffleMode(bool updateUIList)
323 {
324  if (m_shuffleState)
325  {
326  switch (gPlayer->getShuffleMode())
327  {
330  if (class LCD *lcd = LCD::Get())
331  lcd->setMusicShuffle(LCD::MUSIC_SHUFFLE_NONE);
332  break;
334  m_shuffleState->DisplayState("random");
335  if (class LCD *lcd = LCD::Get())
336  lcd->setMusicShuffle(LCD::MUSIC_SHUFFLE_RAND);
337  break;
339  m_shuffleState->DisplayState("intelligent");
340  if (class LCD *lcd = LCD::Get())
341  lcd->setMusicShuffle(LCD::MUSIC_SHUFFLE_SMART);
342  break;
344  m_shuffleState->DisplayState("album");
345  if (class LCD *lcd = LCD::Get())
346  lcd->setMusicShuffle(LCD::MUSIC_SHUFFLE_ALBUM);
347  break;
349  m_shuffleState->DisplayState("artist");
350  if (class LCD *lcd = LCD::Get())
351  lcd->setMusicShuffle(LCD::MUSIC_SHUFFLE_ARTIST);
352  break;
353  default:
355  if (class LCD *lcd = LCD::Get())
356  lcd->setMusicShuffle(LCD::MUSIC_SHUFFLE_NONE);
357  break;
358  }
359  }
360 
361  if (updateUIList)
362  {
364 
369 
370  // need this to update the next track info
372  if (curMeta)
373  updateTrackInfo(curMeta);
374  }
375 }
376 
378 {
379  // can we switch to this view from the current view?
380  switch (m_currentView)
381  {
382  case MV_PLAYLIST:
383  {
384  if (view != MV_PLAYLISTEDITORTREE && view != MV_PLAYLISTEDITORGALLERY &&
385  view != MV_SEARCH && view != MV_VISUALIZER && view != MV_LYRICS)
386  return;
387  break;
388  }
389 
391  {
392  if (view != MV_PLAYLISTEDITORGALLERY && view != MV_SEARCH && view != MV_VISUALIZER && view != MV_LYRICS)
393  return;
394  break;
395  }
396 
398  {
399  if (view != MV_PLAYLISTEDITORTREE && view != MV_SEARCH && view != MV_VISUALIZER && view != MV_LYRICS)
400  return;
401  break;
402  }
403 
404  case MV_SEARCH:
405  {
406  if (view != MV_VISUALIZER && view != MV_LYRICS)
407  return;
408  break;
409  }
410 
411  case MV_VISUALIZER:
412  {
413  return;
414  }
415 
416  case MV_LYRICS:
417  {
418  if (view != MV_VISUALIZER && view != MV_SEARCH)
419  return;
420  break;
421  }
422 
423  case MV_RADIO:
424  {
425  if (view != MV_VISUALIZER && view != MV_LYRICS)
426  return;
427  break;
428  }
429 
430  default:
431  return;
432  }
433 
435 
436  stopVisualizer();
437 
438  if (m_mainvisual)
439  {
440  delete m_mainvisual;
441  m_mainvisual = nullptr;
442  }
443 
444  gPlayer->removeListener(this);
445  gPlayer->setAllowRestorePos(false);
446 
447  switch (view)
448  {
449  case MV_PLAYLIST:
450  {
451  auto *plview = new PlaylistView(mainStack, this);
452 
453  if (plview->Create())
454  {
455  mainStack->AddScreen(plview);
456  connect(plview, SIGNAL(Exiting()), this, SLOT(viewExited()));
457  }
458  else
459  delete plview;
460 
461  break;
462  }
463 
465  {
466  // if we are switching playlist editor views save and restore
467  // the current position in the tree
468  bool restorePos = (m_currentView == MV_PLAYLISTEDITORGALLERY);
469  auto *oldView = dynamic_cast<PlaylistEditorView *>(this);
470  if (oldView)
471  oldView->saveTreePosition();
472 
473  MythScreenType *parentScreen = (oldView != nullptr ? m_parentScreen : this);
474 
475  auto *pleview = new PlaylistEditorView(mainStack, parentScreen, "tree", restorePos);
476 
477  if (pleview->Create())
478  {
479  mainStack->AddScreen(pleview);
480  connect(pleview, SIGNAL(Exiting()), this, SLOT(viewExited()));
481  }
482  else
483  delete pleview;
484 
485  if (oldView)
486  {
487  disconnect(this , SIGNAL(Exiting()));
488  Close();
489  }
490 
491  break;
492  }
493 
495  {
496  // if we are switching playlist editor views save and restore
497  // the current position in the tree
498  bool restorePos = (m_currentView == MV_PLAYLISTEDITORTREE);
499  auto *oldView = dynamic_cast<PlaylistEditorView *>(this);
500  if (oldView)
501  oldView->saveTreePosition();
502 
503  MythScreenType *parentScreen = (oldView != nullptr ? m_parentScreen : this);
504 
505  auto *pleview = new PlaylistEditorView(mainStack, parentScreen, "gallery", restorePos);
506 
507  if (pleview->Create())
508  {
509  mainStack->AddScreen(pleview);
510  connect(pleview, SIGNAL(Exiting()), this, SLOT(viewExited()));
511  }
512  else
513  delete pleview;
514 
515  if (oldView)
516  {
517  disconnect(this , SIGNAL(Exiting()));
518  Close();
519  }
520 
521  break;
522  }
523 
524  case MV_SEARCH:
525  {
526  auto *sview = new SearchView(mainStack, this);
527 
528  if (sview->Create())
529  {
530  mainStack->AddScreen(sview);
531  connect(sview, SIGNAL(Exiting()), this, SLOT(viewExited()));
532  }
533  else
534  delete sview;
535 
536  break;
537  }
538 
539  case MV_VISUALIZER:
540  {
541  auto *vview = new VisualizerView(mainStack, this);
542 
543  if (vview->Create())
544  {
545  mainStack->AddScreen(vview);
546  connect(vview, SIGNAL(Exiting()), this, SLOT(viewExited()));
547  }
548  else
549  delete vview;
550 
551  break;
552  }
553 
554  case MV_LYRICS:
555  {
556  auto *lview = new LyricsView(mainStack, this);
557 
558  if (lview->Create())
559  {
560  mainStack->AddScreen(lview);
561  connect(lview, SIGNAL(Exiting()), this, SLOT(viewExited()));
562  }
563  else
564  delete lview;
565 
566  break;
567  }
568 
569  default:
570  break;
571  }
572 
574 }
575 
577 {
578  init(false);
579 }
580 
581 bool MusicCommon::keyPressEvent(QKeyEvent *e)
582 {
583  bool handled = false;
584 
585  // if there is a pending jump point pass the key press to the default handler
586  if (GetMythMainWindow()->IsExitingToMain())
587  {
589 
590  // do we need to stop playing?
591  if (gPlayer->isPlaying() && gCoreContext->GetSetting("MusicJumpPointAction", "stop") == "stop")
592  gPlayer->stop(true);
593 
595  }
596 
597  QStringList actions;
598  handled = GetMythMainWindow()->TranslateKeyPress("Music", e, actions, true);
599 
600  for (int i = 0; i < actions.size() && !handled; i++)
601  {
602  QString action = actions[i];
603  handled = true;
604 
605  // if we are currently moving an item,
606  // we only accept UP/DOWN/SELECT/ESCAPE
608  {
610  if (!item)
611  return false;
612 
613  if (action == "SELECT" || action == "ESCAPE")
614  {
615  m_movingTrack = false;
616  item->DisplayState("off", "movestate");
617  }
618  else if (action == "UP")
619  {
621  item->MoveUpDown(true);
628  }
629  else if (action == "DOWN")
630  {
632  item->MoveUpDown(false);
639  }
640 
641  return true;
642  }
643 
644  if (action == "ESCAPE")
645  {
646  // if we was started from another music view screen return to it
647  if (m_parentScreen)
648  {
649  handled = false;
650  }
651  else
652  {
653  // this is the top music view screen so prompt to continue playing
654  QString exit_action = gCoreContext->GetSetting("MusicExitAction", "prompt");
655 
656  if (!gPlayer->isPlaying())
657  {
659  stopAll();
660  Close();
661  }
662  else
663  {
664  if (exit_action == "stop")
665  {
667  stopAll();
668  Close();
669  }
670  else if (exit_action == "play")
671  Close();
672  else
673  showExitMenu();
674  }
675  }
676  }
677  else if (action == "THMBUP")
678  changeRating(true);
679  else if (action == "THMBDOWN")
680  changeRating(false);
681  else if (action == "NEXTTRACK")
682  {
683  if (m_nextButton)
684  m_nextButton->Push();
685  else
686  next();
687  }
688  else if (action == "PREVTRACK")
689  {
690  if (m_prevButton)
691  m_prevButton->Push();
692  else
693  previous();
694  }
695  else if (action == "FFWD")
696  {
698  {
699  if (m_ffButton)
700  m_ffButton->Push();
701  else
702  seekforward();
703  }
704  }
705  else if (action == "RWND")
706  {
708  {
709  if (m_rewButton)
710  m_rewButton->Push();
711  else
712  seekback();
713  }
714  }
715  else if (action == "PAUSE")
716  {
718  {
719  // ignore if we are already playing a radio stream
720  }
721  else if (gPlayer->isPlaying() || (gPlayer->getOutput() && gPlayer->getOutput()->IsPaused()))
722  {
723  // if we are playing or are paused PAUSE will toggle the pause state
724  if (m_pauseButton)
725  m_pauseButton->Push();
726  else
727  pause();
728  }
729  else
730  {
731  // not playing or paused so PAUSE acts the same as PLAY
732  if (m_playButton)
733  m_playButton->Push();
734  else
735  play();
736  }
737  }
738  else if (action == "PLAY")
739  {
740  if (m_playButton)
741  m_playButton->Push();
742  else
743  play();
744  }
745  else if (action == "STOP")
746  {
747  if (m_stopButton)
748  m_stopButton->Push();
749  else
750  stop();
751  m_currentTime = 0;
752  }
753  else if (action == "CYCLEVIS")
754  cycleVisualizer();
755  else if (action == "BLANKSCR")
756  {
757  // change to the blank visualizer
758  if (m_mainvisual)
759  switchVisualizer("Blank");
760 
761  // switch to the full screen visualiser view
764  }
765  else if (action == "VOLUMEDOWN")
766  changeVolume(false);
767  else if (action == "VOLUMEUP")
768  changeVolume(true);
769  else if (action == "SPEEDDOWN")
770  changeSpeed(false);
771  else if (action == "SPEEDUP")
772  changeSpeed(true);
773  else if (action == "MUTE")
774  toggleMute();
775  else if (action == "TOGGLEUPMIX")
776  toggleUpmix();
777  else if (action == "INFO" || action == "EDIT")
778  {
780  {
782  {
783  auto *mdata = m_currentPlaylist->GetItemCurrent()->GetData().value<MusicMetadata*>();
784  if (mdata)
785  {
786  if (action == "INFO")
787  showTrackInfo(mdata);
788  else
789  editTrackInfo(mdata);
790  }
791  }
792  }
793  else
794  {
795  if (action == "INFO")
797  else
799  }
800  }
801  else if (action == "DELETE" && m_currentPlaylist && GetFocusWidget() == m_currentPlaylist)
802  {
804  if (item)
805  {
806  auto *mdata = item->GetData().value<MusicMetadata*>();
807  if (mdata)
808  gPlayer->removeTrack(mdata->ID());
809  }
810  }
811  else if (action == "MENU")
812  ShowMenu();
813  else if (action == "REFRESH")
814  {
815  if (m_currentPlaylist)
817  }
818  else if (action == "MARK")
819  {
820  if (!m_moveTrackMode)
821  {
822  m_moveTrackMode = true;
823  m_movingTrack = false;
824 
827  }
828  else
829  {
830  m_moveTrackMode = false;
831 
833  {
835  if (item)
836  item->DisplayState("off", "movestate");
837 
838  m_movingTrack = false;
839  }
840 
843  }
844  }
845  else if (action == "SWITCHTOPLAYLIST" && m_currentView != MV_PLAYLIST)
847  else if (action == "SWITCHTOPLAYLISTEDITORTREE" && m_currentView != MV_PLAYLISTEDITORTREE)
849  else if (action == "SWITCHTOPLAYLISTEDITORGALLERY" && m_currentView != MV_PLAYLISTEDITORGALLERY)
851  else if (action == "SWITCHTOSEARCH" && m_currentView != MV_SEARCH)
853  else if (action == "SWITCHTOVISUALISER" && m_currentView != MV_VISUALIZER)
855  else if (action == "SWITCHTORADIO" && m_currentView != MV_RADIO)
857  else if (action == "TOGGLESHUFFLE")
858  {
860  updateShuffleMode(true);
861  }
862  else if (action == "TOGGLEREPEAT")
863  {
866  }
867  else
868  handled = false;
869  }
870 
871  if (!handled && MythScreenType::keyPressEvent(e))
872  handled = true;
873  return handled;
874 }
875 
877 {
879  {
880  if (up)
881  gPlayer->incVolume();
882  else
883  gPlayer->decVolume();
884  showVolume();
885  }
886 }
887 
889 {
891  {
892  if (up)
893  gPlayer->incSpeed();
894  else
895  gPlayer->decSpeed();
896  showSpeed(true);
897  }
898 }
899 
901 {
902  if (m_controlVolume)
903  {
904  gPlayer->toggleMute();
905  showVolume();
906  }
907 }
908 
910 {
911  if (gPlayer->getOutput())
913 }
914 
916 {
917  if (!m_trackProgress)
918  return;
919 
921  {
922  // radio mode so show the buffer fill level since we don't know the track length
923  int available = 0;
924  int maxSize = 0;
925  gPlayer->getBufferStatus(&available, &maxSize);
926 
927  if (m_infoText)
928  {
929  QString status = QString("%1%").arg((int)(100.0 / ((double)maxSize / (double)available)));
930  m_infoText->SetText(status);
931  }
932 
933  if (m_trackProgress)
934  {
935  m_trackProgress->SetTotal(maxSize);
936  m_trackProgress->SetUsed(available);
937  }
938  }
939  else
940  {
941  // show the track played time
942  int percentplayed = 1;
943  if (m_maxTime)
944  percentplayed = (int)(((double)m_currentTime / (double)m_maxTime) * 100);
946  m_trackProgress->SetUsed(percentplayed);
947  }
948 }
949 
951 {
952  MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
953 
954  auto *vol = new MythMusicVolumeDialog(popupStack, "volumepopup");
955 
956  if (!vol->Create())
957  {
958  delete vol;
959  return;
960  }
961 
962  popupStack->AddScreen(vol);
963 }
964 
966 {
967  (void) show;
968 }
969 
970 void MusicCommon::switchVisualizer(const QString &visual)
971 {
972  switchVisualizer(m_visualModes.indexOf(visual));
973 }
974 
976 {
977  if (!m_mainvisual)
978  return;
979 
980  if (visual < 0 || visual > m_visualModes.count() - 1)
981  visual = 0;
982 
983  m_currentVisual = visual;
984 
986 
987  if (m_visualText)
989 }
990 
992 {
993  if (!m_mainvisual)
994  return;
995 
996  // Only change the visualizer if there is more than 1 visualizer
997  // and the user currently has a visualizer active
998  if (m_visualModes.count() > 1)
999  {
1000  if (m_randomVisualizer)
1001  {
1002  unsigned int next_visualizer = 0;
1003 
1004  //Find a visual thats not like the previous visual
1005  do
1006  next_visualizer = random() % m_visualModes.count();
1007  while (next_visualizer == m_currentVisual);
1008  m_currentVisual = next_visualizer;
1009  }
1010  else
1011  {
1012  //Change to the next selected visual
1013  m_currentVisual = (m_currentVisual + 1) % m_visualModes.count();
1014  }
1015 
1016  //Change to the new visualizer
1018  }
1019 }
1020 
1022 {
1024  return;
1025 
1027 }
1028 
1030 {
1032  return;
1033 
1035 }
1036 
1038 {
1039  LCD *lcd = LCD::Get();
1040  if (!lcd || !mdata)
1041  return;
1042 
1043  // Set the Artist and Tract on the LCD
1044  lcd->switchToMusic(mdata->Artist(),
1045  mdata->Album(),
1046  mdata->Title());
1047 }
1048 
1050 {
1051  if (LCD *lcd = LCD::Get())
1052  {
1053  lcd->switchToTime();
1054  }
1055 
1056  stopVisualizer();
1057 
1058  gPlayer->stop(true);
1059 }
1060 
1062 {
1063  gPlayer->play();
1064 }
1065 
1067 {
1068  gPlayer->pause();
1069 }
1070 
1072 {
1073  gPlayer->stop();
1074 
1075  QString time_string = getTimeString(m_maxTime, 0);
1076 
1077  if (m_timeText)
1078  m_timeText->SetText(time_string);
1079  if (m_infoText)
1080  m_infoText->Reset();
1081 }
1082 
1084 {
1085  if (m_cycleVisualizer)
1086  cycleVisualizer();
1087 
1088 
1089  gPlayer->next();
1090 }
1091 
1093 {
1094  if (m_cycleVisualizer)
1095  cycleVisualizer();
1096 
1097  gPlayer->previous();
1098 }
1099 
1101 {
1102  int nextTime = m_currentTime + 5;
1103  if (nextTime > m_maxTime)
1104  nextTime = m_maxTime;
1105  seek(nextTime);
1106 }
1107 
1109 {
1110  int nextTime = m_currentTime - 5;
1111  if (nextTime < 0)
1112  nextTime = 0;
1113  seek(nextTime);
1114 }
1115 
1116 void MusicCommon::seek(int pos)
1117 {
1118  if (gPlayer->getOutput())
1119  {
1120  if (gPlayer->getDecoder() && gPlayer->getDecoder()->isRunning())
1121  {
1122  gPlayer->getDecoder()->lock();
1123  gPlayer->getDecoder()->seek(pos);
1124 
1125  if (m_mainvisual)
1126  {
1127  m_mainvisual->mutex()->lock();
1128  m_mainvisual->prepare();
1129  m_mainvisual->mutex()->unlock();
1130  }
1131 
1132  gPlayer->getDecoder()->unlock();
1133  }
1134 
1135  gPlayer->getOutput()->SetTimecode(pos*1000);
1136 
1137  if (!gPlayer->isPlaying())
1138  {
1139  m_currentTime = pos;
1140  if (m_timeText)
1142 
1144 
1145  if (LCD *lcd = LCD::Get())
1146  {
1147  float percent_heard = m_maxTime <= 0 ? 0.0F : ((float)pos /
1148  (float)m_maxTime);
1149 
1150  QString lcd_time_string = getTimeString(pos, m_maxTime);
1151 
1152  // if the string is longer than the LCD width, remove all spaces
1153  if (lcd_time_string.length() > (int)lcd->getLCDWidth())
1154  lcd_time_string.remove(' ');
1155 
1156  lcd->setMusicProgress(lcd_time_string, percent_heard);
1157  }
1158  }
1159  }
1160 }
1161 
1162 void MusicCommon::changeRating(bool increase)
1163 {
1165  return;
1166 
1167  // Rationale here is that if you can't get visual feedback on ratings
1168  // adjustments, you probably should not be changing them
1169  // TODO: should check if the rating is visible in the playlist buttontlist
1170  //if (!m_ratingState)
1171  // return;
1172 
1174  if (!curMeta)
1175  return;
1176 
1177 
1178  if (increase)
1179  curMeta->incRating();
1180  else
1181  curMeta->decRating();
1182 
1183  gPlayer->sendTrackStatsChangedEvent(curMeta->ID());
1184 }
1185 
1186 void MusicCommon::customEvent(QEvent *event)
1187 {
1188  QString statusString;
1189 
1190  if (event->type() == OutputEvent::Playing)
1191  {
1193  if (curMeta)
1194  updateTrackInfo(curMeta);
1195 
1196  statusString = tr("Playing stream.");
1197  if (gPlayer->isPlaying())
1198  {
1199  if (m_stopButton)
1200  m_stopButton->SetLocked(false);
1201  if (m_playButton)
1202  m_playButton->SetLocked(true);
1203  if (m_pauseButton)
1204  m_pauseButton->SetLocked(false);
1205  if (m_trackState)
1206  m_trackState->DisplayState("playing");
1207 
1208  if (m_currentPlaylist)
1209  {
1211  if (item)
1212  {
1213  item->SetFontState("running");
1214  item->DisplayState("playing", "playstate");
1215  }
1216  }
1217 
1218  startVisualizer();
1219 
1220  updateVolume();
1221  }
1222  }
1223  else if (event->type() == OutputEvent::Buffering)
1224  {
1225  statusString = tr("Buffering stream.");
1226  }
1227  else if (event->type() == OutputEvent::Paused)
1228  {
1229  statusString = tr("Stream paused.");
1230 
1231  if (m_stopButton)
1232  m_stopButton->SetLocked(false);
1233  if (m_playButton)
1234  m_playButton->SetLocked(false);
1235  if (m_pauseButton)
1236  m_pauseButton->SetLocked(true);
1237  if (m_trackState)
1238  m_trackState->DisplayState("paused");
1239 
1240  if (m_currentPlaylist)
1241  {
1243  if (item)
1244  {
1245  item->SetFontState("idle");
1246  item->DisplayState("paused", "playstate");
1247  }
1248  }
1249  }
1250  else if (event->type() == OutputEvent::Info)
1251  {
1252 
1253  auto *oe = dynamic_cast<OutputEvent *>(event);
1254 
1255  if (!oe)
1256  return;
1257 
1258  int rs = 0;
1260 
1262  {
1263  if (curMeta)
1264  m_currentTime = rs = curMeta->Length() / 1000;
1265  else
1266  m_currentTime = 0;
1267  }
1268  else
1269  m_currentTime = rs = oe->elapsedSeconds();
1270 
1271  QString time_string = getTimeString(rs, m_maxTime);
1272 
1274 
1275  if (curMeta)
1276  {
1277  if (LCD *lcd = LCD::Get())
1278  {
1279  float percent_heard = m_maxTime <= 0 ?
1280  0.0F:((float)rs / (float)curMeta->Length()) * 1000.0F;
1281 
1282  QString lcd_time_string = time_string;
1283 
1284  // if the string is longer than the LCD width, remove all spaces
1285  if (time_string.length() > (int)lcd->getLCDWidth())
1286  lcd_time_string.remove(' ');
1287 
1288  lcd->setMusicProgress(lcd_time_string, percent_heard);
1289  }
1290  }
1291 
1292  QString info_string;
1293 
1294  // Hack around for cd bitrates
1295  if (oe->bitrate() < 2000)
1296  {
1297 #if QT_VERSION < QT_VERSION_CHECK(5,4,0)
1298  info_string.sprintf(QString("%d "+tr("kbps")+ " %.1f "+ tr("kHz")+ " %s "+ tr("ch")).toUtf8().data(),
1299  static_cast<double>(oe->frequency()) / 1000.0,
1300  oe->channels() > 1 ? "2" : "1");
1301 #else
1302  info_string.sprintf(qUtf8Printable("%d "+tr("kbps")+ " %.1f "+ tr("kHz")+ " %s "+ tr("ch")),
1303  oe->bitrate(), static_cast<double>(oe->frequency()) / 1000.0,
1304  oe->channels() > 1 ? "2" : "1");
1305 #endif
1306  }
1307  else
1308  {
1309 #if QT_VERSION < QT_VERSION_CHECK(5,4,0)
1310  info_string.sprintf(QString("%d "+tr("kbps")+ " %.1f "+ tr("kHz")+ " %s "+ tr("ch")).toUtf8().data(),
1311  static_cast<double>(oe->frequency()) / 1000.0,
1312  oe->channels() > 1 ? "2" : "1");
1313 #else
1314  info_string.sprintf(qUtf8Printable("%.1f "+ tr("kHz")+ " %s "+ tr("ch")),
1315  static_cast<double>(oe->frequency()) / 1000.0,
1316  oe->channels() > 1 ? "2" : "1");
1317 #endif
1318  }
1319 
1320  if (curMeta)
1321  {
1322  if (m_timeText)
1323  m_timeText->SetText(time_string);
1324  if (m_infoText)
1325  m_infoText->SetText(info_string);
1326  }
1327 
1328  // TODO only need to update the playlist times here
1330  }
1331  else if (event->type() == OutputEvent::Stopped)
1332  {
1333  statusString = tr("Stream stopped.");
1334  if (m_stopButton)
1335  m_stopButton->SetLocked(true);
1336  if (m_playButton)
1337  m_playButton->SetLocked(false);
1338  if (m_pauseButton)
1339  m_pauseButton->SetLocked(false);
1340  if (m_trackState)
1341  m_trackState->DisplayState("stopped");
1342 
1343  if (m_currentPlaylist)
1344  {
1346  if (item)
1347  {
1348  item->SetFontState("normal");
1349  item->DisplayState("stopped", "playstate");
1350  }
1351  }
1352 
1353  stopVisualizer();
1354  }
1355  else if (event->type() == DialogCompletionEvent::kEventType)
1356  {
1357  auto dce = dynamic_cast<DialogCompletionEvent*>(event);
1358 
1359  // make sure the user didn't ESCAPE out of the menu
1360  if ((dce == nullptr) || (dce->GetResult() < 0))
1361  return;
1362 
1363  QString resultid = dce->GetId();
1364  QString resulttext = dce->GetResultText();
1365 
1366  if (resultid == "mainmenu")
1367  {
1368  if (resulttext == tr("Fullscreen Visualizer"))
1370  else if (resulttext == tr("Playlist Editor"))
1371  {
1372  if (gCoreContext->GetSetting("MusicPlaylistEditorView", "tree") == "tree")
1374  else
1376  }
1377  else if (resulttext == tr("Search for Music"))
1379  else if (resulttext == tr("Switch To Gallery View"))
1381  else if (resulttext == tr("Switch To Tree View"))
1383  else if (resulttext == tr("Lyrics"))
1385  }
1386  else if (resultid == "submenu")
1387  {
1388  if (resulttext == tr("Search List..."))
1389  searchButtonList();
1390  }
1391  else if (resultid == "playlistmenu")
1392  {
1393  if (resulttext == tr("Sync List With Current Track"))
1394  {
1396  }
1397  else if (resulttext == tr("Remove Selected Track"))
1398  {
1400  if (item)
1401  {
1402  auto *mdata = item->GetData().value<MusicMetadata*>();
1403  if (mdata)
1404  gPlayer->removeTrack(mdata->ID());
1405  }
1406  }
1407  else if (resulttext == tr("Remove All Tracks"))
1408  {
1409  if (gPlayer->getCurrentPlaylist())
1410  {
1412  gPlayer->activePlaylistChanged(-1, true);
1413  }
1414  }
1415  else if (resulttext == tr("Save To New Playlist"))
1416  {
1417  QString message = tr("Enter new playlist name");
1418 
1419  MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
1420 
1421  auto *inputdialog = new MythTextInputDialog(popupStack, message);
1422 
1423  if (inputdialog->Create())
1424  {
1425  inputdialog->SetReturnEvent(this, "addplaylist");
1426  popupStack->AddScreen(inputdialog);
1427  }
1428  else
1429  delete inputdialog;
1430  }
1431  else if (resulttext == tr("Save To Existing Playlist"))
1432  {
1433  QString message = tr("Select the playlist to save to");
1434  QStringList playlists = gMusicData->m_all_playlists->getPlaylistNames();
1435 
1436  MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
1437 
1438  auto *searchdialog = new MythUISearchDialog(popupStack, message, playlists);
1439 
1440  if (searchdialog->Create())
1441  {
1442  searchdialog->SetReturnEvent(this, "updateplaylist");
1443  popupStack->AddScreen(searchdialog);
1444  }
1445  }
1446  else if (resulttext == tr("Switch To Move Mode"))
1447  {
1448  m_moveTrackMode = true;
1449  m_movingTrack = false;
1450 
1451  if (m_movingTracksState)
1453  }
1454  else if (resulttext == tr("Switch To Select Mode"))
1455  {
1456  m_moveTrackMode = false;
1457 
1459  {
1461  if (item)
1462  item->DisplayState("off", "movestate");
1463 
1464  m_movingTrack = false;
1465  }
1466 
1467  if (m_movingTracksState)
1469  }
1470  }
1471  else if (resultid == "repeatmenu")
1472  {
1473  int mode = dce->GetData().toInt();
1475  updateRepeatMode();
1476  }
1477  else if (resultid == "shufflemenu")
1478  {
1479  int mode = dce->GetData().toInt();
1481  updateShuffleMode(true);
1482  }
1483  else if (resultid == "exitmenu")
1484  {
1485  if (resulttext == tr("No - Exit, Stop Playing"))
1486  {
1487  gPlayer->savePosition();
1488  stopAll();
1489  Close();
1490  }
1491  else if (resulttext == tr("Yes - Exit, Continue Playing"))
1492  {
1493  Close();
1494  }
1495  }
1496  else if (resultid == "playermenu")
1497  {
1498  if (resulttext == tr("Change Volume"))
1499  showVolume();
1500  else if (resulttext == tr("Mute"))
1501  toggleMute();
1502  else if (resulttext == tr("Previous Track"))
1503  previous();
1504  else if (resulttext == tr("Next Track"))
1505  next();
1506  else if (resulttext == tr("Jump Back"))
1507  seekback();
1508  else if (resulttext == tr("Jump Forward"))
1509  seekforward();
1510  else if (resulttext == tr("Play"))
1511  play();
1512  else if (resulttext == tr("Stop"))
1513  stop();
1514  else if (resulttext == tr("Pause"))
1515  pause();
1516  }
1517  else if (resultid == "quickplaylistmenu")
1518  {
1519  if (resulttext == tr("All Tracks"))
1520  allTracks();
1521  else if (resulttext == tr("From CD"))
1522  fromCD();
1523  else if (resulttext == tr("Tracks By Current Artist"))
1524  byArtist();
1525  else if (resulttext == tr("Tracks From Current Genre"))
1526  byGenre();
1527  else if (resulttext == tr("Tracks From Current Album"))
1528  byAlbum();
1529  else if (resulttext == tr("Tracks From Current Year"))
1530  byYear();
1531  else if (resulttext == tr("Tracks With Same Title"))
1532  byTitle();
1533  }
1534  else if (resultid == "playlistoptionsmenu")
1535  {
1536  if (resulttext == tr("Replace Tracks"))
1537  {
1539  doUpdatePlaylist();
1540  }
1541  else if (resulttext == tr("Add Tracks"))
1542  {
1544  doUpdatePlaylist();
1545  }
1546  }
1547  else if (resultid == "visualizermenu")
1548  {
1549  if (dce->GetResult() >= 0)
1550  {
1551  m_currentVisual = dce->GetData().toInt();
1552 
1553  //Change to the new visualizer
1555  }
1556  }
1557  else if (resultid == "addplaylist")
1558  {
1560  Playlist *playlist = gMusicData->m_all_playlists->getPlaylist(resulttext);
1561  gPlayer->playlistChanged(playlist->getID());
1562  }
1563  else if (resultid == "updateplaylist")
1564  {
1565  if (gPlayer->getCurrentPlaylist())
1566  {
1567  Playlist *playlist = gMusicData->m_all_playlists->getPlaylist(resulttext);
1568  QString songList = gPlayer->getCurrentPlaylist()->toRawSonglist();
1569  playlist->removeAllTracks();
1570  playlist->fillSongsFromSonglist(songList);
1571  playlist->changed();
1572  gPlayer->playlistChanged(playlist->getID());
1573  }
1574  }
1575  }
1576  else if (event->type() == MusicPlayerEvent::TrackChangeEvent)
1577  {
1578  auto *mpe = dynamic_cast<MusicPlayerEvent *>(event);
1579 
1580  if (!mpe)
1581  return;
1582 
1583  int trackNo = mpe->m_trackID;
1584 
1585  if (m_currentPlaylist)
1586  {
1587  if (m_currentTrack >= 0 && m_currentTrack < m_currentPlaylist->GetCount())
1588  {
1590  if (item)
1591  {
1592  item->SetFontState("normal");
1593  item->DisplayState("default", "playstate");
1594  }
1595  }
1596 
1597  if (trackNo >= 0 && trackNo < m_currentPlaylist->GetCount())
1598  {
1601 
1603  if (item)
1604  {
1605  item->SetFontState("running");
1606  item->DisplayState("playing", "playstate");
1607  }
1608  }
1609  }
1610 
1611  m_currentTrack = trackNo;
1612 
1613  if (gPlayer->getCurrentPlaylist())
1616  if (m_playlistProgress)
1617  {
1620  }
1621 
1624  }
1625  else if (event->type() == MusicPlayerEvent::VolumeChangeEvent)
1626  {
1627  updateVolume();
1628  }
1629  else if (event->type() == MusicPlayerEvent::TrackRemovedEvent)
1630  {
1631  auto *mpe = dynamic_cast<MusicPlayerEvent *>(event);
1632 
1633  if (!mpe)
1634  return;
1635 
1636  int trackID = mpe->m_trackID;
1637 
1638  if (m_currentPlaylist)
1639  {
1640  // find and remove the list item for the removed track
1641  for (int x = 0; x < m_currentPlaylist->GetCount(); x++)
1642  {
1644  auto *mdata = item->GetData().value<MusicMetadata*>();
1645  if (mdata && mdata->ID() == (MusicMetadata::IdType) trackID)
1646  {
1648  break;
1649  }
1650  }
1651  }
1652 
1654 
1655  // if we have just removed the playing track from the playlist
1656  // move to the next track
1657  if (gPlayer->getCurrentMetadata())
1658  {
1659  if (gPlayer->getCurrentMetadata()->ID() == (MusicMetadata::IdType) trackID)
1660  gPlayer->next();
1661  }
1662 
1663  if (gPlayer->getCurrentPlaylist())
1668 
1671  }
1672  else if (event->type() == MusicPlayerEvent::TrackAddedEvent)
1673  {
1674  auto *mpe = dynamic_cast<MusicPlayerEvent *>(event);
1675 
1676  if (!mpe)
1677  return;
1678 
1679  int trackID = mpe->m_trackID;
1680 
1681  if (m_currentPlaylist)
1682  {
1683  if (trackID == -1)
1684  {
1685  // more than one track has been added so easier to just reload the list
1686  updateUIPlaylist();
1687  }
1688  else
1689  {
1690  // just one track was added so just add that track to the end of the list
1691  MusicMetadata *mdata = gMusicData->m_all_music->getMetadata(trackID);
1692 
1693  if (mdata)
1694  {
1695  InfoMap metadataMap;
1696  mdata->toMap(metadataMap);
1697 
1698  auto *item = new MythUIButtonListItem(m_currentPlaylist, "",
1699  QVariant::fromValue(mdata));
1700 
1701  item->SetTextFromMap(metadataMap);
1702 
1704  mdata->ID() == gPlayer->getCurrentMetadata()->ID())
1705  {
1706  item->SetFontState("running");
1707  item->DisplayState("playing", "playstate");
1708  }
1709  else
1710  {
1711  item->SetFontState("normal");
1712  item->DisplayState("default", "playstate");
1713  }
1714 
1715  if (!gPlayer->getCurrentMetadata())
1717  }
1718 
1721  }
1722  }
1723 
1724  if (gPlayer->getCurrentPlaylist())
1727 
1730  }
1731  else if (event->type() == MusicPlayerEvent::AllTracksRemovedEvent)
1732  {
1733  updateUIPlaylist();
1735  updateTrackInfo(nullptr);
1736  }
1737  else if (event->type() == MusicPlayerEvent::MetadataChangedEvent ||
1739  {
1740  auto *mpe = dynamic_cast<MusicPlayerEvent *>(event);
1741 
1742  if (!mpe)
1743  return;
1744 
1745  uint trackID = mpe->m_trackID;
1746 
1747  if (m_currentPlaylist)
1748  {
1749  for (int x = 0; x < m_currentPlaylist->GetCount(); x++)
1750  {
1752  auto *mdata = item->GetData().value<MusicMetadata*>();
1753 
1754  if (mdata && mdata->ID() == trackID)
1755  {
1756  InfoMap metadataMap;
1757  mdata->toMap(metadataMap);
1758  item->SetTextFromMap(metadataMap);
1759 
1760  item->DisplayState(QString("%1").arg(mdata->Rating()), "ratingstate");
1761  }
1762  }
1763  }
1764 
1765  if (m_playedTracksList)
1766  {
1767  for (int x = 0; x < m_playedTracksList->GetCount(); x++)
1768  {
1770  auto *mdata = item->GetData().value<MusicMetadata*>();
1771 
1772  if (mdata && mdata->ID() == trackID)
1773  {
1774  InfoMap metadataMap;
1775  mdata->toMap(metadataMap);
1776  item->SetTextFromMap(metadataMap);
1777  }
1778  }
1779  }
1780 
1781  if (gPlayer->getCurrentMetadata() && trackID == gPlayer->getCurrentMetadata()->ID())
1783 
1784  // this will ensure the next track info gets updated
1785  if (gPlayer->getNextMetadata() && trackID == gPlayer->getNextMetadata()->ID())
1787  }
1788  else if (event->type() == MusicPlayerEvent::AlbumArtChangedEvent)
1789  {
1790  auto *mpe = dynamic_cast<MusicPlayerEvent *>(event);
1791 
1792  if (!mpe)
1793  return;
1794 
1795  uint trackID = mpe->m_trackID;
1796 
1797  if (m_currentPlaylist)
1798  {
1799  for (int x = 0; x < m_currentPlaylist->GetCount(); x++)
1800  {
1802  auto *mdata = item->GetData().value<MusicMetadata*>();
1803  if (mdata && mdata->ID() == trackID)
1804  {
1805  // reload the albumart image if one has already been loaded for this track
1806  if (!item->GetImageFilename().isEmpty())
1807  {
1808  QString artFile = mdata->getAlbumArtFile();
1809  if (artFile.isEmpty())
1810  {
1811  item->SetImage("");
1812  item->SetImage("", "coverart");
1813  }
1814  else
1815  {
1816  item->SetImage(mdata->getAlbumArtFile());
1817  item->SetImage(mdata->getAlbumArtFile(), "coverart");
1818  }
1819  }
1820  }
1821  }
1822  }
1823 
1824  if (gPlayer->getCurrentMetadata() && trackID == gPlayer->getCurrentMetadata()->ID())
1826  }
1827  else if (event->type() == MusicPlayerEvent::TrackUnavailableEvent)
1828  {
1829  auto *mpe = dynamic_cast<MusicPlayerEvent *>(event);
1830 
1831  if (!mpe)
1832  return;
1833 
1834  uint trackID = mpe->m_trackID;
1835 
1836  if (m_currentPlaylist)
1837  {
1838  for (int x = 0; x < m_currentPlaylist->GetCount(); x++)
1839  {
1841  auto *mdata = item->GetData().value<MusicMetadata*>();
1842  if (mdata && mdata->ID() == trackID)
1843  {
1844  item->SetFontState("disabled");
1845  item->DisplayState("unavailable", "playstate");
1846  }
1847  }
1848  }
1849  }
1850 }
1851 
1853 {
1854  if (!m_controlVolume)
1855  {
1856  if (m_volumeText)
1857  m_volumeText->Hide();
1858 
1859  if (m_muteState)
1860  m_muteState->Hide();
1861 
1862  return;
1863  }
1864 
1865  if (m_volumeText)
1866  {
1867  InfoMap map;
1868  gPlayer->toMap(map);
1870  }
1871 
1872  if (m_muteState)
1873  {
1874  bool muted = gPlayer->isMuted();
1875  m_muteState->DisplayState(muted ? "on" : "off");
1876  }
1877 }
1878 
1880 {
1881  if (!mdata)
1882  return;
1883 
1885 
1886  auto *editDialog = new EditMetadataDialog(mainStack, mdata);
1887 
1888  if (!editDialog->Create())
1889  {
1890  delete editDialog;
1891  return;
1892  }
1893 
1894  mainStack->AddScreen(editDialog);
1895 }
1896 
1898 {
1899  if (!mdata)
1900  {
1901  InfoMap metadataMap;
1902  MusicMetadata metadata;
1903  metadata.toMap(metadataMap);
1904  metadata.toMap(metadataMap, "next");
1905  ResetMap(metadataMap);
1906 
1907  if (m_coverartImage)
1909  if (m_ratingState)
1911  if (m_timeText)
1912  m_timeText->Reset();
1913  if (m_infoText)
1914  m_infoText->Reset();
1915  if (m_trackProgress)
1917 
1918  if (m_mainvisual)
1920 
1921  return;
1922  }
1923 
1925  m_maxTime = 0;
1926  else
1927  m_maxTime = mdata->Length() / 1000;
1928 
1929  // get map for current track
1930  InfoMap metadataMap;
1931  mdata->toMap(metadataMap);
1932 
1933  // add the map from the next track
1934  MusicMetadata *nextMetadata = gPlayer->getNextMetadata();
1935  if (nextMetadata)
1936  nextMetadata->toMap(metadataMap, "next");
1937 
1938  // now set text using the map
1939  SetTextFromMap(metadataMap);
1940 
1941  if (m_coverartImage)
1942  {
1943  QString filename = mdata->getAlbumArtFile();
1944  if (!filename.isEmpty())
1945  {
1947  m_coverartImage->Load();
1948  }
1949  else
1951  }
1952 
1953  if (m_ratingState)
1954  m_ratingState->DisplayState(QString("%1").arg(mdata->Rating()));
1955 
1956  setTrackOnLCD(mdata);
1957 }
1958 
1960 {
1961  if (!mdata)
1962  return;
1963 
1964  MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
1965 
1966  auto *dlg = new TrackInfoDialog(popupStack, mdata, "trackinfopopup");
1967 
1968  if (!dlg->Create())
1969  {
1970  delete dlg;
1971  return;
1972  }
1973 
1974  popupStack->AddScreen(dlg);
1975 }
1976 
1978 {
1979  if (!item)
1980  return;
1981 
1982  if (m_moveTrackMode)
1983  {
1985 
1986  if (m_movingTrack)
1987  item->DisplayState("on", "movestate");
1988  else
1989  item->DisplayState("off", "movestate");
1990  }
1991  else
1993 
1994  if (m_cycleVisualizer)
1995  cycleVisualizer();
1996 }
1997 
1999 {
2000  if (!item)
2001  return;
2002 
2003  auto *mdata = item->GetData().value<MusicMetadata*>();
2004  if (mdata && item->GetText() == " ")
2005  {
2006  if (item->GetImageFilename().isEmpty())
2007  {
2008  QString artFile = mdata->getAlbumArtFile();
2009  if (artFile.isEmpty())
2010  {
2011  item->SetImage("");
2012  item->SetImage("", "coverart");
2013  }
2014  else
2015  {
2016  item->SetImage(mdata->getAlbumArtFile());
2017  item->SetImage(mdata->getAlbumArtFile(), "coverart");
2018  }
2019  }
2020 
2021  InfoMap metadataMap;
2022  mdata->toMap(metadataMap);
2023  item->SetText("");
2024  item->SetTextFromMap(metadataMap);
2025  item->DisplayState(QString("%1").arg(mdata->Rating()), "ratingstate");
2026  }
2027 }
2028 
2030 {
2033 
2034  if (!m_currentPlaylist)
2035  return;
2036 
2038 
2039  m_currentTrack = -1;
2040 
2041  Playlist *playlist = gPlayer->getCurrentPlaylist();
2042 
2043  if (!playlist)
2044  return;
2045 
2046  for (int x = 0; x < playlist->getTrackCount(); x++)
2047  {
2048  MusicMetadata *mdata = playlist->getSongAt(x);
2049  if (mdata)
2050  {
2051  auto *item = new MythUIButtonListItem(m_currentPlaylist, " ",
2052  QVariant::fromValue(mdata));
2053 
2054  item->SetText(mdata->Artist() + mdata->Album() + mdata->Title(), "**search**");
2055  item->SetFontState("normal");
2056  item->DisplayState("default", "playstate");
2057 
2058  // if this is the current track update its play state to match the player
2059  if (gPlayer->getCurrentMetadata() && mdata->ID() == gPlayer->getCurrentMetadata()->ID())
2060  {
2061  if (gPlayer->isPlaying())
2062  {
2063  item->SetFontState("running");
2064  item->DisplayState("playing", "playstate");
2065  }
2066  else if (gPlayer->isPaused())
2067  {
2068  item->SetFontState("idle");
2069  item->DisplayState("paused", "playstate");
2070  }
2071  else
2072  {
2073  item->SetFontState("normal");
2074  item->DisplayState("stopped", "playstate");
2075  }
2076 
2079  }
2080  }
2081  }
2082 }
2083 
2085 {
2086  if (!m_playedTracksList)
2087  return;
2088 
2090 
2091  QList<MusicMetadata*> playedList = gPlayer->getPlayedTracksList();
2092 
2093  for (int x = playedList.count(); x > 0; x--)
2094  {
2095  MusicMetadata *mdata = playedList[x-1];
2096  auto *item = new MythUIButtonListItem(m_playedTracksList, "",
2097  QVariant::fromValue(mdata));
2098 
2099  InfoMap metadataMap;
2100  mdata->toMap(metadataMap);
2101  item->SetTextFromMap(metadataMap);
2102 
2103  item->SetFontState("normal");
2104  item->DisplayState("default", "playstate");
2105 
2106  item->SetImage(mdata->getAlbumArtFile());
2107  }
2108 }
2109 
2111 {
2112  int trackCount = 0;
2113 
2114  if (gPlayer->getCurrentPlaylist())
2115  trackCount = gPlayer->getCurrentPlaylist()->getTrackCount();
2116 
2117  InfoMap map;
2118  if (gPlayer->isPlaying() && trackCount > 0)
2119  {
2120  QString playlistcurrent = QLocale::system().toString(m_currentTrack + 1);
2121  QString playlisttotal = QLocale::system().toString(trackCount);
2122 
2123  map["playlistposition"] = tr("%1 of %2").arg(playlistcurrent)
2124  .arg(playlisttotal);
2125  map["playlistcurrent"] = playlistcurrent;
2126  map["playlistcount"] = playlisttotal;
2128  map["playlistplayedtime"] = getTimeString(m_playlistPlayedTime + m_currentTime, 0);
2129  map["playlisttotaltime"] = getTimeString(m_playlistMaxTime, 0);
2130  QString playlistName = gPlayer->getCurrentPlaylist() ? gPlayer->getCurrentPlaylist()->getName() : "";
2131  if (playlistName == "default_playlist_storage")
2132  playlistName = tr("Default Playlist");
2133  else if (playlistName == "stream_playlist")
2134  playlistName = tr("Stream Playlist");
2135  map["playlistname"] = playlistName;
2136  }
2137  else
2138  {
2139  map["playlistposition"] = "";
2140  map["playlistcurrent"] = "";
2141  map["playlistcount"] = "";
2142  map["playlisttime"] = "";
2143  map["playlistplayedtime"] = "";
2144  map["playlisttotaltime"] = "";
2145  map["playlistname"] = "";
2146  }
2147 
2148  SetTextFromMap(map);
2149 
2150  if (m_playlistProgress)
2152 }
2153 
2154 QString MusicCommon::getTimeString(int exTime, int maxTime)
2155 {
2156  QString time_string;
2157 
2158  int eh = exTime / 3600;
2159  int em = (exTime / 60) % 60;
2160  int es = exTime % 60;
2161 
2162  int maxh = maxTime / 3600;
2163  int maxm = (maxTime / 60) % 60;
2164  int maxs = maxTime % 60;
2165 
2166  if (maxTime <= 0)
2167  {
2168  if (eh > 0)
2169  time_string.sprintf("%d:%02d:%02d", eh, em, es);
2170  else
2171  time_string.sprintf("%02d:%02d", em, es);
2172  }
2173  else
2174  {
2175  if (maxh > 0)
2176  {
2177  time_string.sprintf("%d:%02d:%02d / %02d:%02d:%02d", eh, em,
2178  es, maxh, maxm, maxs);
2179  }
2180  else
2181  {
2182  time_string.sprintf("%02d:%02d / %02d:%02d", em, es, maxm, maxs);
2183  }
2184  }
2185 
2186  return time_string;
2187 }
2188 
2190 {
2191  auto *buttonList = dynamic_cast<MythUIButtonList *>(GetFocusWidget());
2192  if (buttonList)
2193  buttonList->ShowSearchDialog();
2194 
2195  auto *buttonTree = dynamic_cast<MythUIButtonTree *>(GetFocusWidget());
2196  if (buttonTree)
2197  buttonTree->ShowSearchDialog();
2198 }
2199 
2201 {
2202  MythMenu *mainMenu = createMainMenu();
2203 
2204  MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
2205 
2206  auto *menuPopup = new MythDialogBox(mainMenu, popupStack, "actionmenu");
2207 
2208  if (menuPopup->Create())
2209  popupStack->AddScreen(menuPopup);
2210  else
2211  delete mainMenu;
2212 }
2213 
2215 {
2216  QString label = tr("View Actions");
2217 
2218  auto *menu = new MythMenu(label, this, "mainmenu");
2219 
2221  menu->AddItem(tr("Switch To Gallery View"));
2223  menu->AddItem(tr("Switch To Tree View"));
2224  else if (m_currentView == MV_PLAYLIST)
2225  menu->AddItem(MusicCommon::tr("Playlist Editor"));
2226 
2227  QStringList screenList;
2228  MythScreenType *screen = this;
2229  while (screen)
2230  {
2231  screenList.append(screen->objectName());
2232  screen = dynamic_cast<MusicCommon*>(screen)->m_parentScreen;
2233  }
2234 
2235  if (!screenList.contains("searchview") && !screenList.contains("streamview"))
2236  menu->AddItem(tr("Search for Music"));
2237 
2238  if (!screenList.contains("visualizerview"))
2239  menu->AddItem(tr("Fullscreen Visualizer"));
2240 
2241  if (!screenList.contains("lyricsview"))
2242  menu->AddItem(tr("Lyrics"));
2243 
2244  menu->AddItem(tr("More Options"), nullptr, createSubMenu());
2245 
2246  return menu;
2247 }
2248 
2250 {
2251  QString label = tr("Actions");
2252 
2253  auto *menu = new MythMenu(label, this, "submenu");
2254 
2255  if (GetFocusWidget() && (GetFocusWidget()->inherits("MythUIButtonList") ||
2256  GetFocusWidget()->inherits("MythUIButtonTree")))
2257  menu->AddItem(tr("Search List..."));
2258 
2260  {
2261  menu->AddItem(tr("Playlist Options"), nullptr, createPlaylistMenu());
2262  menu->AddItem(tr("Set Shuffle Mode"), nullptr, createShuffleMenu());
2263  menu->AddItem(tr("Set Repeat Mode"), nullptr, createRepeatMenu());
2264  }
2265 
2266  menu->AddItem(tr("Player Options"), nullptr, createPlayerMenu());
2267 
2269  menu->AddItem(tr("Quick Playlists"), nullptr, createQuickPlaylistsMenu());
2270 
2271  if (m_visualizerVideo)
2272  menu->AddItem(tr("Change Visualizer"), nullptr, createVisualizerMenu());
2273 
2274  return menu;
2275 }
2276 
2278 {
2279  QString label = tr("Playlist Options");
2280 
2281  auto *menu = new MythMenu(label, this, "playlistmenu");
2282 
2283  if (m_currentPlaylist)
2284  {
2285  menu->AddItem(tr("Sync List With Current Track"));
2286  menu->AddItem(tr("Remove Selected Track"));
2287  }
2288 
2289  menu->AddItem(tr("Remove All Tracks"));
2290 
2291  if (m_currentPlaylist)
2292  {
2293  menu->AddItem(tr("Save To New Playlist"));
2294  menu->AddItem(tr("Save To Existing Playlist"));
2295 
2296  if (m_moveTrackMode)
2297  menu->AddItem(tr("Switch To Select Mode"));
2298  else
2299  menu->AddItem(tr("Switch To Move Mode"));
2300  }
2301 
2302  return menu;
2303 }
2304 
2306 {
2307  QString label = tr("Exiting Music Player.\n\n"
2308  "Do you want to continue playing in the background?");
2309 
2310  MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
2311 
2312  auto *menu = new MythDialogBox(label, popupStack, "exitmenu");
2313 
2314  if (!menu->Create())
2315  {
2316  delete menu;
2317  return;
2318  }
2319 
2320  menu->SetReturnEvent(this, "exitmenu");
2321 
2322  menu->AddButton(tr("No - Exit, Stop Playing"));
2323  menu->AddButton(tr("Yes - Exit, Continue Playing"));
2324  menu->AddButton(tr("Cancel"));
2325 
2326  popupStack->AddScreen(menu);
2327 }
2328 
2330 {
2331  QString label = tr("Player Actions");
2332 
2333  auto *menu = new MythMenu(label, this, "playermenu");
2334 
2335  menu->AddItem(tr("Change Volume"));
2336  menu->AddItem(tr("Mute"));
2337  menu->AddItem(tr("Previous Track"));
2338  menu->AddItem(tr("Next Track"));
2339 
2341  {
2342  menu->AddItem(tr("Jump Back"));
2343  menu->AddItem(tr("Jump Forward"));
2344  }
2345 
2346  menu->AddItem(tr("Play"));
2347  menu->AddItem(tr("Stop"));
2348 
2350  menu->AddItem(tr("Pause"));
2351 
2352  return menu;
2353 }
2354 
2356 {
2357  QString label = tr("Set Repeat Mode");
2358 
2359  auto *menu = new MythMenu(label, this, "repeatmenu");
2360 
2361  menu->AddItem(tr("None"), QVariant::fromValue((int)MusicPlayer::REPEAT_OFF));
2362  menu->AddItem(tr("Track"), QVariant::fromValue((int)MusicPlayer::REPEAT_TRACK));
2363  menu->AddItem(tr("All"), QVariant::fromValue((int)MusicPlayer::REPEAT_ALL));
2364 
2365  menu->SetSelectedByData(static_cast<int>(gPlayer->getRepeatMode()));
2366 
2367  return menu;
2368 }
2369 
2371 {
2372  QString label = tr("Set Shuffle Mode");
2373 
2374  auto *menu = new MythMenu(label, this, "shufflemenu");
2375 
2376  menu->AddItem(tr("None"), QVariant::fromValue((int)MusicPlayer::SHUFFLE_OFF));
2377  menu->AddItem(tr("Random"), QVariant::fromValue((int)MusicPlayer::SHUFFLE_RANDOM));
2378  menu->AddItem(tr("Smart"), QVariant::fromValue((int)MusicPlayer::SHUFFLE_INTELLIGENT));
2379  menu->AddItem(tr("Album"), QVariant::fromValue((int)MusicPlayer::SHUFFLE_ALBUM));
2380  menu->AddItem(tr("Artist"), QVariant::fromValue((int)MusicPlayer::SHUFFLE_ARTIST));
2381 
2382  menu->SetSelectedByData(static_cast<int>(gPlayer->getShuffleMode()));
2383 
2384  return menu;
2385 }
2386 
2388 {
2389  QString label = tr("Quick Playlists");
2390 
2391  auto *menu = new MythMenu(label, this, "quickplaylistmenu");
2392 
2393  menu->AddItem(tr("All Tracks"));
2394 
2396  menu->AddItem(tr("From CD"));
2397 
2398  if (gPlayer->getCurrentMetadata())
2399  {
2400  menu->AddItem(tr("Tracks By Current Artist"));
2401  menu->AddItem(tr("Tracks From Current Album"));
2402  menu->AddItem(tr("Tracks From Current Genre"));
2403  menu->AddItem(tr("Tracks From Current Year"));
2404  menu->AddItem(tr("Tracks With Same Title"));
2405  }
2406 
2407  return menu;
2408 }
2409 
2411 {
2412  QString label = tr("Choose Visualizer");
2413 
2414  auto *menu = new MythMenu(label, this, "visualizermenu");
2415 
2416  for (uint x = 0; x < static_cast<uint>(m_visualModes.count()); x++)
2417  menu->AddItem(m_visualModes.at(x), QVariant::fromValue(x));
2418 
2419  menu->SetSelectedByData(m_currentVisual);
2420 
2421  return menu;
2422 }
2423 
2425 {
2426  QString label = tr("Add to Playlist Options");
2427 
2428  auto *menu = new MythMenu(label, this, "playlistoptionsmenu");
2429 
2430  menu->AddItem(tr("Replace Tracks"));
2431  menu->AddItem(tr("Add Tracks"));
2432 
2433  return menu;
2434 }
2435 
2437 {
2438  m_whereClause = "ORDER BY music_artists.artist_name, album_name, disc_number, track";
2440 }
2441 
2443 {
2444  m_whereClause = "";
2445  m_songList.clear();
2446 
2447  // get the list of cd tracks
2448  for (int x = 1; x <= gMusicData->m_all_music->getCDTrackCount(); x++)
2449  {
2451  if (mdata)
2452  {
2453  m_songList.append((mdata)->ID());
2454  }
2455  }
2456 
2458 }
2459 
2461 {
2463  if (!mdata)
2464  return;
2465 
2466  QString value = formattedFieldValue(mdata->Artist().toUtf8().constData());
2467  m_whereClause = "WHERE music_artists.artist_name = " + value +
2468  " ORDER BY album_name, disc_number, track";
2469 
2471 }
2472 
2474 {
2476  if (!mdata)
2477  return;
2478 
2479  QString value = formattedFieldValue(mdata->Album().toUtf8().constData());
2480  m_whereClause = "WHERE album_name = " + value +
2481  " ORDER BY disc_number, track";
2482 
2484 }
2485 
2487 {
2489  if (!mdata)
2490  return;
2491 
2492  QString value = formattedFieldValue(mdata->Genre().toUtf8().constData());
2493  m_whereClause = "WHERE genre = " + value +
2494  " ORDER BY music_artists.artist_name, album_name, disc_number, track";
2495 
2497 }
2498 
2500 {
2502  if (!mdata)
2503  return;
2504 
2505  QString value = formattedFieldValue(mdata->Year());
2506  m_whereClause = "WHERE music_songs.year = " + value +
2507  " ORDER BY music_artists.artist_name, album_name, disc_number, track";
2508 
2510 }
2511 
2513 {
2515  if (!mdata)
2516  return;
2517 
2518  QString value = formattedFieldValue(mdata->Title().toUtf8().constData());
2519  m_whereClause = "WHERE music_songs.name = " + value +
2520  " ORDER BY music_artists.artist_name, album_name, disc_number, track";
2521 
2523 }
2524 
2526 {
2527  if (!gPlayer->getCurrentPlaylist())
2528  return;
2529 
2531 
2532  // Don't bother showing the dialog if the current playlist is empty
2533  if (gPlayer->getCurrentPlaylist()->getTrackCount() == 0)
2534  {
2536  doUpdatePlaylist();
2537  return;
2538  }
2539 
2541 
2542  if (addMainMenu)
2543  menu->AddItem(tr("More Options"), nullptr, createMainMenu());
2544 
2545  MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
2546 
2547  auto *menuPopup = new MythDialogBox(menu, popupStack, "playlistoptionsmenu");
2548 
2549  if (menuPopup->Create())
2550  popupStack->AddScreen(menuPopup);
2551  else
2552  delete menu;
2553 }
2554 
2556 {
2557  int curTrackID = -1;
2558  int trackCount = 0;
2559  int curPos = gPlayer->getCurrentTrackPos();
2560 
2561  if (gPlayer->getCurrentPlaylist())
2562  trackCount = gPlayer->getCurrentPlaylist()->getTrackCount();
2563 
2564  // store id of current track
2565  if (gPlayer->getCurrentMetadata())
2566  curTrackID = gPlayer->getCurrentMetadata()->ID();
2567 
2568  if (!m_whereClause.isEmpty())
2569  {
2570  // update playlist from quick playlist
2572  m_whereClause, true,
2573  m_playlistOptions.insertPLOption, curTrackID);
2574  m_whereClause.clear();
2575  }
2576  else if (!m_songList.isEmpty())
2577  {
2578  // update playlist from song list (from the playlist editor)
2580  m_songList, true,
2581  m_playlistOptions.insertPLOption, curTrackID);
2582 
2583  m_songList.clear();
2584  }
2585 
2587 
2588  updateUIPlaylist();
2589 
2590  if (m_currentTrack == -1)
2591  playFirstTrack();
2592  else
2593  {
2595  {
2596  case PL_CURRENT:
2597  {
2598  if (!restorePosition(curTrackID))
2599  playFirstTrack();
2600 
2601  break;
2602  }
2603 
2604  case PL_FIRST:
2605  playFirstTrack();
2606  break;
2607 
2608  case PL_FIRSTNEW:
2609  {
2611  {
2612  case PL_REPLACE:
2613  playFirstTrack();
2614  break;
2615 
2616  case PL_INSERTATEND:
2617  {
2618  pause();
2619  if (!gPlayer->setCurrentTrackPos(trackCount))
2620  playFirstTrack();
2621  break;
2622  }
2623 
2624  case PL_INSERTAFTERCURRENT:
2625  if (!gPlayer->setCurrentTrackPos(curPos + 1))
2626  playFirstTrack();
2627  break;
2628 
2629  default:
2630  playFirstTrack();
2631  }
2632 
2633  break;
2634  }
2635  }
2636  }
2637 
2638  if (gPlayer->getCurrentPlaylist())
2643 }
2644 
2646 {
2647  // try to move to the current track
2648  bool foundTrack = false;
2649 
2650  if (trackID != -1 && gPlayer->getCurrentPlaylist())
2651  {
2652  for (int x = 0; x < gPlayer->getCurrentPlaylist()->getTrackCount(); x++)
2653  {
2655  if (mdata && mdata->ID() == (MusicMetadata::IdType) trackID)
2656  {
2657  m_currentTrack = x;
2658  if (m_currentPlaylist)
2659  {
2662  if (item)
2663  {
2664  item->SetFontState("running");
2665  item->DisplayState("playing", "playstate");
2666  }
2667  }
2668 
2669  foundTrack = true;
2670 
2671  break;
2672  }
2673  }
2674  }
2675 
2676  return foundTrack;
2677 }
2678 
2680 {
2682 }
2683 
2684 //---------------------------------------------------------
2685 // MythMusicVolumeDialog
2686 //---------------------------------------------------------
2687 #define MUSICVOLUMEPOPUPTIME (4 * 1000)
2688 
2690 {
2691  if (m_displayTimer)
2692  {
2693  m_displayTimer->stop();
2694  delete m_displayTimer;
2695  m_displayTimer = nullptr;
2696  }
2697 }
2698 
2700 {
2701  if (!LoadWindowFromXML("music-ui.xml", "volume_popup", this))
2702  return false;
2703 
2704  UIUtilW::Assign(this, m_volText, "volume");
2705  UIUtilW::Assign(this, m_volProgress, "volumeprogress");
2706  UIUtilW::Assign(this, m_muteState, "mutestate");
2707 
2708  if (m_volProgress)
2709  m_volProgress->SetTotal(100);
2710 
2711  updateDisplay();
2712 
2713  m_displayTimer = new QTimer(this);
2714  connect(m_displayTimer, SIGNAL(timeout()), this, SLOT(Close()));
2715  m_displayTimer->setSingleShot(true);
2717 
2718  return true;
2719 }
2720 
2722 {
2723  QStringList actions;
2724  bool handled = GetMythMainWindow()->TranslateKeyPress("Music", event, actions, false);
2725 
2726  for (int i = 0; i < actions.size() && !handled; i++)
2727  {
2728  QString action = actions[i];
2729  handled = true;
2730 
2731  if (action == "UP" || action == "VOLUMEUP")
2732  increaseVolume();
2733  else if (action == "DOWN" || action == "VOLUMEDOWN")
2734  decreaseVolume();
2735  else if (action == "MUTE" || action == "SELECT")
2736  toggleMute();
2737  else
2738  handled = false;
2739  }
2740 
2741  if (!handled && MythScreenType::keyPressEvent(event))
2742  handled = true;
2743 
2744  // Restart the display timer only if we handled this keypress, if nothing
2745  // has changed there's no need to keep the volume on-screen
2746  if (handled)
2748 
2749  return handled;
2750 }
2751 
2753 {
2754  gPlayer->incVolume();
2755  updateDisplay();
2756 }
2757 
2759 {
2760  gPlayer->decVolume();
2761  updateDisplay();
2762 }
2763 
2765 {
2766  gPlayer->toggleMute();
2767  updateDisplay();
2768 }
2769 
2771 {
2772  if (m_muteState)
2773  m_muteState->DisplayState(gPlayer->isMuted() ? "on" : "off");
2774 
2775  if (m_volProgress)
2777 
2778  if (m_volText)
2779  {
2780  InfoMap map;
2781  gPlayer->toMap(map);
2782  m_volText->SetTextFromMap(map);
2783  }
2784 }
2785 
2786 //---------------------------------------------------------
2787 // TrackInfoDialog
2788 //---------------------------------------------------------
2790 {
2791  if (!LoadWindowFromXML("music-ui.xml", "trackdetail_popup", this))
2792  return false;
2793 
2794  InfoMap metadataMap;
2795  m_metadata->toMap(metadataMap);
2796  SetTextFromMap(metadataMap);
2797 
2798  MythUIStateType *ratingState = dynamic_cast<MythUIStateType *>(GetChild("rating_state"));
2799  if (ratingState)
2800  ratingState->DisplayState(QString("%1").arg(m_metadata->Rating()));
2801 
2802  MythUIImage *albumImage = dynamic_cast<MythUIImage *>(GetChild("coverart"));
2803  if (albumImage)
2804  {
2805  if (!m_metadata->getAlbumArtFile().isEmpty())
2806  {
2807  albumImage->SetFilename(m_metadata->getAlbumArtFile());
2808  albumImage->Load();
2809  }
2810  }
2811 
2812  // hide the song ID by default
2813  MythUIText *songID = dynamic_cast<MythUIText *>(GetChild("songid"));
2814  if (songID)
2815  songID->Hide();
2816 
2817  return true;
2818 }
2819 
2820 bool TrackInfoDialog::keyPressEvent(QKeyEvent *event)
2821 {
2822  QStringList actions;
2823  bool handled = GetMythMainWindow()->TranslateKeyPress("Music", event, actions, false);
2824 
2825  for (int i = 0; i < actions.size() && !handled; i++)
2826  {
2827  QString action = actions[i];
2828  handled = true;
2829 
2830  if (action == "INFO")
2831  Close();
2832  if (action == "0")
2833  {
2834  // if it's available show the song ID
2835  MythUIText *songID = dynamic_cast<MythUIText *>(GetChild("songid"));
2836  if (songID)
2837  songID->Show();
2838  }
2839  else
2840  handled = false;
2841  }
2842 
2843  if (!handled && MythScreenType::keyPressEvent(event))
2844  handled = true;
2845 
2846  return handled;
2847 }
This widget is used for grouping other widgets for display when a particular named state is called.
static Type Info
Definition: output.h:63
virtual bool IsPaused(void) const =0
void decVolume(void)
MythUIButton * m_playButton
Definition: musiccommon.h:196
MusicMetadata * getSongAt(int pos) const
Definition: playlist.cpp:1086
QString m_whereClause
Definition: musiccommon.h:165
void setPlayMode(PlayMode mode)
int getCDTrackCount(void) const
void SetUsed(int value)
bool Create(void) override
void Show(void)
void toggleMute(void)
void byArtist(void)
void setShuffleMode(ShuffleMode mode)
void changeCurrentTrack(int trackNo)
change the current track to the given track
static void startPlayback(void)
MusicPlayer * gPlayer
Definition: musicplayer.cpp:35
uint getVolume(void) const
static void changeSpeed(bool up)
static Type MetadataChangedEvent
Definition: musicplayer.h:46
void sendTrackStatsChangedEvent(int trackID)
void doUpdatePlaylist(void)
virtual bool ToggleUpmix(void)
Definition: audiooutput.h:157
void switchVisualizer(const QString &visual)
MusicMetadata * getCurrentMetadata(void)
get the metadata for the current track in the playlist
void cycleVisualizer(void)
QStringList getPlaylistNames(void)
bool TranslateKeyPress(const QString &context, QKeyEvent *e, QStringList &actions, bool allowJumps=true)
Get a list of actions for a keypress in the given context.
void copyNewPlaylist(const QString &name)
Playlist * getCurrentPlaylist(void)
MythUIProgressBar * m_volProgress
Definition: musiccommon.h:231
MythMenu * createQuickPlaylistsMenu(void)
All purpose text widget, displays a text string.
Definition: mythuitext.h:28
void seekback(void)
RepeatMode toggleRepeatMode(void)
void removeListener(QObject *listener)
MythUIButton * m_prevButton
Definition: musiccommon.h:193
MythUIText * m_trackSpeedText
Definition: musiccommon.h:185
QHash< QString, QString > InfoMap
Definition: mythtypes.h:15
void removeVisual(MainVisual *visual)
static Type TrackAddedEvent
Definition: musicplayer.h:42
static Type Playing
Definition: output.h:61
void seek(int pos)
~MythMusicVolumeDialog(void) override
virtual void SetTimecode(int64_t timecode)=0
static void editTrackInfo(MusicMetadata *mdata)
MythUIText * m_volumeText
Definition: musiccommon.h:189
MusicView m_currentView
Definition: musiccommon.h:139
bool isStopped(void)
Definition: musicplayer.h:104
Image widget, displays a single image or multiple images in sequence.
Definition: mythuiimage.h:97
virtual void unlock(void)
Definition: decoder.h:81
uint32_t IdType
Definition: musicmetadata.h:86
void stopAll(void)
QString Genre() const
MythUIText * m_trackProgressText
Definition: musiccommon.h:184
Basic menu dialog, message and a list of options.
MusicCommon(MythScreenStack *parent, MythScreenType *parentScreen, const QString &name)
Definition: musiccommon.cpp:48
void showPlaylistOptionsMenu(bool addMainMenu=false)
PlayPLOption playPLOption
Definition: playlist.h:40
QString GetImageFilename(const QString &name="") const
PlaylistOptions m_playlistOptions
Definition: musiccommon.h:164
void customEvent(QEvent *event) override
Playlist * getActive(void)
bool setCurrentTrackPos(int pos)
void SetTextFromMap(const InfoMap &map)
Definition: mythuitext.cpp:158
void ShowMenu(void) override
virtual void SetText(const QString &text)
Definition: mythuitext.cpp:135
bool m_fullscreenBlank
Definition: musiccommon.h:143
bool isPlaying(void)
Definition: musicplayer.h:102
static void showVolume(void)
MythUIStateType * m_repeatState
Definition: musiccommon.h:177
int Length() const
MythScreenStack * GetStack(const QString &stackname)
void incVolume(void)
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
void addVisual(MainVisual *visual)
MythUIVideo * m_visualizerVideo
Definition: musiccommon.h:206
MythScreenStack * GetMainStack()
MythUIText * m_noTracksText
Definition: musiccommon.h:174
bool Create(void) override
void updateProgressBar(void)
MythUIButtonListItem * GetItemAt(int pos) const
static MythThemedMenu * menu
MythUIButton * m_nextButton
Definition: musiccommon.h:199
QString getName(void)
Definition: playlist.h:106
uint m_playlistMaxTime
Definition: musiccommon.h:161
MythUIStateType * m_ratingState
Definition: musiccommon.h:181
MythUIProgressBar * m_trackProgress
Definition: musiccommon.h:183
RepeatMode getRepeatMode(void)
Definition: musicplayer.h:180
bool Load(bool allowLoadInBackground=true, bool forceStat=false)
Load the image(s), wraps ImageLoader::LoadImage()
QStringList getVisualizations(void)
Definition: mainvisual.h:57
MythMenu * createVisualizerMenu(void)
void RemoveItem(MythUIButtonListItem *item)
MythUIText * m_volText
Definition: musiccommon.h:229
MythUIStateType * m_muteState
Definition: musiccommon.h:188
static Type Buffering
Definition: output.h:62
int Rating() const
Playlist * getPlaylist(int id)
static Type kEventType
Definition: mythdialogbox.h:56
static void setTrackOnLCD(MusicMetadata *mdata)
void SetImage(MythImage *image, const QString &name="")
Sets an image directly, should only be used in special circumstances since it bypasses the cache.
bool m_moveTrackMode
Definition: musiccommon.h:150
void updatePlaylistStats(void)
void changeVolume(bool up)
void byTitle(void)
static LCD * Get(void)
Definition: lcddevice.cpp:65
virtual void lock(void)
Definition: decoder.h:80
#define MUSICVOLUMEPOPUPTIME
MythUIButtonList * m_currentPlaylist
Definition: musiccommon.h:203
static Type TrackChangeEvent
Definition: musicplayer.h:40
void Hide(void)
virtual void Close()
QString Artist() const
MythUIButton * m_stopButton
Definition: musiccommon.h:197
void playlistItemClicked(MythUIButtonListItem *item)
void savePosition(void)
void updateVolume(void)
void fromCD(void)
virtual void SetVisible(bool visible)
virtual void AddScreen(MythScreenType *screen, bool allowFade=true)
void previous(void)
PlaylistContainer * m_all_playlists
Definition: musicdata.h:54
void previous(void)
void updateShuffleMode(bool updateUIList=false)
static QString getTimeString(int exTime, int maxTime)
QString toRawSonglist(bool shuffled=false, bool tracksOnly=false)
Definition: playlist.cpp:858
MusicView
Definition: musiccommon.h:30
void next(void)
MythMenu * createShuffleMenu(void)
MusicMetadata * getMetadata(int an_id)
static void show(uint8_t *buf, int length)
Definition: ringbuffer.c:318
unsigned int m_currentVisual
Definition: musiccommon.h:148
void updateRepeatMode(void)
PlayMode getPlayMode(void)
Definition: musicplayer.h:70
void showExitMenu(void)
void SetLocked(bool locked)
void next(void)
MythUIButtonList * m_playedTracksList
Definition: musiccommon.h:204
void stop(void)
MainVisual * m_mainvisual
Definition: musiccommon.h:142
int getTrackCount(void)
Definition: playlist.h:82
void byAlbum(void)
static void play(void)
uint m_playlistTrackCount
Definition: musiccommon.h:159
void updateTrackInfo(MusicMetadata *mdata)
QString GetSetting(const QString &key, const QString &defaultval="")
IdType ID() const
MythMenu * createMainMenu(void)
void fillSonglistFromQuery(const QString &whereClause, bool removeDuplicates=false, InsertPLOption insertOption=PL_REPLACE, int currentTrackID=0)
Definition: playlist.cpp:693
QList< MusicMetadata * > & getPlayedTracksList(void)
Definition: musicplayer.h:130
void Reset(void) override
Reset the widget to it's original state, should not reset changes made by the theme.
Definition: mythuitext.cpp:83
MythUIButton * m_rewButton
Definition: musiccommon.h:194
bool isRunning(void) const
Definition: mthread.cpp:274
void getBufferStatus(int *bufferAvailable, int *bufferSize)
MythUIButton * m_pauseButton
Definition: musiccommon.h:195
MythUIText * m_timeText
Definition: musiccommon.h:171
bool isMuted(void) const
Definition: musicplayer.h:82
QString getAlbumArtFile(void)
void SetTotal(int value)
void Reset(void) override
Reset the image back to the default defined in the theme.
void changed(void)
Definition: playlist.cpp:989
virtual void SetTextFromMap(const InfoMap &infoMap)
static Type TrackRemovedEvent
Definition: musicplayer.h:43
bool m_movingTrack
Definition: musiccommon.h:151
static Type TrackUnavailableEvent
Definition: musicplayer.h:44
MythScreenType * m_parentScreen
Definition: musiccommon.h:138
static bool Assign(ContainerType *container, UIType *&item, const QString &name, bool *err=nullptr)
Definition: mythuiutils.h:27
void pause(void)
MythUIText * m_visualText
Definition: musiccommon.h:173
bool keyPressEvent(QKeyEvent *event) override
Key event handler.
MusicMetadata * m_metadata
Definition: musiccommon.h:247
bool Create(void) override
void SetText(const QString &text, const QString &name="", const QString &state="")
unsigned int uint
Definition: compat.h:140
QString Album() const
int getID(void)
Definition: playlist.h:111
void searchButtonList(void)
ShuffleMode toggleShuffleMode(void)
bool m_cycleVisualizer
Definition: musiccommon.h:144
bool MoveUpDown(bool flag)
void viewExited(void)
void updateUIPlaylist(void)
void byGenre(void)
virtual void seek(double)=0
void stop(bool stopAll=false)
static bool LoadWindowFromXML(const QString &xmlfile, const QString &windowname, MythUIType *parent)
static void showSpeed(bool show)
MythUIType * GetFocusWidget(void) const
MythUIStateType * m_trackState
Definition: musiccommon.h:186
int m_currentTime
Definition: musiccommon.h:156
void Reset() override
Reset the widget to it's original state, should not reset changes made by the theme.
MythMainWindow * GetMythMainWindow(void)
void startVisualizer(void)
QString GetText(const QString &name="") const
MythUIImage * m_coverartImage
Definition: musiccommon.h:201
void setAllowRestorePos(bool allow)
Definition: musicplayer.h:143
int getCurrentVisual(void)
Definition: mainvisual.h:59
void play(void)
MythUIStateType * m_muteState
Definition: musiccommon.h:230
bool keyPressEvent(QKeyEvent *event) override
Key event handler.
void restorePosition(void)
MythMenu * createRepeatMenu(void)
Dialog prompting the user to enter a text string.
void byYear(void)
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
int Year() const
bool m_randomVisualizer
Definition: musiccommon.h:145
ShuffleMode getShuffleMode(void)
Definition: musicplayer.h:184
static Type AllTracksRemovedEvent
Definition: musicplayer.h:45
uint m_playlistPlayedTime
Definition: musiccommon.h:160
static void playlistItemVisible(MythUIButtonListItem *item)
void addListener(QObject *listener)
MythMenu * createPlayerMenu(void)
static void changeRating(bool increase)
QStringList m_visualModes
Definition: musiccommon.h:147
MythUIProgressBar * m_playlistProgress
Definition: musiccommon.h:191
bool GetBoolSetting(const QString &key, bool defaultval=false)
QMutex * mutex()
Definition: visual.h:25
void prepare(void) override
Definition: mainvisual.cpp:139
int getCurrentTrackPos(void)
Definition: musicplayer.h:132
MythUIStateType * m_shuffleState
Definition: musiccommon.h:176
QString Title() const
void SetFilename(const QString &filename)
Must be followed by a call to Load() to load the image.
bool isPaused(void)
Definition: musicplayer.h:103
void fillSongsFromSonglist(const QString &songList)
Definition: playlist.cpp:648
void updateUIPlayedList(void)
void init(bool startPlayback=true)
bool keyPressEvent(QKeyEvent *event) override
Key event handler.
MythUIText * m_infoText
Definition: musiccommon.h:172
static void pause(void)
void SetLockable(bool lockable)
Definition: mythuibutton.h:39
void SetFontState(const QString &state, const QString &name="")
void getStats(uint *trackCount, uint *totalLength, uint currentTrack=0, uint *playedLength=nullptr) const
Definition: playlist.cpp:508
void stopVisualizer(void)
bool DisplayState(const QString &name)
MusicData * gMusicData
Definition: musicdata.cpp:20
void toMap(InfoMap &infoMap)
MusicMetadata * getCDMetadata(int m_the_track)
Definition: lcddevice.h:169
bool m_controlVolume
Definition: musiccommon.h:153
MythMenu * createSubMenu(void)
InsertPLOption insertPLOption
Definition: playlist.h:39
QList< int > m_songList
Definition: musiccommon.h:168
void allTracks(void)
void SetItemCurrent(MythUIButtonListItem *item)
QString formattedFieldValue(const QVariant &value)
void playlistChanged(int playlistID)
void removeTrack(int trackID)
void moveTrackUpDown(bool moveUp, int whichTrack)
static long int random(void)
Definition: compat.h:149
~MusicCommon(void) override
Definition: musiccommon.cpp:63
void fillSonglistFromList(const QList< int > &songList, bool removeDuplicates, InsertPLOption insertOption, int currentTrackID)
Definition: playlist.cpp:789
void toggleMute(void)
MythUIStateType * m_movingTracksState
Definition: musiccommon.h:179
Decoder * getDecoder(void)
Definition: musicplayer.h:115
bool restorePosition(int trackID)
AudioOutput * getOutput(void)
Definition: musicplayer.h:117
Screen in which all other widgets are contained and rendered.
static void showTrackInfo(MusicMetadata *mdata)
int GetCurrentPos() const
MythMenu * createPlaylistOptionsMenu(void)
static void playFirstTrack()
void removeAllTracks(void)
Definition: playlist.cpp:87
void setVisual(const QString &name)
Definition: mainvisual.cpp:81
static Type VolumeChangeEvent
Definition: musicplayer.h:41
void switchToMusic(const QString &artist, const QString &album, const QString &track)
Definition: lcddevice.cpp:563
int m_currentTrack
Definition: musiccommon.h:155
MusicMetadata * getNextMetadata(void)
get the metadata for the next track in the playlist
virtual void ResetMap(const InfoMap &infoMap)
static Type Paused
Definition: output.h:64
void SetSearchFields(const QString &fields)
static Type AlbumArtChangedEvent
Definition: musicplayer.h:48
MythUIType * GetChild(const QString &name) const
Get a named child of this UIType.
Definition: mythuitype.cpp:130
void DisplayState(const QString &state, const QString &name)
void Push(bool lock=false)
void SetTextFromMap(const InfoMap &infoMap, const QString &state="")
MythUIButton * m_ffButton
Definition: musiccommon.h:198
void switchView(MusicView view)
void activePlaylistChanged(int trackID, bool deleted)
void toMap(InfoMap &metadataMap, const QString &prefix="")
void seekforward(void)
static Type TrackStatsChangedEvent
Definition: musicplayer.h:47
void setRepeatMode(RepeatMode mode)
Definition: musicplayer.h:181
bool keyPressEvent(QKeyEvent *e) override
Key event handler.
AllMusic * m_all_music
Definition: musicdata.h:55
bool CreateCommon(void)
Definition: musiccommon.cpp:81
Provide a dialog to quickly find an entry in a list.
MythUIButtonListItem * GetItemCurrent() const
static Type Stopped
Definition: output.h:65
MythMenu * createPlaylistMenu(void)
static void toggleUpmix(void)