MythTV master
musiccommon.cpp
Go to the documentation of this file.
1// C++ includes
2#include <cstdlib>
3#include <iostream>
4
5// Qt includes
6#include <QApplication>
7#include <QLocale>
8
9// mythtv
27
28// MythMusic includes
29#include "constants.h"
30#include "decoder.h"
31#include "editmetadata.h"
32#include "lyricsview.h"
33#include "mainvisual.h"
34#include "musiccommon.h"
35#include "musicdata.h"
36#include "playlist.h"
37#include "playlistcontainer.h"
38#include "playlisteditorview.h"
39#include "playlistview.h"
40#include "search.h"
41#include "searchview.h"
42#include "smartplaylist.h"
43#include "streamview.h"
44#include "visualizerview.h"
45
47 const QString &name)
48 : MythScreenType(parent, name),
49 m_parentScreen(parentScreen)
50{
51 m_cycleVisualizer = gCoreContext->GetBoolSetting("VisualCycleOnSongChange", false);
52
53 if (LCD *lcd = LCD::Get())
54 {
55 lcd->switchToTime();
56 lcd->setFunctionLEDs(FUNC_MUSIC, true);
57 }
58}
59
61{
63
64 if (m_mainvisual)
65 {
67 delete m_mainvisual;
68 m_mainvisual = nullptr;
69 }
70
71 if (LCD *lcd = LCD::Get())
72 {
73 lcd->switchToTime();
74 lcd->setFunctionLEDs(FUNC_MUSIC, false);
75 }
76}
77
79{
80 bool err = false;
81 UIUtilW::Assign(this, m_timeText, "time", &err);
82 UIUtilW::Assign(this, m_infoText, "info", &err);
83 UIUtilW::Assign(this, m_visualText, "visualizername", &err);
84 UIUtilW::Assign(this, m_noTracksText, "notracks", &err);
85
86 UIUtilW::Assign(this, m_shuffleState, "shufflestate", &err);
87 UIUtilW::Assign(this, m_repeatState, "repeatstate", &err);
88 UIUtilW::Assign(this, m_movingTracksState, "movingtracksstate", &err);
89
90 UIUtilW::Assign(this, m_ratingState, "ratingstate", &err);
91
92 UIUtilW::Assign(this, m_trackProgress, "progress", &err);
93 UIUtilW::Assign(this, m_trackProgressText, "trackprogress", &err);
94 UIUtilW::Assign(this, m_trackSpeedText, "trackspeed", &err);
95 UIUtilW::Assign(this, m_trackState, "trackstate", &err);
96
97 UIUtilW::Assign(this, m_volumeText, "volume", &err);
98 UIUtilW::Assign(this, m_muteState, "mutestate", &err);
99
100 UIUtilW::Assign(this, m_playlistProgress, "playlistprogress", &err);
101
102 UIUtilW::Assign(this, m_prevButton, "prev", &err);
103 UIUtilW::Assign(this, m_rewButton, "rew", &err);
104 UIUtilW::Assign(this, m_pauseButton, "pause", &err);
105 UIUtilW::Assign(this, m_playButton, "play", &err);
106 UIUtilW::Assign(this, m_stopButton, "stop", &err);
107 UIUtilW::Assign(this, m_ffButton, "ff", &err);
108 UIUtilW::Assign(this, m_nextButton, "next", &err);
109
110 UIUtilW::Assign(this, m_coverartImage, "coverart", &err);
111
112 UIUtilW::Assign(this, m_currentPlaylist, "currentplaylist", &err);
113 UIUtilW::Assign(this, m_playedTracksList, "playedtrackslist", &err);
114
115 UIUtilW::Assign(this, m_visualizerVideo, "visualizer", &err);
116
117 if (m_prevButton)
119
120 if (m_rewButton)
122
123 if (m_pauseButton)
124 {
127 }
128
129 if (m_playButton)
130 {
133 }
134
135 if (m_stopButton)
136 {
139 }
140
141 if (m_ffButton)
143
144 if (m_nextButton)
146
148 {
153
154 m_currentPlaylist->SetSearchFields("**search**");
155 }
156
157 init();
158
159 return err;
160}
161
163{
164 gPlayer->addListener(this);
165
166 if (startPlayback)
167 {
168 if (!gPlayer->isPlaying())
169 {
171 m_currentView == MV_VISUALIZERINFO) // keep playmode
173 else 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
220
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())
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
277 {
280 }
281
283
285}
286
288{
289 if (m_repeatState)
290 {
291 switch (gPlayer->getRepeatMode())
292 {
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;
305 if (class LCD *lcd = LCD::Get())
306 lcd->setMusicRepeat (LCD::MUSIC_REPEAT_ALL);
307 break;
308 default:
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
322void 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;
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
437
438 if (m_mainvisual)
439 {
440 delete m_mainvisual;
441 m_mainvisual = nullptr;
442 }
443
444 gPlayer->removeListener(this);
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, &MythScreenType::Exiting, this, &MusicCommon::viewExited);
457 }
458 else
459 {
460 delete plview;
461 }
462
463 break;
464 }
465
467 {
468 // if we are switching playlist editor views save and restore
469 // the current position in the tree
470 bool restorePos = (m_currentView == MV_PLAYLISTEDITORGALLERY);
471 auto *oldView = qobject_cast<PlaylistEditorView *>(this);
472 if (oldView)
473 oldView->saveTreePosition();
474
475 MythScreenType *parentScreen = (oldView != nullptr ? m_parentScreen : this);
476
477 auto *pleview = new PlaylistEditorView(mainStack, parentScreen, "tree", restorePos);
478
479 if (pleview->Create())
480 {
481 mainStack->AddScreen(pleview);
482 connect(pleview, &MythScreenType::Exiting, this, &MusicCommon::viewExited);
483 }
484 else
485 {
486 delete pleview;
487 }
488
489 if (oldView)
490 Close();
491
492 break;
493 }
494
496 {
497 // if we are switching playlist editor views save and restore
498 // the current position in the tree
499 bool restorePos = (m_currentView == MV_PLAYLISTEDITORTREE);
500 auto *oldView = qobject_cast<PlaylistEditorView *>(this);
501 if (oldView)
502 oldView->saveTreePosition();
503
504 MythScreenType *parentScreen = (oldView != nullptr ? m_parentScreen : this);
505
506 auto *pleview = new PlaylistEditorView(mainStack, parentScreen, "gallery", restorePos);
507
508 if (pleview->Create())
509 {
510 mainStack->AddScreen(pleview);
511 connect(pleview, &MythScreenType::Exiting, this, &MusicCommon::viewExited);
512 }
513 else
514 {
515 delete pleview;
516 }
517
518 if (oldView)
519 Close();
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, &MythScreenType::Exiting, this, &MusicCommon::viewExited);
532 }
533 else
534 {
535 delete sview;
536 }
537
538 break;
539 }
540
541 case MV_VISUALIZER:
542 {
543 auto *vview = new VisualizerView(mainStack, this);
544
545 if (vview->Create())
546 {
547 mainStack->AddScreen(vview);
548 connect(vview, &MythScreenType::Exiting, this, &MusicCommon::viewExited);
549 }
550 else
551 {
552 delete vview;
553 }
554
555 break;
556 }
557
558 case MV_LYRICS:
559 {
560 auto *lview = new LyricsView(mainStack, this);
561
562 if (lview->Create())
563 {
564 mainStack->AddScreen(lview);
565 connect(lview, &MythScreenType::Exiting, this, &MusicCommon::viewExited);
566 }
567 else
568 {
569 delete lview;
570 }
571
572 break;
573 }
574
575 default:
576 break;
577 }
578
580}
581
583{
584 init(false);
585}
586
588{
589 bool handled = false;
590
591 // if there is a pending jump point pass the key press to the default handler
592 if (GetMythMainWindow()->IsExitingToMain())
593 {
595
596 // do we need to stop playing?
597 if (gPlayer->isPlaying() && gCoreContext->GetSetting("MusicJumpPointAction", "stop") == "stop")
598 gPlayer->stop(true);
599
601 }
602
603 QStringList actions;
604 handled = GetMythMainWindow()->TranslateKeyPress("Music", e, actions, true);
605
606 for (int i = 0; i < actions.size() && !handled; i++)
607 {
608 const QString& action = actions[i];
609 handled = true;
610
611 // if we are currently moving an item,
612 // we only accept UP/DOWN/SELECT/ESCAPE
614 {
616 if (!item)
617 return false;
618
619 if (action == "SELECT" || action == "ESCAPE")
620 {
621 m_movingTrack = false;
622 item->DisplayState("off", "movestate");
623 }
624 else if (action == "UP")
625 {
627 item->MoveUpDown(true);
634 }
635 else if (action == "DOWN")
636 {
638 item->MoveUpDown(false);
645 }
646
647 return true;
648 }
649
650 if (action == "ESCAPE")
651 {
652 // if we was started from another music view screen return to it
653 if (m_parentScreen)
654 {
655 handled = false;
656 }
657 else
658 {
659 // this is the top music view screen so prompt to continue playing
660 QString exit_action = gCoreContext->GetSetting("MusicExitAction", "prompt");
661
662 if (!gPlayer->isPlaying())
663 {
665 stopAll();
666 Close();
667 }
668 else
669 {
670 if (exit_action == "stop")
671 {
673 stopAll();
674 Close();
675 }
676 else if (exit_action == "play")
677 {
678 Close();
679 }
680 else
681 {
682 showExitMenu();
683 }
684 }
685 }
686 }
687 else if (action == "THMBUP")
688 {
689 changeRating(true);
690 }
691 else if (action == "THMBDOWN")
692 {
693 changeRating(false);
694 }
695 else if (action == "NEXTTRACK")
696 {
697 if (m_nextButton)
699 else
700 next();
701 }
702 else if (action == "PREVTRACK")
703 {
704 if (m_prevButton)
706 else
707 previous();
708 }
709 else if (action == "FFWD")
710 {
712 {
713 if (m_ffButton)
714 m_ffButton->Push();
715 else
716 seekforward();
717 }
718 }
719 else if (action == "RWND")
720 {
722 {
723 if (m_rewButton)
724 m_rewButton->Push();
725 else
726 seekback();
727 }
728 }
729 else if (action == "PAUSE")
730 {
732 {
733 // ignore if we are already playing a radio stream
734 }
735 else if (gPlayer->isPlaying() || (gPlayer->getOutput() && gPlayer->getOutput()->IsPaused()))
736 {
737 // if we are playing or are paused PAUSE will toggle the pause state
738 if (m_pauseButton)
740 else
741 pause();
742 }
743 else
744 {
745 // not playing or paused so PAUSE acts the same as PLAY
746 if (m_playButton)
748 else
749 play();
750 }
751 }
752 else if (action == "PLAY")
753 {
754 if (m_playButton)
756 else
757 play();
758 }
759 else if (action == "STOP")
760 {
761 if (m_stopButton)
763 else
764 stop();
765 m_currentTime = 0s;
766 }
767 else if (action == "CYCLEVIS")
768 {
770 }
771 else if (action == "BLANKSCR")
772 {
773 // change to the blank visualizer
774 if (m_mainvisual)
775 switchVisualizer("Blank");
776
777 // switch to the full screen visualiser view
780 }
781 else if (action == "VOLUMEDOWN")
782 {
783 changeVolume(false);
784 }
785 else if (action == "VOLUMEUP")
786 {
787 changeVolume(true);
788 }
789 else if (action == "SPEEDDOWN")
790 {
791 changeSpeed(false);
792 }
793 else if (action == "SPEEDUP")
794 {
795 changeSpeed(true);
796 }
797 else if (action == "MUTE")
798 {
799 toggleMute();
800 }
801 else if (action == "TOGGLEUPMIX")
802 {
803 toggleUpmix();
804 }
805 else if (action == "INFO" || action == "EDIT")
806 {
808 {
810 {
811 auto *mdata = m_currentPlaylist->GetItemCurrent()->GetData().value<MusicMetadata*>();
812 if (mdata)
813 {
814 if (action == "INFO")
815 showTrackInfo(mdata);
816 else
817 editTrackInfo(mdata);
818 }
819 }
820 }
821 else
822 {
823 if (action == "INFO")
825 else
827 }
828 }
829 else if (action == "DELETE" && m_currentPlaylist && GetFocusWidget() == m_currentPlaylist)
830 {
832 if (item)
833 {
834 auto *mdata = item->GetData().value<MusicMetadata*>();
835 if (mdata)
836 gPlayer->removeTrack(mdata->ID());
837 }
838 }
839 else if (action == "MENU")
840 {
841 ShowMenu();
842 }
843 else if (action == "REFRESH")
844 {
847 }
848 else if (action == "MARK")
849 {
850 if (!m_moveTrackMode)
851 {
852 m_moveTrackMode = true;
853 m_movingTrack = false;
854
857 }
858 else
859 {
860 m_moveTrackMode = false;
861
863 {
865 if (item)
866 item->DisplayState("off", "movestate");
867
868 m_movingTrack = false;
869 }
870
873 }
874 }
875 else if (action == "SWITCHTOPLAYLIST" && m_currentView != MV_PLAYLIST)
876 {
878 }
879 else if (action == "SWITCHTOPLAYLISTEDITORTREE" && m_currentView != MV_PLAYLISTEDITORTREE)
880 {
882 }
883 else if (action == "SWITCHTOPLAYLISTEDITORGALLERY" && m_currentView != MV_PLAYLISTEDITORGALLERY)
884 {
886 }
887 else if (action == "SWITCHTOSEARCH" && m_currentView != MV_SEARCH)
888 {
890 }
891 else if (action == "SWITCHTOVISUALISER" && m_currentView != MV_VISUALIZER)
892 {
894 }
895 else if (action == "SWITCHTORADIO" && m_currentView != MV_RADIO)
896 {
898 }
899 else if (action == "TOGGLESHUFFLE")
900 {
902 updateShuffleMode(true);
903 }
904 else if (action == "TOGGLEREPEAT")
905 {
908 }
909 else
910 {
911 handled = false;
912 }
913 }
914
915 if (!handled && MythScreenType::keyPressEvent(e))
916 handled = true;
917 return handled;
918}
919
920void MusicCommon::changeVolume(bool up) const
921{
923 {
924 if (up)
926 else
928 showVolume();
929 }
930}
931
933{
935 {
936 if (up)
937 gPlayer->incSpeed();
938 else
939 gPlayer->decSpeed();
940 showSpeed(true);
941 updatePlaylistStats(); // update trackspeed and map for templates
942 }
943}
944
946{
947 if (m_controlVolume)
948 {
950 showVolume();
951 }
952}
953
955{
956 if (gPlayer->getOutput())
958}
959
961{
962 if (!m_trackProgress)
963 return;
964
966 {
967 // radio mode so show the buffer fill level since we don't know the track length
968 int available = 0;
969 int maxSize = 0;
970 gPlayer->getBufferStatus(&available, &maxSize);
971
972 if (m_infoText)
973 {
974 QString status = QString("%1%").arg((int)(100.0 / ((double)maxSize / (double)available)));
975 m_infoText->SetText(status);
976 }
977
978 if (m_trackProgress)
979 {
980 m_trackProgress->SetTotal(maxSize);
981 m_trackProgress->SetUsed(available);
982 }
983 }
984 else
985 {
986 // show the track played time
987 int percentplayed = 1;
988 if (m_maxTime > 0s)
989 percentplayed = m_currentTime * 100 / m_maxTime;
991 m_trackProgress->SetUsed(percentplayed);
992 }
993}
994
996{
997 MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
998
999 auto *vol = new MythMusicVolumeDialog(popupStack, "volumepopup");
1000
1001 if (!vol->Create())
1002 {
1003 delete vol;
1004 return;
1005 }
1006
1007 popupStack->AddScreen(vol);
1008}
1009
1010void MusicCommon::showSpeed([[maybe_unused]] bool show)
1011{
1012}
1013
1014void MusicCommon::switchVisualizer(const QString &visual)
1015{
1016 switchVisualizer(m_visualModes.indexOf(visual));
1017}
1018
1020{
1021 if (!m_mainvisual)
1022 return;
1023
1024 if (visual < 0 || visual > m_visualModes.count() - 1)
1025 visual = 0;
1026
1027 m_currentVisual = visual;
1028
1030
1031 if (m_visualText)
1033}
1034
1036{
1037 if (!m_mainvisual)
1038 return;
1039
1040 // Only change the visualizer if there is more than 1 visualizer
1041 // and the user currently has a visualizer active
1042 if (m_visualModes.count() > 1)
1043 {
1045 {
1046 unsigned int next_visualizer = m_currentVisual;
1047
1048 //Find a visual thats not like the previous visual
1049 while (next_visualizer == m_currentVisual)
1050 next_visualizer = MythRandom(0, m_visualModes.count() - 1);
1051 m_currentVisual = next_visualizer;
1052 }
1053 else
1054 {
1055 //Change to the next selected visual
1057 }
1058
1059 //Change to the new visualizer
1061 }
1062}
1063
1065{
1067 return;
1068
1070}
1071
1073{
1075 return;
1076
1078}
1079
1081{
1082 LCD *lcd = LCD::Get();
1083 if (!lcd || !mdata)
1084 return;
1085
1086 // Set the Artist and Tract on the LCD
1087 lcd->switchToMusic(mdata->Artist(),
1088 mdata->Album(),
1089 mdata->Title());
1090}
1091
1093{
1094 if (LCD *lcd = LCD::Get())
1095 {
1096 lcd->switchToTime();
1097 }
1098
1100
1101 gPlayer->stop(true);
1102}
1103
1105{
1106 gPlayer->play();
1107}
1108
1110{
1111 gPlayer->pause();
1112}
1113
1115{
1116 gPlayer->stop();
1117
1118 if (m_timeText)
1120 if (m_infoText)
1121 m_infoText->Reset();
1122}
1123
1125{
1128
1129
1130 gPlayer->next();
1131}
1132
1134{
1137
1138 gPlayer->previous();
1139}
1140
1142{
1143 std::chrono::seconds nextTime = m_currentTime + 5s;
1144 nextTime = std::clamp(nextTime, 0s, m_maxTime);
1145 seek(nextTime);
1146}
1147
1149{
1150 // I don't know why, but seeking before 00:05 fails. Repeated
1151 // rewind under 00:05 can hold time < 5s while the music plays.
1152 // Time starts incrementing from zero but is now several seconds
1153 // behind. Finishing a track after this records a truncated
1154 // length. We can workaround this by limiting rewind to 1s.
1155 std::chrono::seconds nextTime = m_currentTime - 5s;
1156 nextTime = std::clamp(nextTime, 1s, m_maxTime); // #787
1157 seek(nextTime);
1158}
1159
1160void MusicCommon::seek(std::chrono::seconds pos)
1161{
1162 if (gPlayer->getOutput())
1163 {
1164 Decoder *decoder = gPlayer->getDecoder();
1165 if (decoder && decoder->isRunning())
1166 {
1167 decoder->lock();
1168 decoder->seek(pos.count());
1169
1170 if (m_mainvisual)
1171 {
1172 m_mainvisual->mutex()->lock();
1174 m_mainvisual->mutex()->unlock();
1175 }
1176
1177 decoder->unlock();
1178 }
1179
1180 gPlayer->getOutput()->SetTimecode(pos);
1181
1182 if (!gPlayer->isPlaying())
1183 {
1184 m_currentTime = pos;
1185 if (m_timeText)
1187
1189
1190 if (LCD *lcd = LCD::Get())
1191 {
1192 float percent_heard = m_maxTime <= 0s ? 0.0F : ((float)pos.count() /
1193 (float)m_maxTime.count());
1194
1195 QString lcd_time_string = getTimeString(pos, m_maxTime);
1196
1197 // if the string is longer than the LCD width, remove all spaces
1198 if (lcd_time_string.length() > lcd->getLCDWidth())
1199 lcd_time_string.remove(' ');
1200
1201 lcd->setMusicProgress(lcd_time_string, percent_heard);
1202 }
1203 }
1204 }
1205}
1206
1207void MusicCommon::changeRating(bool increase)
1208{
1210 return;
1211
1212 // Rationale here is that if you can't get visual feedback on ratings
1213 // adjustments, you probably should not be changing them
1214 // TODO: should check if the rating is visible in the playlist buttontlist
1215 //if (!m_ratingState)
1216 // return;
1217
1219 if (!curMeta)
1220 return;
1221
1222
1223 if (increase)
1224 curMeta->incRating();
1225 else
1226 curMeta->decRating();
1227
1229}
1230
1231void MusicCommon::customEvent(QEvent *event)
1232{
1233 QString statusString;
1234
1235 if (event->type() == OutputEvent::kPlaying)
1236 {
1238 if (curMeta)
1239 updateTrackInfo(curMeta);
1240
1241 statusString = tr("Playing stream.");
1242 if (gPlayer->isPlaying())
1243 {
1244 if (m_stopButton)
1245 m_stopButton->SetLocked(false);
1246 if (m_playButton)
1247 m_playButton->SetLocked(true);
1248 if (m_pauseButton)
1249 m_pauseButton->SetLocked(false);
1250 if (m_trackState)
1251 m_trackState->DisplayState("playing");
1252
1254 {
1256 if (item)
1257 {
1258 item->SetFontState("running");
1259 item->DisplayState("playing", "playstate");
1260 }
1261 }
1262
1264
1265 updateVolume();
1266 }
1267 }
1268 else if (event->type() == OutputEvent::kBuffering)
1269 {
1270 statusString = tr("Buffering stream.");
1271 }
1272 else if (event->type() == OutputEvent::kPaused)
1273 {
1274 statusString = tr("Stream paused.");
1275
1276 if (m_stopButton)
1277 m_stopButton->SetLocked(false);
1278 if (m_playButton)
1279 m_playButton->SetLocked(false);
1280 if (m_pauseButton)
1281 m_pauseButton->SetLocked(true);
1282 if (m_trackState)
1283 m_trackState->DisplayState("paused");
1284
1286 {
1288 if (item)
1289 {
1290 item->SetFontState("idle");
1291 item->DisplayState("paused", "playstate");
1292 }
1293 }
1294 }
1295 else if (event->type() == OutputEvent::kInfo)
1296 {
1297
1298 auto *oe = dynamic_cast<OutputEvent *>(event);
1299
1300 if (!oe)
1301 return;
1302
1303 std::chrono::seconds rs = 0s;
1305
1307 {
1308 if (curMeta)
1309 m_currentTime = rs = duration_cast<std::chrono::seconds>(curMeta->Length());
1310 else
1311 m_currentTime = 0s;
1312 }
1313 else
1314 {
1315 m_currentTime = rs = oe->elapsedSeconds();
1316 }
1317
1318 QString time_string = getTimeString(rs, m_maxTime);
1319
1321
1322 if (curMeta)
1323 {
1324 if (LCD *lcd = LCD::Get())
1325 {
1326 float percent_heard = m_maxTime <= 0s ?
1327 0.0F:((float)rs.count() / (float)curMeta->Length().count()) * 1000.0F;
1328
1329 QString lcd_time_string = time_string;
1330
1331 // if the string is longer than the LCD width, remove all spaces
1332 if (time_string.length() > lcd->getLCDWidth())
1333 lcd_time_string.remove(' ');
1334
1335 lcd->setMusicProgress(lcd_time_string, percent_heard);
1336 }
1337 }
1338
1339 QString info_string;
1340
1341 // Hack around for cd bitrates
1342 if (oe->bitrate() < 2000)
1343 {
1344 info_string = QString("%1 "+tr("kbps")+ " %2 "+ tr("kHz")+ " %3 "+ tr("ch"))
1345 .arg(oe->bitrate())
1346 .arg(static_cast<double>(oe->frequency()) / 1000.0,0,'f',1,QChar('0'))
1347 .arg(oe->channels() > 1 ? "2" : "1");
1348 }
1349 else
1350 {
1351 info_string = QString("%1 "+ tr("kHz")+ " %2 "+ tr("ch"))
1352 .arg(static_cast<double>(oe->frequency()) / 1000.0,0,'f',1,QChar('0'))
1353 .arg(oe->channels() > 1 ? "2" : "1");
1354 }
1355
1356 if (curMeta)
1357 {
1358 if (m_timeText)
1359 m_timeText->SetText(time_string);
1360 if (m_infoText)
1361 m_infoText->SetText(info_string);
1362 }
1363
1364 // TODO only need to update the playlist times here
1366 }
1367 else if (event->type() == OutputEvent::kStopped)
1368 {
1369 statusString = tr("Stream stopped.");
1370 if (m_stopButton)
1371 m_stopButton->SetLocked(true);
1372 if (m_playButton)
1373 m_playButton->SetLocked(false);
1374 if (m_pauseButton)
1375 m_pauseButton->SetLocked(false);
1376 if (m_trackState)
1377 m_trackState->DisplayState("stopped");
1378
1380 {
1382 if (item)
1383 {
1384 item->SetFontState("normal");
1385 item->DisplayState("stopped", "playstate");
1386 }
1387 }
1388
1390 }
1391 else if (event->type() == DialogCompletionEvent::kEventType)
1392 {
1393 auto *dce = dynamic_cast<DialogCompletionEvent*>(event);
1394
1395 // make sure the user didn't ESCAPE out of the menu
1396 if ((dce == nullptr) || (dce->GetResult() < 0))
1397 return;
1398
1399 QString resultid = dce->GetId();
1400 QString resulttext = dce->GetResultText();
1401
1402 if (resultid == "mainmenu")
1403 {
1404 if (resulttext == tr("Fullscreen Visualizer"))
1406 else if (resulttext == tr("Playlist Editor") ||
1407 resulttext == tr("Browse Music Library"))
1408 {
1409 if (gCoreContext->GetSetting("MusicPlaylistEditorView", "tree") == "tree")
1411 else
1413 }
1414 else if (resulttext == tr("Search for Music"))
1415 {
1417 }
1418 else if (resulttext == tr("Switch To Gallery View"))
1419 {
1421 }
1422 else if (resulttext == tr("Switch To Tree View"))
1423 {
1425 }
1426 else if (resulttext == tr("Lyrics"))
1427 {
1429 }
1430 }
1431 else if (resultid == "submenu")
1432 {
1433 if (resulttext == tr("Search List..."))
1435 }
1436 else if (resultid == "playlistmenu")
1437 {
1438 if (resulttext == tr("Sync List With Current Track"))
1439 {
1441 }
1442 else if (resulttext == tr("Remove Selected Track"))
1443 {
1445 if (item)
1446 {
1447 auto *mdata = item->GetData().value<MusicMetadata*>();
1448 if (mdata)
1449 gPlayer->removeTrack(mdata->ID());
1450 }
1451 }
1452 else if (resulttext == tr("Remove All Tracks"))
1453 {
1455 {
1457 gPlayer->activePlaylistChanged(-1, true);
1458 }
1459 }
1460 else if (resulttext == tr("Save To New Playlist"))
1461 {
1462 QString message = tr("Enter new playlist name");
1463
1464 MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
1465
1466 auto *inputdialog = new MythTextInputDialog(popupStack, message);
1467
1468 if (inputdialog->Create())
1469 {
1470 inputdialog->SetReturnEvent(this, "addplaylist");
1471 popupStack->AddScreen(inputdialog);
1472 }
1473 else
1474 {
1475 delete inputdialog;
1476 }
1477 }
1478 else if (resulttext == tr("Save To Existing Playlist"))
1479 {
1480 QString message = tr("Select the playlist to save to");
1481 QStringList playlists = gMusicData->m_all_playlists->getPlaylistNames();
1482
1483 MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
1484
1485 auto *searchdialog = new MythUISearchDialog(popupStack, message, playlists);
1486
1487 if (searchdialog->Create())
1488 {
1489 searchdialog->SetReturnEvent(this, "updateplaylist");
1490 popupStack->AddScreen(searchdialog);
1491 }
1492 }
1493 else if (resulttext == tr("Switch To Move Mode"))
1494 {
1495 m_moveTrackMode = true;
1496 m_movingTrack = false;
1497
1500 }
1501 else if (resulttext == tr("Switch To Select Mode"))
1502 {
1503 m_moveTrackMode = false;
1504
1506 {
1508 if (item)
1509 item->DisplayState("off", "movestate");
1510
1511 m_movingTrack = false;
1512 }
1513
1516 }
1517 }
1518 else if (resultid == "repeatmenu")
1519 {
1520 int mode = dce->GetData().toInt();
1523 }
1524 else if (resultid == "shufflemenu")
1525 {
1526 int mode = dce->GetData().toInt();
1528 updateShuffleMode(true);
1529 }
1530 else if (resultid == "exitmenu")
1531 {
1532 if (resulttext == tr("No - Exit, Stop Playing"))
1533 {
1535 stopAll();
1536 Close();
1537 }
1538 else if (resulttext == tr("Yes - Exit, Continue Playing"))
1539 {
1540 Close();
1541 }
1542 }
1543 else if (resultid == "playermenu")
1544 {
1545 if (resulttext == tr("Change Volume"))
1546 showVolume();
1547 else if (resulttext == tr("Mute"))
1548 toggleMute();
1549 else if (resulttext == tr("Previous Track"))
1550 previous();
1551 else if (resulttext == tr("Next Track"))
1552 next();
1553 else if (resulttext == tr("Jump Back"))
1554 seekback();
1555 else if (resulttext == tr("Jump Forward"))
1556 seekforward();
1557 else if (resulttext == tr("Play"))
1558 play();
1559 else if (resulttext == tr("Stop"))
1560 stop();
1561 else if (resulttext == tr("Pause"))
1562 pause();
1563 }
1564 else if (resultid == "quickplaylistmenu")
1565 {
1566 if (resulttext == tr("All Tracks"))
1567 allTracks();
1568 else if (resulttext == tr("From CD"))
1569 fromCD();
1570 else if (resulttext == tr("Tracks By Current Artist"))
1571 byArtist();
1572 else if (resulttext == tr("Tracks From Current Genre"))
1573 byGenre();
1574 else if (resulttext == tr("Tracks From Current Album"))
1575 byAlbum();
1576 else if (resulttext == tr("Tracks From Current Year"))
1577 byYear();
1578 else if (resulttext == tr("Tracks With Same Title"))
1579 byTitle();
1580 }
1581 else if (resultid == "playlistoptionsmenu")
1582 {
1583 if (resulttext == tr("Replace Tracks"))
1584 {
1587 }
1588 else if (resulttext == tr("Add Tracks"))
1589 {
1592 }
1593 else if (resulttext == tr("Play Now"))
1594 { // cancel shuffles and repeats to play only this now
1602 }
1603 else if (resulttext == tr("Prefer Play Now"))
1604 {
1606 }
1607 else if (resulttext == tr("Prefer Add Tracks"))
1608 {
1610 }
1611 }
1612 else if (resultid == "visualizermenu")
1613 {
1614 if (dce->GetResult() >= 0)
1615 {
1616 m_currentVisual = dce->GetData().toInt();
1617
1618 //Change to the new visualizer
1620 }
1621 }
1622 else if (resultid == "addplaylist")
1623 {
1625 Playlist *playlist = gMusicData->m_all_playlists->getPlaylist(resulttext);
1626 gPlayer->playlistChanged(playlist->getID());
1627 }
1628 else if (resultid == "updateplaylist")
1629 {
1631 {
1632 Playlist *playlist = gMusicData->m_all_playlists->getPlaylist(resulttext);
1633 QString songList = gPlayer->getCurrentPlaylist()->toRawSonglist();
1634 playlist->removeAllTracks();
1635 playlist->fillSongsFromSonglist(songList);
1636 playlist->changed();
1637 gPlayer->playlistChanged(playlist->getID());
1638 }
1639 }
1640 }
1641 else if (event->type() == MusicPlayerEvent::kTrackChangeEvent)
1642 {
1643 auto *mpe = dynamic_cast<MusicPlayerEvent *>(event);
1644
1645 if (!mpe)
1646 return;
1647
1648 int trackNo = mpe->m_trackID;
1649
1651 {
1652 if (m_currentTrack >= 0 && m_currentTrack < m_currentPlaylist->GetCount())
1653 {
1655 if (item)
1656 {
1657 item->SetFontState("normal");
1658 item->DisplayState("default", "playstate");
1659 }
1660 }
1661
1662 if (trackNo >= 0 && trackNo < m_currentPlaylist->GetCount())
1663 {
1666
1668 if (item)
1669 {
1670 item->SetFontState("running");
1671 item->DisplayState("playing", "playstate");
1672 }
1673 }
1674 }
1675
1676 m_currentTrack = trackNo;
1677
1682 {
1685 }
1686
1689 }
1690 else if (event->type() == MusicPlayerEvent::kVolumeChangeEvent)
1691 {
1692 updateVolume();
1693 }
1694 else if (event->type() == MusicPlayerEvent::kTrackRemovedEvent)
1695 {
1696 auto *mpe = dynamic_cast<MusicPlayerEvent *>(event);
1697
1698 if (!mpe)
1699 return;
1700
1701 int trackID = mpe->m_trackID;
1702
1704 {
1705 // find and remove the list item for the removed track
1706 for (int x = 0; x < m_currentPlaylist->GetCount(); x++)
1707 {
1709 auto *mdata = item->GetData().value<MusicMetadata*>();
1710 if (mdata && mdata->ID() == (MusicMetadata::IdType) trackID)
1711 {
1713 x -= 1; // remove all entries, or:
1714 // break; // remove only first entry
1715 }
1716 }
1717 }
1718
1720
1721 // if we have just removed the playing track from the playlist
1722 // move to the next track
1724 {
1725 if (gPlayer->getCurrentMetadata()->ID() == (MusicMetadata::IdType) trackID)
1726 gPlayer->next();
1727 }
1728
1734
1737 }
1738 else if (event->type() == MusicPlayerEvent::kTrackAddedEvent)
1739 {
1740 auto *mpe = dynamic_cast<MusicPlayerEvent *>(event);
1741
1742 if (!mpe)
1743 return;
1744
1745 int trackID = mpe->m_trackID;
1746
1748 {
1749 if (trackID == -1)
1750 {
1751 // more than one track has been added so easier to just reload the list
1753 }
1754 else
1755 {
1756 // just one track was added so just add that track to the end of the list
1757 MusicMetadata *mdata = gMusicData->m_all_music->getMetadata(trackID);
1758
1759 if (mdata)
1760 {
1761 InfoMap metadataMap;
1762 mdata->toMap(metadataMap);
1763
1764 auto *item = new MythUIButtonListItem(m_currentPlaylist, "",
1765 QVariant::fromValue(mdata));
1766
1767 item->SetTextFromMap(metadataMap);
1768
1770 mdata->ID() == gPlayer->getCurrentMetadata()->ID())
1771 {
1772 item->SetFontState("running");
1773 item->DisplayState("playing", "playstate");
1774 }
1775 else
1776 {
1777 item->SetFontState("normal");
1778 item->DisplayState("default", "playstate");
1779 }
1780
1783 }
1784
1787 }
1788 }
1789
1793
1794 updateUIPlaylist(); // else album art doesn't update
1797 }
1798 else if (event->type() == MusicPlayerEvent::kAllTracksRemovedEvent)
1799 {
1802 updateTrackInfo(nullptr);
1803 }
1804 else if (event->type() == MusicPlayerEvent::kMetadataChangedEvent ||
1806 {
1807 auto *mpe = dynamic_cast<MusicPlayerEvent *>(event);
1808
1809 if (!mpe)
1810 return;
1811
1812 uint trackID = mpe->m_trackID;
1813
1815 {
1816 for (int x = 0; x < m_currentPlaylist->GetCount(); x++)
1817 {
1819 auto *mdata = item->GetData().value<MusicMetadata*>();
1820
1821 if (mdata && mdata->ID() == trackID)
1822 {
1823 InfoMap metadataMap;
1824 mdata->toMap(metadataMap);
1825 item->SetTextFromMap(metadataMap);
1826
1827 item->DisplayState(QString("%1").arg(mdata->Rating()), "ratingstate");
1828 }
1829 }
1830 }
1831
1833 {
1834 for (int x = 0; x < m_playedTracksList->GetCount(); x++)
1835 {
1837 auto *mdata = item->GetData().value<MusicMetadata*>();
1838
1839 if (mdata && mdata->ID() == trackID)
1840 {
1841 InfoMap metadataMap;
1842 mdata->toMap(metadataMap);
1843 item->SetTextFromMap(metadataMap);
1844 }
1845 }
1846 }
1847
1848 if (gPlayer->getCurrentMetadata() && trackID == gPlayer->getCurrentMetadata()->ID())
1850
1851 // this will ensure the next track info gets updated
1852 if (gPlayer->getNextMetadata() && trackID == gPlayer->getNextMetadata()->ID())
1854 }
1855 else if (event->type() == MusicPlayerEvent::kAlbumArtChangedEvent)
1856 {
1857 auto *mpe = dynamic_cast<MusicPlayerEvent *>(event);
1858
1859 if (!mpe)
1860 return;
1861
1862 uint trackID = mpe->m_trackID;
1863
1865 {
1866 for (int x = 0; x < m_currentPlaylist->GetCount(); x++)
1867 {
1869 auto *mdata = item->GetData().value<MusicMetadata*>();
1870 if (mdata && mdata->ID() == trackID)
1871 {
1872 // reload the albumart image if one has already been loaded for this track
1873 if (!item->GetImageFilename().isEmpty())
1874 {
1875 QString artFile = mdata->getAlbumArtFile();
1876 if (artFile.isEmpty())
1877 {
1878 item->SetImage("");
1879 item->SetImage("", "coverart");
1880 }
1881 else
1882 {
1883 item->SetImage(mdata->getAlbumArtFile());
1884 item->SetImage(mdata->getAlbumArtFile(), "coverart");
1885 }
1886 }
1887 }
1888 }
1889 }
1890
1891 if (gPlayer->getCurrentMetadata() && trackID == gPlayer->getCurrentMetadata()->ID())
1893 }
1894 else if (event->type() == MusicPlayerEvent::kTrackUnavailableEvent)
1895 {
1896 auto *mpe = dynamic_cast<MusicPlayerEvent *>(event);
1897
1898 if (!mpe)
1899 return;
1900
1901 uint trackID = mpe->m_trackID;
1902
1904 {
1905 for (int x = 0; x < m_currentPlaylist->GetCount(); x++)
1906 {
1908 auto *mdata = item->GetData().value<MusicMetadata*>();
1909 if (mdata && mdata->ID() == trackID)
1910 {
1911 item->SetFontState("disabled");
1912 item->DisplayState("unavailable", "playstate");
1913 }
1914 }
1915 }
1916 }
1917}
1918
1920{
1921 if (!m_controlVolume)
1922 {
1923 if (m_volumeText)
1924 m_volumeText->Hide();
1925
1926 if (m_muteState)
1927 m_muteState->Hide();
1928
1929 return;
1930 }
1931
1932 if (m_volumeText)
1933 {
1934 InfoMap map;
1935 gPlayer->toMap(map);
1937 }
1938
1939 if (m_muteState)
1940 {
1941 bool muted = gPlayer->isMuted();
1942 m_muteState->DisplayState(muted ? "on" : "off");
1943 }
1944}
1945
1947{
1948 if (!mdata)
1949 return;
1950
1952
1953 auto *editDialog = new EditMetadataDialog(mainStack, mdata);
1954
1955 if (!editDialog->Create())
1956 {
1957 delete editDialog;
1958 return;
1959 }
1960
1961 mainStack->AddScreen(editDialog);
1962}
1963
1965{
1966 if (!mdata)
1967 {
1968 InfoMap metadataMap;
1969 MusicMetadata metadata;
1970 metadata.toMap(metadataMap);
1971 metadata.toMap(metadataMap, "next");
1972 ResetMap(metadataMap);
1973
1974 if (m_coverartImage)
1976 if (m_ratingState)
1978 if (m_timeText)
1979 m_timeText->Reset();
1980 if (m_infoText)
1981 m_infoText->Reset();
1982 if (m_trackProgress)
1984
1985 if (m_mainvisual)
1987
1988 return;
1989 }
1990
1992 m_maxTime = 0s;
1993 else
1994 m_maxTime = duration_cast<std::chrono::seconds>(mdata->Length());
1995
1996 // get map for current track
1997 InfoMap metadataMap;
1998 mdata->toMap(metadataMap);
1999
2000 // add the map from the next track
2001 MusicMetadata *nextMetadata = gPlayer->getNextMetadata();
2002 if (nextMetadata)
2003 nextMetadata->toMap(metadataMap, "next");
2004
2005 // now set text using the map
2006 SetTextFromMap(metadataMap);
2007
2008 if (m_coverartImage)
2009 {
2010 QString filename = mdata->getAlbumArtFile();
2011 if (!filename.isEmpty())
2012 {
2015 }
2016 else
2017 {
2019 }
2020 }
2021
2022 if (m_ratingState)
2023 m_ratingState->DisplayState(QString("%1").arg(mdata->Rating()));
2024
2025 setTrackOnLCD(mdata);
2026}
2027
2029{
2030 if (!mdata)
2031 return;
2032
2033 MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
2034
2035 auto *dlg = new TrackInfoDialog(popupStack, mdata, "trackinfopopup");
2036
2037 if (!dlg->Create())
2038 {
2039 delete dlg;
2040 return;
2041 }
2042
2043 popupStack->AddScreen(dlg);
2044}
2045
2047{
2048 if (!item)
2049 return;
2050
2051 if (m_moveTrackMode)
2052 {
2054
2055 if (m_movingTrack)
2056 item->DisplayState("on", "movestate");
2057 else
2058 item->DisplayState("off", "movestate");
2059 }
2060 else
2061 {
2063 }
2064
2067}
2068
2070{
2071 if (!item)
2072 return;
2073
2074 auto *mdata = item->GetData().value<MusicMetadata*>();
2075 if (mdata && item->GetText() == " ")
2076 {
2077 if (item->GetImageFilename().isEmpty())
2078 {
2079 QString artFile = mdata->getAlbumArtFile();
2080 if (artFile.isEmpty())
2081 {
2082 item->SetImage("");
2083 item->SetImage("", "coverart");
2084 }
2085 else
2086 {
2087 item->SetImage(mdata->getAlbumArtFile());
2088 item->SetImage(mdata->getAlbumArtFile(), "coverart");
2089 }
2090 }
2091
2092 InfoMap metadataMap;
2093 mdata->toMap(metadataMap);
2094 item->SetText("");
2095 item->SetTextFromMap(metadataMap);
2096 item->DisplayState(QString("%1").arg(mdata->Rating()), "ratingstate");
2097 }
2098}
2099
2101{
2104
2105 if (!m_currentPlaylist)
2106 return;
2107
2109
2110 m_currentTrack = -1;
2111
2112 Playlist *playlist = gPlayer->getCurrentPlaylist();
2113
2114 if (!playlist)
2115 return;
2116
2117 for (int x = 0; x < playlist->getTrackCount(); x++)
2118 {
2119 MusicMetadata *mdata = playlist->getSongAt(x);
2120 if (mdata)
2121 {
2122 auto *item = new MythUIButtonListItem(m_currentPlaylist, " ",
2123 QVariant::fromValue(mdata));
2124
2125 item->SetText(mdata->Artist() + mdata->Album() + mdata->Title(), "**search**");
2126 item->SetFontState("normal");
2127 item->DisplayState("default", "playstate");
2128
2129 // if this is the current track update its play state to match the player
2130 if (gPlayer->getCurrentMetadata() && mdata->ID() == gPlayer->getCurrentMetadata()->ID())
2131 {
2132 if (gPlayer->isPlaying())
2133 {
2134 item->SetFontState("running");
2135 item->DisplayState("playing", "playstate");
2136 }
2137 else if (gPlayer->isPaused())
2138 {
2139 item->SetFontState("idle");
2140 item->DisplayState("paused", "playstate");
2141 }
2142 else
2143 {
2144 item->SetFontState("normal");
2145 item->DisplayState("stopped", "playstate");
2146 }
2147
2150 }
2151 }
2152 }
2153}
2154
2156{
2157 if (!m_playedTracksList)
2158 return;
2159
2161
2162 QList<MusicMetadata*> playedList = gPlayer->getPlayedTracksList();
2163
2164 for (int x = playedList.count(); x > 0; x--)
2165 {
2166 MusicMetadata *mdata = playedList[x-1];
2167 auto *item = new MythUIButtonListItem(m_playedTracksList, "",
2168 QVariant::fromValue(mdata));
2169
2170 InfoMap metadataMap;
2171 mdata->toMap(metadataMap);
2172 item->SetTextFromMap(metadataMap);
2173
2174 item->SetFontState("normal");
2175 item->DisplayState("default", "playstate");
2176
2177 item->SetImage(mdata->getAlbumArtFile());
2178 }
2179}
2180
2182{
2183 int trackCount = 0;
2184
2186 trackCount = gPlayer->getCurrentPlaylist()->getTrackCount();
2187
2188 InfoMap map;
2189 if (gPlayer->isPlaying() && trackCount > 0)
2190 {
2191 QString playlistcurrent = QLocale::system().toString(m_currentTrack + 1);
2192 QString playlisttotal = QLocale::system().toString(trackCount);
2193
2194 map["playlistposition"] = tr("%1 of %2").arg(playlistcurrent, playlisttotal);
2195 map["playlistcurrent"] = playlistcurrent;
2196 map["playlistcount"] = playlisttotal;
2198 map["playlistplayedtime"] = getTimeString(m_playlistPlayedTime + m_currentTime, 0s);
2199 map["playlisttotaltime"] = getTimeString(m_playlistMaxTime, 0s);
2200 QString playlistName = gPlayer->getCurrentPlaylist() ? gPlayer->getCurrentPlaylist()->getName() : "";
2201 if (playlistName == "default_playlist_storage")
2202 playlistName = tr("Default Playlist");
2203 else if (playlistName == "stream_playlist")
2204 playlistName = tr("Stream Playlist");
2205 map["playlistname"] = playlistName;
2206 map["playedtime"] = getTimeString(m_currentTime, 0s); // v34 - parts
2207 map["totaltime"] = getTimeString(m_maxTime, 0s);
2208 map["trackspeed"] = getTimeString(-1s, 0s);
2209 }
2210 else
2211 {
2212 map["playlistposition"] = "";
2213 map["playlistcurrent"] = "";
2214 map["playlistcount"] = "";
2215 map["playlisttime"] = "";
2216 map["playlistplayedtime"] = "";
2217 map["playlisttotaltime"] = "";
2218 map["playlistname"] = "";
2219 map["playedtime"] = ""; // v34 - parts for track templates
2220 map["totaltime"] = "";
2221 map["trackspeed"] = "";
2222 }
2223
2224 SetTextFromMap(map);
2225
2228}
2229
2230QString MusicCommon::getTimeString(std::chrono::seconds exTime, std::chrono::seconds maxTime)
2231{
2232 if (exTime > -1s && maxTime <= 0s)
2233 return MythDate::formatTime(exTime,
2234 (exTime >= 1h) ? "H:mm:ss" : "mm:ss");
2235
2236 QString fmt = (maxTime >= 1h) ? "H:mm:ss" : "mm:ss";
2237 QString out = MythDate::formatTime(exTime, fmt)
2238 + " / " + MythDate::formatTime(maxTime, fmt);
2239 float speed = gPlayer->getSpeed(); // v34 - show altered speed
2240 QString speedstr = "";
2241 if (lroundf(speed * 100.0F) != 100.0F)
2242 {
2243 speedstr = QString("%1").arg(speed);
2244 out += ", " + speedstr + "X";
2245 }
2246 if (exTime <= -1s)
2247 return speedstr;
2248 return out;
2249}
2250
2252{
2253 auto *buttonList = dynamic_cast<MythUIButtonList *>(GetFocusWidget());
2254 if (buttonList)
2255 buttonList->ShowSearchDialog();
2256
2257 auto *buttonTree = dynamic_cast<MythUIButtonTree *>(GetFocusWidget());
2258 if (buttonTree)
2259 buttonTree->ShowSearchDialog();
2260}
2261
2263{
2264 MythMenu *mainMenu = createMainMenu();
2265
2266 MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
2267
2268 auto *menuPopup = new MythDialogBox(mainMenu, popupStack, "actionmenu");
2269
2270 if (menuPopup->Create())
2271 popupStack->AddScreen(menuPopup);
2272 else
2273 delete mainMenu;
2274}
2275
2277{
2278 QString label = tr("View Actions");
2279
2280 auto *menu = new MythMenu(label, this, "mainmenu");
2281
2283 {
2284 menu->AddItem(tr("Switch To Gallery View"));
2285 }
2287 {
2288 menu->AddItem(tr("Switch To Tree View"));
2289 }
2290
2291 QStringList screenList;
2292 MythScreenType *screen = this;
2293 while (screen)
2294 {
2295 screenList.append(screen->objectName());
2296 screen = qobject_cast<MusicCommon*>(screen)->m_parentScreen;
2297 }
2298
2299 if (!screenList.contains("visualizerview"))
2300 menu->AddItem(tr("Fullscreen Visualizer"));
2301
2303 menu->AddItem(tr("Browse Music Library")); // v33- was "Playlist Editor"
2304
2306 if (!screenList.contains("searchview") && !screenList.contains("streamview"))
2307 menu->AddItem(tr("Search for Music"));
2308
2309 if (!screenList.contains("lyricsview"))
2310 menu->AddItem(tr("Lyrics"));
2311 }
2312
2313 menu->AddItem(tr("More Options"), nullptr, createSubMenu());
2314
2315 return menu;
2316}
2317
2319{
2320 QString label = tr("Actions");
2321
2322 auto *menu = new MythMenu(label, this, "submenu");
2323
2324 if (GetFocusWidget() && (GetFocusWidget()->inherits("MythUIButtonList") ||
2325 GetFocusWidget()->inherits("MythUIButtonTree")))
2326 menu->AddItem(tr("Search List..."));
2327
2329 {
2330 menu->AddItem(tr("Playlist Options"), nullptr, createPlaylistMenu());
2331 menu->AddItem(tr("Set Shuffle Mode"), nullptr, createShuffleMenu());
2332 menu->AddItem(tr("Set Repeat Mode"), nullptr, createRepeatMenu());
2333 }
2334
2335 menu->AddItem(tr("Player Options"), nullptr, createPlayerMenu());
2336
2338 menu->AddItem(tr("Quick Playlists"), nullptr, createQuickPlaylistsMenu());
2339
2341 menu->AddItem(tr("Change Visualizer"), nullptr, createVisualizerMenu());
2342
2343 return menu;
2344}
2345
2347{
2348 QString label = tr("Playlist Options");
2349
2350 auto *menu = new MythMenu(label, this, "playlistmenu");
2351
2353 {
2354 menu->AddItem(tr("Sync List With Current Track"));
2355 menu->AddItem(tr("Remove Selected Track"));
2356 }
2357
2358 menu->AddItem(tr("Remove All Tracks"));
2359
2361 {
2362 menu->AddItem(tr("Save To New Playlist"));
2363 menu->AddItem(tr("Save To Existing Playlist"));
2364
2365 if (m_moveTrackMode)
2366 menu->AddItem(tr("Switch To Select Mode"));
2367 else
2368 menu->AddItem(tr("Switch To Move Mode"));
2369 }
2370
2371 return menu;
2372}
2373
2375{
2376 QString label = tr("Exiting Music Player.\n\n"
2377 "Do you want to continue playing in the background?");
2378
2379 MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
2380
2381 auto *menu = new MythDialogBox(label, popupStack, "exitmenu");
2382
2383 if (!menu->Create())
2384 {
2385 delete menu;
2386 return;
2387 }
2388
2389 menu->SetReturnEvent(this, "exitmenu");
2390
2391 menu->AddButton(tr("No - Exit, Stop Playing"));
2392 menu->AddButton(tr("Yes - Exit, Continue Playing"));
2393 menu->AddButton(tr("Cancel"));
2394
2395 popupStack->AddScreen(menu);
2396}
2397
2399{
2400 QString label = tr("Player Actions");
2401
2402 auto *menu = new MythMenu(label, this, "playermenu");
2403
2404 menu->AddItem(tr("Change Volume"));
2405 menu->AddItem(tr("Mute"));
2406 menu->AddItem(tr("Previous Track"));
2407 menu->AddItem(tr("Next Track"));
2408
2410 {
2411 menu->AddItem(tr("Jump Back"));
2412 menu->AddItem(tr("Jump Forward"));
2413 }
2414
2415 menu->AddItem(tr("Play"));
2416 menu->AddItem(tr("Stop"));
2417
2419 menu->AddItem(tr("Pause"));
2420
2421 return menu;
2422}
2423
2425{
2426 QString label = tr("Set Repeat Mode");
2427
2428 auto *menu = new MythMenu(label, this, "repeatmenu");
2429
2430 menu->AddItemV(tr("None"), QVariant::fromValue((int)MusicPlayer::REPEAT_OFF));
2431 menu->AddItemV(tr("Track"), QVariant::fromValue((int)MusicPlayer::REPEAT_TRACK));
2432 menu->AddItemV(tr("All"), QVariant::fromValue((int)MusicPlayer::REPEAT_ALL));
2433
2434 menu->SetSelectedByData(static_cast<int>(gPlayer->getRepeatMode()));
2435
2436 return menu;
2437}
2438
2440{
2441 QString label = tr("Set Shuffle Mode");
2442
2443 auto *menu = new MythMenu(label, this, "shufflemenu");
2444
2445 menu->AddItemV(tr("None"), QVariant::fromValue((int)MusicPlayer::SHUFFLE_OFF));
2446 menu->AddItemV(tr("Random"), QVariant::fromValue((int)MusicPlayer::SHUFFLE_RANDOM));
2447 menu->AddItemV(tr("Smart"), QVariant::fromValue((int)MusicPlayer::SHUFFLE_INTELLIGENT));
2448 menu->AddItemV(tr("Album"), QVariant::fromValue((int)MusicPlayer::SHUFFLE_ALBUM));
2449 menu->AddItemV(tr("Artist"), QVariant::fromValue((int)MusicPlayer::SHUFFLE_ARTIST));
2450
2451 menu->SetSelectedByData(static_cast<int>(gPlayer->getShuffleMode()));
2452
2453 return menu;
2454}
2455
2457{
2458 QString label = tr("Quick Playlists");
2459
2460 auto *menu = new MythMenu(label, this, "quickplaylistmenu");
2461
2462 menu->AddItem(tr("All Tracks"));
2463
2465 menu->AddItem(tr("From CD"));
2466
2468 {
2469 menu->AddItem(tr("Tracks By Current Artist"));
2470 menu->AddItem(tr("Tracks From Current Album"));
2471 menu->AddItem(tr("Tracks From Current Genre"));
2472 menu->AddItem(tr("Tracks From Current Year"));
2473 menu->AddItem(tr("Tracks With Same Title"));
2474 }
2475
2476 return menu;
2477}
2478
2480{
2481 QString label = tr("Choose Visualizer");
2482
2483 auto *menu = new MythMenu(label, this, "visualizermenu");
2484
2485 for (uint x = 0; x < static_cast<uint>(m_visualModes.count()); x++)
2486 menu->AddItemV(m_visualModes.at(x), QVariant::fromValue(x));
2487
2488 menu->SetSelectedByData(m_currentVisual);
2489
2490 return menu;
2491}
2492
2494{
2495 QString label = tr("Add to Playlist Options");
2496
2497 auto *menu = new MythMenu(label, this, "playlistoptionsmenu");
2498
2500 {
2501 menu->AddItem(tr("Play Now"));
2502 menu->AddItem(tr("Add Tracks"));
2503 menu->AddItem(tr("Replace Tracks"));
2504 menu->AddItem(tr("Prefer Add Tracks"));
2505 }
2506 else
2507 {
2508 menu->AddItem(tr("Add Tracks"));
2509 menu->AddItem(tr("Play Now"));
2510 menu->AddItem(tr("Replace Tracks"));
2511 menu->AddItem(tr("Prefer Play Now"));
2512 }
2513
2514 return menu;
2515}
2516
2518{
2519 m_whereClause = "ORDER BY music_artists.artist_name, album_name, disc_number, track";
2521}
2522
2524{
2525 m_whereClause = "";
2526 m_songList.clear();
2527
2528 // get the list of cd tracks
2529 for (int x = 1; x <= gMusicData->m_all_music->getCDTrackCount(); x++)
2530 {
2532 if (mdata)
2533 {
2534 m_songList.append((mdata)->ID());
2535 }
2536 }
2537
2539}
2540
2542{
2544 if (!mdata)
2545 return;
2546
2547 QString value = formattedFieldValue(mdata->Artist().toUtf8().constData());
2548 m_whereClause = "WHERE music_artists.artist_name = " + value +
2549 " ORDER BY album_name, disc_number, track";
2550
2552}
2553
2555{
2557 if (!mdata)
2558 return;
2559
2560 QString value = formattedFieldValue(mdata->Album().toUtf8().constData());
2561 m_whereClause = "WHERE album_name = " + value +
2562 " ORDER BY disc_number, track";
2563
2565}
2566
2568{
2570 if (!mdata)
2571 return;
2572
2573 QString value = formattedFieldValue(mdata->Genre().toUtf8().constData());
2574 m_whereClause = "WHERE genre = " + value +
2575 " ORDER BY music_artists.artist_name, album_name, disc_number, track";
2576
2578}
2579
2581{
2583 if (!mdata)
2584 return;
2585
2586 QString value = formattedFieldValue(mdata->Year());
2587 m_whereClause = "WHERE music_songs.year = " + value +
2588 " ORDER BY music_artists.artist_name, album_name, disc_number, track";
2589
2591}
2592
2594{
2596 if (!mdata)
2597 return;
2598
2599 QString value = formattedFieldValue(mdata->Title().toUtf8().constData());
2600 m_whereClause = "WHERE music_songs.name = " + value +
2601 " ORDER BY music_artists.artist_name, album_name, disc_number, track";
2602
2604}
2605
2607{
2609 return;
2610
2612
2613 // Don't bother showing the dialog if the current playlist is empty
2615 {
2618 return;
2619 }
2620
2622
2623 if (addMainMenu)
2624 menu->AddItem(tr("More Options"), nullptr, createMainMenu());
2625
2626 MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
2627
2628 auto *menuPopup = new MythDialogBox(menu, popupStack, "playlistoptionsmenu");
2629
2630 if (menuPopup->Create())
2631 popupStack->AddScreen(menuPopup);
2632 else
2633 delete menu;
2634}
2635
2637{
2638 int curTrackID = -1;
2639 int added = 0;
2640 int curPos = gPlayer->getCurrentTrackPos();
2641
2642 // store id of current track
2644 curTrackID = gPlayer->getCurrentMetadata()->ID();
2645
2646 if (!m_whereClause.isEmpty())
2647 {
2648 // update playlist from quick playlist
2650 m_whereClause, true,
2651 m_playlistOptions.insertPLOption, curTrackID);
2652 m_whereClause.clear();
2653 }
2654 else if (!m_songList.isEmpty())
2655 {
2656 // update playlist from song list (from the playlist editor)
2658 m_songList, true,
2659 m_playlistOptions.insertPLOption, curTrackID);
2660
2661 m_songList.clear();
2662 }
2663
2665
2667 Playlist *playlist = gPlayer->getCurrentPlaylist();
2668 if (nullptr == playlist)
2669 return;
2670
2671 // if (m_currentTrack == -1) // why? non-playing should also
2672 // playFirstTrack(); // start playing per options -twitham
2673 // else
2674 {
2676 {
2677 case PL_CURRENT:
2678 {
2679 if (!restorePosition(curTrackID))
2681
2682 break;
2683 }
2684
2685 case PL_FIRST:
2687 break;
2688
2689 case PL_FIRSTNEW:
2690 {
2692 {
2693 case PL_REPLACE:
2695 break;
2696
2697 case PL_INSERTATEND:
2698 {
2699 pause();
2700 if (!gPlayer->setCurrentTrackPos(playlist->getTrackCount() - added))
2702 break;
2703 }
2704
2706 if (!gPlayer->setCurrentTrackPos(curPos + 1))
2708 break;
2709
2710 default:
2712 }
2713
2714 break;
2715 }
2716 }
2717 }
2718
2723}
2724
2726{
2727 // try to move to the current track
2728 bool foundTrack = false;
2729
2730 Playlist *playlist = gPlayer->getCurrentPlaylist();
2731 if (nullptr == playlist)
2732 return false;
2733
2734 if (trackID != -1)
2735 {
2736 for (int x = 0; x < playlist->getTrackCount(); x++)
2737 {
2738 MusicMetadata *mdata = playlist->getSongAt(x);
2739 if (mdata && mdata->ID() == (MusicMetadata::IdType) trackID)
2740 {
2741 m_currentTrack = x;
2743 {
2746 if (item)
2747 {
2748 item->SetFontState("running");
2749 item->DisplayState("playing", "playstate");
2750 }
2751 }
2752
2753 foundTrack = true;
2754
2755 break;
2756 }
2757 }
2758 }
2759
2760 return foundTrack;
2761}
2762
2764{
2766}
2767
2768//---------------------------------------------------------
2769// MythMusicVolumeDialog
2770//---------------------------------------------------------
2771static constexpr std::chrono::milliseconds MUSICVOLUMEPOPUPTIME { 4s };
2772
2774{
2775 if (m_displayTimer)
2776 {
2777 m_displayTimer->stop();
2778 delete m_displayTimer;
2779 m_displayTimer = nullptr;
2780 }
2781}
2782
2784{
2785 if (!LoadWindowFromXML("music-ui.xml", "volume_popup", this))
2786 return false;
2787
2788 UIUtilW::Assign(this, m_volText, "volume");
2789 UIUtilW::Assign(this, m_volProgress, "volumeprogress");
2790 UIUtilW::Assign(this, m_muteState, "mutestate");
2791
2792 if (m_volProgress)
2793 m_volProgress->SetTotal(100);
2794
2795 updateDisplay();
2796
2797 m_displayTimer = new QTimer(this);
2799 m_displayTimer->setSingleShot(true);
2801
2802 return true;
2803}
2804
2806{
2807 QStringList actions;
2808 bool handled = GetMythMainWindow()->TranslateKeyPress("Music", event, actions, false);
2809
2810 for (int i = 0; i < actions.size() && !handled; i++)
2811 {
2812 const QString& action = actions[i];
2813 handled = true;
2814
2815 if (action == "UP" || action == "VOLUMEUP")
2817 else if (action == "DOWN" || action == "VOLUMEDOWN")
2819 else if (action == "MUTE" || action == "SELECT")
2820 toggleMute();
2821 else
2822 handled = false;
2823 }
2824
2825 if (!handled && MythScreenType::keyPressEvent(event))
2826 handled = true;
2827
2828 // Restart the display timer only if we handled this keypress, if nothing
2829 // has changed there's no need to keep the volume on-screen
2830 if (handled)
2832
2833 return handled;
2834}
2835
2837{
2838 gPlayer->incVolume();
2839 updateDisplay();
2840}
2841
2843{
2844 gPlayer->decVolume();
2845 updateDisplay();
2846}
2847
2849{
2851 updateDisplay();
2852}
2853
2855{
2856 if (m_muteState)
2857 m_muteState->DisplayState(gPlayer->isMuted() ? "on" : "off");
2858
2859 if (m_volProgress)
2861
2862 if (m_volText)
2863 {
2864 InfoMap map;
2865 gPlayer->toMap(map);
2867 }
2868}
2869
2870//---------------------------------------------------------
2871// TrackInfoDialog
2872//---------------------------------------------------------
2874{
2875 if (!LoadWindowFromXML("music-ui.xml", "trackdetail_popup", this))
2876 return false;
2877
2878 InfoMap metadataMap;
2879 m_metadata->toMap(metadataMap);
2880 SetTextFromMap(metadataMap);
2881
2882 MythUIStateType *ratingState = dynamic_cast<MythUIStateType *>(GetChild("rating_state"));
2883 if (ratingState)
2884 ratingState->DisplayState(QString("%1").arg(m_metadata->Rating()));
2885
2886 MythUIImage *albumImage = dynamic_cast<MythUIImage *>(GetChild("coverart"));
2887 if (albumImage)
2888 {
2889 if (!m_metadata->getAlbumArtFile().isEmpty())
2890 {
2891 albumImage->SetFilename(m_metadata->getAlbumArtFile());
2892 albumImage->Load();
2893 }
2894 }
2895
2896 // hide the song ID by default
2897 MythUIText *songID = dynamic_cast<MythUIText *>(GetChild("songid"));
2898 if (songID)
2899 songID->Hide();
2900
2901 return true;
2902}
2903
2905{
2906 QStringList actions;
2907 bool handled = GetMythMainWindow()->TranslateKeyPress("Music", event, actions, false);
2908
2909 for (int i = 0; i < actions.size() && !handled; i++)
2910 {
2911 const QString& action = actions[i];
2912 handled = true;
2913
2914 if (action == "INFO")
2915 Close();
2916 if (action == "0")
2917 {
2918 // if it's available show the song ID
2919 MythUIText *songID = dynamic_cast<MythUIText *>(GetChild("songid"));
2920 if (songID)
2921 songID->Show();
2922 }
2923 else
2924 {
2925 handled = false;
2926 }
2927 }
2928
2929 if (!handled && MythScreenType::keyPressEvent(event))
2930 handled = true;
2931
2932 return handled;
2933}
MusicMetadata * getCDMetadata(int m_the_track)
MusicMetadata * getMetadata(int an_id)
int getCDTrackCount(void) const
virtual bool IsPaused(void) const =0
virtual void SetTimecode(std::chrono::milliseconds timecode)=0
virtual bool ToggleUpmix(void)
Definition: audiooutput.h:158
virtual void lock(void)
Definition: decoder.h:85
virtual void unlock(void)
Definition: decoder.h:86
virtual void seek(double)=0
Event dispatched from MythUI modal dialogs to a listening class containing a result of some form.
Definition: mythdialogbox.h:41
static const Type kEventType
Definition: mythdialogbox.h:56
Definition: lcddevice.h:170
static LCD * Get(void)
Definition: lcddevice.cpp:69
@ MUSIC_REPEAT_ALL
Definition: lcddevice.h:187
@ MUSIC_REPEAT_TRACK
Definition: lcddevice.h:186
@ MUSIC_REPEAT_NONE
Definition: lcddevice.h:185
@ MUSIC_SHUFFLE_ALBUM
Definition: lcddevice.h:194
@ MUSIC_SHUFFLE_NONE
Definition: lcddevice.h:191
@ MUSIC_SHUFFLE_ARTIST
Definition: lcddevice.h:195
@ MUSIC_SHUFFLE_RAND
Definition: lcddevice.h:192
@ MUSIC_SHUFFLE_SMART
Definition: lcddevice.h:193
void switchToMusic(const QString &artist, const QString &album, const QString &track)
Definition: lcddevice.cpp:565
bool isRunning(void) const
Definition: mthread.cpp:263
void prepare(void) override
Definition: mainvisual.cpp:138
void setVisual(const QString &name)
Definition: mainvisual.cpp:80
QStringList getVisualizations(void)
Definition: mainvisual.h:58
int getCurrentVisual(void) const
Definition: mainvisual.h:60
void seek(std::chrono::seconds pos)
MythUIButton * m_nextButton
Definition: musiccommon.h:201
void updateRepeatMode(void)
void changeVolume(bool up) const
MythMenu * createRepeatMenu(void)
bool m_movingTrack
Definition: musiccommon.h:153
bool m_cycleVisualizer
Definition: musiccommon.h:146
void stop(void)
void byAlbum(void)
void cycleVisualizer(void)
MythUIButton * m_ffButton
Definition: musiccommon.h:200
static void play(void)
MythMenu * createPlaylistOptionsMenu(void)
bool m_moveTrackMode
Definition: musiccommon.h:152
void fromCD(void)
std::chrono::seconds m_currentTime
Definition: musiccommon.h:158
std::chrono::seconds m_maxTime
Definition: musiccommon.h:159
void viewExited(void)
void playlistItemClicked(MythUIButtonListItem *item)
void seekforward(void)
void next(void)
void init(bool startPlayback=true)
void switchVisualizer(const QString &visual)
static void showSpeed(bool show)
MythUIProgressBar * m_trackProgress
Definition: musiccommon.h:185
void allTracks(void)
QStringList m_visualModes
Definition: musiccommon.h:149
static void toggleUpmix(void)
QList< int > m_songList
Definition: musiccommon.h:170
MythUIVideo * m_visualizerVideo
Definition: musiccommon.h:208
void updateShuffleMode(bool updateUIList=false)
MythUIButton * m_playButton
Definition: musiccommon.h:198
MythMenu * createMainMenu(void)
MythMenu * createPlaylistMenu(void)
MythUIText * m_trackSpeedText
Definition: musiccommon.h:187
MythUIStateType * m_shuffleState
Definition: musiccommon.h:178
void doUpdatePlaylist(void)
MythScreenType * m_parentScreen
Definition: musiccommon.h:140
static void setTrackOnLCD(MusicMetadata *mdata)
MythMenu * createShuffleMenu(void)
MythMenu * createVisualizerMenu(void)
std::chrono::seconds m_playlistPlayedTime
Definition: musiccommon.h:162
void changeSpeed(bool up)
bool m_randomVisualizer
Definition: musiccommon.h:147
void stopVisualizer(void)
~MusicCommon(void) override
Definition: musiccommon.cpp:60
PlaylistOptions m_playlistOptions
Definition: musiccommon.h:166
MythUIText * m_infoText
Definition: musiccommon.h:174
MythUIButton * m_pauseButton
Definition: musiccommon.h:197
void byYear(void)
void seekback(void)
MythUIButton * m_rewButton
Definition: musiccommon.h:196
static void showTrackInfo(MusicMetadata *mdata)
static void showVolume(void)
void byGenre(void)
void stopAll(void)
MusicView m_currentView
Definition: musiccommon.h:141
int m_currentTrack
Definition: musiccommon.h:157
void showExitMenu(void)
void updateTrackInfo(MusicMetadata *mdata)
static void pause(void)
MythUIText * m_trackProgressText
Definition: musiccommon.h:186
MythMenu * createQuickPlaylistsMenu(void)
static void changeRating(bool increase)
void updateVolume(void)
void ShowMenu(void) override
MythUIStateType * m_ratingState
Definition: musiccommon.h:183
bool CreateCommon(void)
Definition: musiccommon.cpp:78
void updateUIPlayedList(void)
static void playlistItemVisible(MythUIButtonListItem *item)
void byTitle(void)
static void editTrackInfo(MusicMetadata *mdata)
void previous(void)
QString m_whereClause
Definition: musiccommon.h:167
MythMenu * createSubMenu(void)
std::chrono::seconds m_playlistMaxTime
Definition: musiccommon.h:163
bool keyPressEvent(QKeyEvent *e) override
Key event handler.
void byArtist(void)
MythUIText * m_visualText
Definition: musiccommon.h:175
MythUIProgressBar * m_playlistProgress
Definition: musiccommon.h:193
unsigned int m_currentVisual
Definition: musiccommon.h:150
bool m_controlVolume
Definition: musiccommon.h:155
bool restorePosition(int trackID)
bool m_fullscreenBlank
Definition: musiccommon.h:145
MythUIButtonList * m_playedTracksList
Definition: musiccommon.h:206
MainVisual * m_mainvisual
Definition: musiccommon.h:144
MythUIText * m_volumeText
Definition: musiccommon.h:191
MythUIText * m_noTracksText
Definition: musiccommon.h:176
static QString getTimeString(std::chrono::seconds exTime, std::chrono::seconds maxTime)
MythUIStateType * m_repeatState
Definition: musiccommon.h:179
void showPlaylistOptionsMenu(bool addMainMenu=false)
void searchButtonList(void)
MythUIButton * m_prevButton
Definition: musiccommon.h:195
MythUIButton * m_stopButton
Definition: musiccommon.h:199
void updateProgressBar(void)
uint m_playlistTrackCount
Definition: musiccommon.h:161
void switchView(MusicView view)
MythUIImage * m_coverartImage
Definition: musiccommon.h:203
MythUIStateType * m_trackState
Definition: musiccommon.h:188
MusicCommon(MythScreenStack *parent, MythScreenType *parentScreen, const QString &name)
Definition: musiccommon.cpp:46
MythUIText * m_timeText
Definition: musiccommon.h:173
void customEvent(QEvent *event) override
MythUIStateType * m_movingTracksState
Definition: musiccommon.h:181
MythUIButtonList * m_currentPlaylist
Definition: musiccommon.h:205
void toggleMute(void) const
static void playFirstTrack()
void updatePlaylistStats(void)
void startVisualizer(void)
MythMenu * createPlayerMenu(void)
void updateUIPlaylist(void)
MythUIStateType * m_muteState
Definition: musiccommon.h:190
AllMusic * m_all_music
Definition: musicdata.h:52
PlaylistContainer * m_all_playlists
Definition: musicdata.h:51
int Year() const
std::chrono::milliseconds Length() const
void toMap(InfoMap &metadataMap, const QString &prefix="")
QString Title() const
QString getAlbumArtFile(void)
IdType ID() const
QString Artist() const
int Rating() const
uint32_t IdType
Definition: musicmetadata.h:86
QString Genre() const
QString Album() const
static const Type kMetadataChangedEvent
Definition: musicplayer.h:45
static const Type kTrackStatsChangedEvent
Definition: musicplayer.h:46
static const Type kTrackUnavailableEvent
Definition: musicplayer.h:43
static const Type kAlbumArtChangedEvent
Definition: musicplayer.h:47
static const Type kVolumeChangeEvent
Definition: musicplayer.h:40
static const Type kAllTracksRemovedEvent
Definition: musicplayer.h:44
static const Type kTrackAddedEvent
Definition: musicplayer.h:41
static const Type kTrackChangeEvent
Definition: musicplayer.h:39
static const Type kTrackRemovedEvent
Definition: musicplayer.h:42
MusicMetadata * getCurrentMetadata(void)
get the metadata for the current track in the playlist
ShuffleMode toggleShuffleMode(void)
PlayMode getPlayMode(void)
Definition: musicplayer.h:77
void savePosition(void)
void playlistChanged(int playlistID)
void next(void)
@ SHUFFLE_INTELLIGENT
Definition: musicplayer.h:177
uint getVolume(void) const
void decVolume(void)
void setPlayMode(PlayMode mode)
void removeTrack(int trackID)
void stop(bool stopAll=false)
void activePlaylistChanged(int trackID, bool deleted)
bool isStopped(void)
Definition: musicplayer.h:111
void play(void)
bool isPaused(void)
Definition: musicplayer.h:110
@ PLAYMODE_TRACKSPLAYLIST
Definition: musicplayer.h:71
@ PLAYMODE_TRACKSEDITOR
Definition: musicplayer.h:72
void getBufferStatus(int *bufferAvailable, int *bufferSize) const
void previous(void)
void setAllowRestorePos(bool allow)
Definition: musicplayer.h:154
QList< MusicMetadata * > & getPlayedTracksList(void)
Definition: musicplayer.h:141
void moveTrackUpDown(bool moveUp, int whichTrack)
void restorePosition(void)
void removeListener(QObject *listener)
bool isPlaying(void) const
Definition: musicplayer.h:109
void removeVisual(MainVisual *visual)
bool setCurrentTrackPos(int pos)
ShuffleMode getShuffleMode(void)
Definition: musicplayer.h:195
void incVolume(void)
AudioOutput * getOutput(void)
Definition: musicplayer.h:128
float getSpeed() const
Definition: musicplayer.h:99
void sendTrackStatsChangedEvent(int trackID)
void addListener(QObject *listener)
RepeatMode getRepeatMode(void)
Definition: musicplayer.h:191
static bool getPlayNow(void)
void pause(void)
void setShuffleMode(ShuffleMode mode)
Playlist * getCurrentPlaylist(void)
static void setPlayNow(bool PlayNow)
whether we prefer Play Now over Add Tracks
void setRepeatMode(RepeatMode mode)
Definition: musicplayer.h:192
void toggleMute(void)
bool isMuted(void) const
Definition: musicplayer.h:89
Decoder * getDecoder(void)
Definition: musicplayer.h:126
MusicMetadata * getNextMetadata(void)
get the metadata for the next track in the playlist
RepeatMode toggleRepeatMode(void)
void changeCurrentTrack(int trackNo)
change the current track to the given track
int getCurrentTrackPos(void) const
Definition: musicplayer.h:143
void addVisual(MainVisual *visual)
void toMap(InfoMap &infoMap) const
QString GetSetting(const QString &key, const QString &defaultval="")
bool GetBoolSetting(const QString &key, bool defaultval=false)
Basic menu dialog, message and a list of options.
MythScreenStack * GetMainStack()
bool TranslateKeyPress(const QString &Context, QKeyEvent *Event, QStringList &Actions, bool AllowJumps=true)
Get a list of actions for a keypress in the given context.
MythScreenStack * GetStack(const QString &Stackname)
~MythMusicVolumeDialog(void) override
bool keyPressEvent(QKeyEvent *event) override
Key event handler.
MythUIProgressBar * m_volProgress
Definition: musiccommon.h:233
MythUIText * m_volText
Definition: musiccommon.h:231
bool Create(void) override
MythUIStateType * m_muteState
Definition: musiccommon.h:232
virtual void AddScreen(MythScreenType *screen, bool allowFade=true)
Screen in which all other widgets are contained and rendered.
MythUIType * GetFocusWidget(void) const
bool keyPressEvent(QKeyEvent *event) override
Key event handler.
virtual void Close()
QMutex * mutex()
Definition: visual.h:26
Dialog prompting the user to enter a text string.
bool Create(void) override
void SetFontState(const QString &state, const QString &name="")
void DisplayState(const QString &state, const QString &name)
bool MoveUpDown(bool flag)
void SetTextFromMap(const InfoMap &infoMap, const QString &state="")
void SetImage(MythImage *image, const QString &name="")
Sets an image directly, should only be used in special circumstances since it bypasses the cache.
QString GetImageFilename(const QString &name="") const
QString GetText(const QString &name="") const
void SetText(const QString &text, const QString &name="", const QString &state="")
List widget, displays list items in a variety of themeable arrangements and can trigger signals when ...
MythUIButtonListItem * GetItemCurrent() const
void itemVisible(MythUIButtonListItem *item)
void SetItemCurrent(MythUIButtonListItem *item)
void RemoveItem(MythUIButtonListItem *item)
void Reset() override
Reset the widget to it's original state, should not reset changes made by the theme.
void SetSearchFields(const QString &fields)
int GetCurrentPos() const
void itemClicked(MythUIButtonListItem *item)
MythUIButtonListItem * GetItemAt(int pos) const
A tree widget for displaying and navigating a MythGenericTree()
void ShowSearchDialog(void)
void SetLocked(bool locked)
void Push(bool lock=false)
void Clicked()
void SetLockable(bool lockable)
Definition: mythuibutton.h:39
virtual void SetTextFromMap(const InfoMap &infoMap)
virtual void ResetMap(const InfoMap &infoMap)
Image widget, displays a single image or multiple images in sequence.
Definition: mythuiimage.h:98
bool Load(bool allowLoadInBackground=true, bool forceStat=false)
Load the image(s), wraps ImageLoader::LoadImage()
void SetFilename(const QString &filename)
Must be followed by a call to Load() to load the image.
void Reset(void) override
Reset the image back to the default defined in the theme.
void SetUsed(int value)
void SetTotal(int value)
Provide a dialog to quickly find an entry in a list.
This widget is used for grouping other widgets for display when a particular named state is called.
bool DisplayState(const QString &name)
All purpose text widget, displays a text string.
Definition: mythuitext.h:29
void Reset(void) override
Reset the widget to it's original state, should not reset changes made by the theme.
Definition: mythuitext.cpp:65
void SetTextFromMap(const InfoMap &map)
Definition: mythuitext.cpp:138
virtual void SetText(const QString &text)
Definition: mythuitext.cpp:115
virtual void SetVisible(bool visible)
void Hide(void)
MythUIType * GetChild(const QString &name) const
Get a named child of this UIType.
Definition: mythuitype.cpp:138
void Show(void)
static const Type kInfo
Definition: output.h:65
static const Type kPlaying
Definition: output.h:63
static const Type kStopped
Definition: output.h:67
static const Type kPaused
Definition: output.h:66
static const Type kBuffering
Definition: output.h:64
Playlist * getPlaylist(int id)
Playlist * getActive(void)
void copyNewPlaylist(const QString &name)
QStringList getPlaylistNames(void)
int getID(void) const
Definition: playlist.h:111
QString getName(void)
Definition: playlist.h:106
QString toRawSonglist(bool shuffled=false, bool tracksOnly=false)
Definition: playlist.cpp:855
void removeAllTracks(void)
Definition: playlist.cpp:89
int fillSonglistFromQuery(const QString &whereClause, bool removeDuplicates=false, InsertPLOption insertOption=PL_REPLACE, int currentTrackID=0)
Definition: playlist.cpp:686
void changed(void)
Definition: playlist.cpp:990
void fillSongsFromSonglist(const QString &songList)
Definition: playlist.cpp:641
int getTrackCount(void)
Definition: playlist.h:82
void getStats(uint *trackCount, std::chrono::seconds *totalLength, uint currentTrack=0, std::chrono::seconds *playedLength=nullptr) const
Definition: playlist.cpp:501
MusicMetadata * getSongAt(int pos) const
Definition: playlist.cpp:1096
int fillSonglistFromList(const QList< int > &songList, bool removeDuplicates, InsertPLOption insertOption, int currentTrackID)
Definition: playlist.cpp:785
MusicMetadata * m_metadata
Definition: musiccommon.h:249
bool keyPressEvent(QKeyEvent *event) override
Key event handler.
bool Create(void) override
static bool LoadWindowFromXML(const QString &xmlfile, const QString &windowname, MythUIType *parent)
unsigned int uint
Definition: freesurround.h:24
@ FUNC_MUSIC
Definition: lcddevice.h:160
static constexpr std::chrono::milliseconds MUSICVOLUMEPOPUPTIME
MusicView
Definition: musiccommon.h:32
@ MV_SEARCH
Definition: musiccommon.h:38
@ MV_PLAYLIST
Definition: musiccommon.h:33
@ MV_LYRICS
Definition: musiccommon.h:34
@ MV_PLAYLISTEDITORTREE
Definition: musiccommon.h:35
@ MV_RADIO
Definition: musiccommon.h:42
@ MV_VISUALIZERINFO
Definition: musiccommon.h:44
@ MV_MINIPLAYER
Definition: musiccommon.h:43
@ MV_PLAYLISTEDITORGALLERY
Definition: musiccommon.h:36
@ MV_VISUALIZER
Definition: musiccommon.h:37
MusicData * gMusicData
Definition: musicdata.cpp:23
MusicPlayer * gPlayer
Definition: musicplayer.cpp:38
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
static void startPlayback(void)
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
MythMainWindow * GetMythMainWindow(void)
Convenience inline random number generator functions.
static MythThemedMenu * menu
QHash< QString, QString > InfoMap
Definition: mythtypes.h:15
QString formatTime(std::chrono::milliseconds msecs, QString fmt)
Format a milliseconds time value.
Definition: mythdate.cpp:242
uint32_t MythRandom()
generate 32 random bits
Definition: mythrandom.h:20
@ PL_FIRST
Definition: playlist.h:32
@ PL_FIRSTNEW
Definition: playlist.h:33
@ PL_CURRENT
Definition: playlist.h:34
@ PL_INSERTAFTERCURRENT
Definition: playlist.h:27
@ PL_REPLACE
Definition: playlist.h:24
@ PL_INSERTATEND
Definition: playlist.h:26
static eu8 clamp(eu8 value, eu8 low, eu8 high)
Definition: pxsup2dast.c:206
static void show(uint8_t *buf, int length)
Definition: ringbuffer.cpp:341
QString formattedFieldValue(const QVariant &value)
PlayPLOption playPLOption
Definition: playlist.h:40
InsertPLOption insertPLOption
Definition: playlist.h:39
static bool Assign(ContainerType *container, UIType *&item, const QString &name, bool *err=nullptr)
Definition: mythuiutils.h:27