2 Copyright 2004-2020 Chris Tallon, 2014 Marten Richter
4 This file is part of VOMP.
6 VOMP is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 VOMP is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with VOMP. If not, see <https://www.gnu.org/licenses/>.
30 #include "messagequeue.h"
32 #include "movieinfo.h"
33 #include "seriesinfo.h"
36 #include "vepgsummary.h"
37 #include "vepgsettimer.h"
39 #include "staticartwork.h"
41 #include "vepglistadvanced.h"
43 static const char* TAG = "VEpgListAdvanced";
45 VEpgListAdvanced::VEpgListAdvanced(MessageReceiver* tvideolive, ChannelList* tchanList, ULONG initialChannelNumber)
47 channelNumber = initialChannelNumber;
49 videolive = tvideolive;
50 boxstack = BoxStack::getInstance();
54 setSize(640 + 40, 500 + 40); //old setSize(570, 420);
60 setTitleBarColour(DrawStyle::TITLEBARBACKGROUND);
61 TVMediaInfo* info = new TVMediaInfo();
62 info->setChannelLogo(channelNumber);
63 info->setStaticFallback(sa_tv);
64 setTitleBarIcon(info);
66 sl.setPosition(10, 30 + 5);
67 sl.setSize(area.w * 42 / 100 - 20, area.h - 30 - 15 - 30);
68 sl.setLinesPerOption(2.4f);
71 Region slarea = sl.getRegionR();
73 epg.setParaMode(true);
74 epg.setPosition(slarea.x + slarea.w + 10, 30 + 5);
75 epg.setSize(area.w - slarea.x - slarea.w - 10, area.h - 30 - 15 - 30);
78 epg.setVideoBackground();
79 epg.setBackgroundColour(DrawStyle::VIEWTRANSPARENTBACKGROUND);
81 epgTVmedia.setPosition(epg.getRegionR().w - 100 - 10, 10);
82 epgTVmedia.setSize(100, static_cast<UINT>(150 / Osd::getInstance()->getPixelAspect()));
85 boxRed.setBackgroundColour(DrawStyle::RED);
86 boxRed.setPosition(165 /*54*/, sl.getY2() + 8);
87 boxRed.setSize(18, 16);
90 textRed.setPosition(boxRed.getX2(), sl.getY2() + 4);
91 textRed.setSize(116, 30);
95 boxGreen.setBackgroundColour(DrawStyle::GREEN);
96 boxGreen.setPosition(165 + 1 * 110, sl.getY2() + 8);
97 boxGreen.setSize(18, 16);
100 textGreen.setPosition(boxGreen.getX2(), sl.getY2() + 4);
101 textGreen.setSize(116, 30);
104 boxYellow.setBackgroundColour(DrawStyle::YELLOW);
105 boxYellow.setPosition(165 + 2 * 110, sl.getY2() + 8);
106 boxYellow.setSize(18, 16);
109 textYellow.setPosition(boxYellow.getX2(), sl.getY2() + 4);
110 textYellow.setSize(116, 30);
113 boxBlue.setBackgroundColour(DrawStyle::BLUE);
114 boxBlue.setPosition(165 + 3 * 110, sl.getY2() + 8);
115 boxBlue.setSize(18, 16);
118 textBlue.setPosition(boxBlue.getX2(), sl.getY2() + 4);
119 textBlue.setSize(116, 30);
124 updateEpgDataChannel();
126 MessageQueue::getInstance()->addReceiver(this);
129 VEpgListAdvanced::~VEpgListAdvanced()
131 MessageQueue::getInstance()->removeReceiver(this);
135 void VEpgListAdvanced::setButtonText()
141 textRed.setText(tr("Record"));
142 textGreen.setText(tr("Now"));
143 textYellow.setText(tr("Next"));
144 textBlue.setText(tr("Guide"));
149 textRed.setText(tr("Record"));
150 textGreen.setText(tr("Next"));
151 textYellow.setText(tr("Schedule"));
152 textBlue.setText(tr("Switch"));
157 textRed.setText(tr("Record"));
158 textGreen.setText(tr("Now"));
159 textYellow.setText(tr("Schedule"));
160 textBlue.setText(tr("Switch"));
166 void VEpgListAdvanced::doRed()
171 void VEpgListAdvanced::doGreen()
189 void VEpgListAdvanced::doYellow()
207 void VEpgListAdvanced::doBlue()
225 void VEpgListAdvanced::doNext()
227 LogNT::getInstance()->debug(TAG, "doNext");
228 ULONG slCurrentOption = reinterpret_cast<ULONG>(sl.getCurrentOptionData());
230 if (mode != OneChannel)
232 Channel* chan = (*chanList)[slCurrentOption];
233 channelNumber = chan->number;
237 updateEpgDataNowNext(true);
239 TVMediaInfo* info = new TVMediaInfo();
240 info->setStaticArtwork(sa_tv);
241 setTitleBarIcon(info);
243 boxstack->update(this);
246 void VEpgListAdvanced::doNow()
248 LogNT::getInstance()->debug(TAG, "doNow");
249 ULONG slCurrentOption = reinterpret_cast<ULONG>(sl.getCurrentOptionData());
251 if (mode != OneChannel)
253 Channel* chan = (*chanList)[slCurrentOption];
254 channelNumber = chan->number;
258 updateEpgDataNowNext(true);
260 TVMediaInfo* info = new TVMediaInfo();
261 info->setStaticArtwork(sa_tv);
262 setTitleBarIcon(info);
264 boxstack->update(this);
267 void VEpgListAdvanced::doProgramm()
269 LogNT::getInstance()->debug(TAG, "doProgram");
271 ULONG slCurrentOption = reinterpret_cast<ULONG>(sl.getCurrentOptionData());
272 Channel* chan = (*chanList)[slCurrentOption];
273 channelNumber = chan->number;
274 updateEpgDataChannel();
276 TVMediaInfo* info = new TVMediaInfo();
277 info->setChannelLogo(channelNumber);
278 info->setStaticFallback(sa_tv);
279 setTitleBarIcon(info);
281 boxstack->update(this);
284 void VEpgListAdvanced::doSwitch()
288 if (mode != OneChannel)
290 ULONG slCurrentOption = reinterpret_cast<ULONG>(sl.getCurrentOptionData());
291 Channel* chan = (*chanList)[slCurrentOption];
292 channelNumber = chan->number;
295 LogNT::getInstance()->debug(TAG, "doSwitch {}", channelNumber);
296 Message* m = new Message(); // Must be done after this view deleted
299 m->message = Message::CHANNEL_CHANGE;
300 m->parameter = channelNumber;
302 MessageQueue::getInstance()->postMessage(m);
308 #pragma warning(disable : 4703)
311 void VEpgListAdvanced::doRecord()
314 Event* current = getCurrentOptionEvent(channel);
318 LogNT::getInstance()->debug(TAG, "Found the option you pointed at. {} {}", current->title, current->id);
319 unsigned int chanlistsize = chanList->size();
323 for (listIndex = 0; listIndex < chanlistsize; listIndex++)
325 chan = (*chanList)[listIndex];
327 if (chan->number == channel) break;
330 LogNT::getInstance()->debug(TAG, "ID {} TIME {} DURATION {} TITLE {}",
331 current->id, current->time, current->duration, current->title);
332 VEpgSetTimer* vs = new VEpgSetTimer(current, chan);
335 boxstack->update(vs);
339 void VEpgListAdvanced::doGrid()
341 if (mode != OneChannel)
343 ULONG slCurrentOption = reinterpret_cast<ULONG>(sl.getCurrentOptionData());
344 Channel* chan = (*chanList)[slCurrentOption];
345 channelNumber = chan->number;
349 unsigned int chanlistsize = chanList->size();
352 for (listIndex = 0; listIndex < chanlistsize; listIndex++)
354 chan = (*chanList)[listIndex];
355 if (chan->number == channelNumber) break;
358 VEpg* vepg = new VEpg(videolive, listIndex, chanList);
361 boxstack->update(vepg);
364 void VEpgListAdvanced::clearEventList()
366 std::vector<EventList*>::iterator itty = eventLista.begin();
368 while (itty != eventLista.end())
384 * if (!chanList) return;
386 for(UINT listIndex = 0; listIndex < gridRows; listIndex++)
388 if(listTop + listIndex >= UINT(chanListbox.getBottomOption()))
390 chan = (*chanList)[listTop + listIndex];
391 eventLista[listIndex] = VDR::getInstance()->getChannelSchedule(chan->number, ltime - 1, window_width * 60 + 2); // ltime - 1 to get prog before window (allows cursor left past ltime). + 2 to get prog after window
396 void VEpgListAdvanced::updateEpgData()
402 //updateEpgDataChannel();
408 updateEpgDataNowNext(false);
414 void VEpgListAdvanced::updateEpgDataNowNext(bool changeState)
419 UINT chanlistsize = chanList->size();
424 eventLista.resize(chanList->size());
427 for (UINT listIndex = 0; listIndex < chanlistsize; listIndex++)
429 if (listIndex >= chanlistsize) continue;
431 chan = (*chanList)[listIndex];
433 if (chan->number == channelNumber)
435 startupdate = listIndex - sl.getNumOptionsDisplayable() - 2;
436 endupdate = listIndex + sl.getNumOptionsDisplayable() + 2;
443 startupdate = sl.getTopOption() - 2;
444 endupdate = sl.getBottomOption() + 1;
452 for (int listIndex = startupdate; listIndex < endupdate; listIndex++)
454 if (listIndex < 0) continue;
455 if (listIndex >= static_cast<int>(chanlistsize)) continue;
457 chan = (*chanList)[listIndex];
459 if (!eventLista[listIndex]) eventLista[listIndex] = VDR::getInstance()->getChannelSchedule(chan->number, now, 4 * 60 * 60);
463 void VEpgListAdvanced::updateEpgDataChannel()
466 eventLista.resize(1);
469 eventLista[0] = VDR::getInstance()->getChannelSchedule(channelNumber, now, 24 * 60 * 60 * 30); // one month
470 LogNT::getInstance()->debug(TAG, "Eventlist {:#x} {}", static_cast<void*>(eventLista[0]), channelNumber);
473 void VEpgListAdvanced::drawData(bool doIndexPop)
475 if (mode == OneChannel) drawDataChannel(doIndexPop);
476 else if (mode == Next) drawDataNowNext(true, doIndexPop);
477 else if (mode == Now) drawDataNowNext(false, doIndexPop);
480 void VEpgListAdvanced::drawDataChannel(bool doIndexPop)
482 int saveIndex = sl.getCurrentOption();
483 int saveTop = sl.getTopOption();
487 sl.addColumn(25 + 7);
488 sl.addColumn(25 + 7 + 7);
495 char startTimeStr[16];
498 Event* currentEvent = NULL;
499 EventList::iterator j;
500 EventList* eventList = eventLista[0];
504 for (j = eventList->begin(); j != eventList->end(); j++)
507 time_t eventStartTime = static_cast<time_t>(currentEvent->time);
508 time_t eventEndTime = static_cast<time_t>(currentEvent->time + currentEvent->duration);
510 LOCALTIME_R(&eventStartTime, &btime);
511 strftime(startTimeStr, 16, "%d/%m/%y %H:%M", &btime);
512 LOCALTIME_R(&eventEndTime, &btime);
513 strftime(endTimeStr, 16, "%H:%M", &btime);
514 std::string eventText = fmt::format("\t {}\n \t \t{} - {}", currentEvent->title, startTimeStr, endTimeStr);
517 TVMediaInfo* info = new TVMediaInfo();
518 info->setPosterThumb(channelNumber, currentEvent->id);
519 info->setStaticFallback(sa_defposter);
521 currentEvent->index = sl.addOption(eventText, reinterpret_cast<void*>(currentEvent->id), first, info);
528 sl.hintSetCurrent(0);
532 sl.hintSetCurrent(saveIndex);
533 sl.hintSetTop(saveTop);
539 void VEpgListAdvanced::drawDataNowNext(bool next, bool doIndexPop)
541 int saveIndex = sl.getCurrentOption();
542 int saveTop = sl.getTopOption();
550 char startTimeStr[16];
554 Event* currentEvent = NULL;
555 EventList::iterator j;
558 if (next) minevents++;
560 int setcurrenthelper = 0;
562 unsigned int chanlistsize = chanList->size();
564 std::string eventText;
566 for (UINT listIndex = 0; listIndex < chanlistsize; listIndex++)
569 chan = (*chanList)[listIndex];
571 EventList* eventList = eventLista[listIndex];
573 if (eventList && (eventList->size() >= minevents))
575 j = eventList->begin();
577 currentEvent = j[minevents - 1];
578 time_t eventStartTime = static_cast<time_t>(currentEvent->time);
579 time_t eventEndTime = static_cast<time_t>(currentEvent->time + currentEvent->duration);
581 LOCALTIME_R(&eventStartTime, &btime);
582 strftime(startTimeStr, 16, "%H:%M", &btime);
583 LOCALTIME_R(&eventEndTime, &btime);
584 strftime(endTimeStr, 16, "%H:%M", &btime);
586 eventText = fmt::format("{}\n{}\t{} - {}", currentEvent->title, chan->name, startTimeStr, endTimeStr);
590 eventText = fmt::format("\n{}", chan->name);
593 TVMediaInfo* info = new TVMediaInfo();
595 if ((*chanList)[listIndex]->number == channelNumber)
598 setcurrenthelper = listIndex;
601 info->setChannelLogo((*chanList)[listIndex]->number);
602 info->setStaticFallback(sa_tv);
603 int index = sl.addOption(eventText, reinterpret_cast<void*>(listIndex), first, info);
605 if (currentEvent) currentEvent->index = index;
612 sl.hintSetCurrent(setcurrenthelper);
616 sl.hintSetCurrent(saveIndex);
617 sl.hintSetTop(saveTop);
623 void VEpgListAdvanced::draw(bool doIndexPop)
625 // Single channel mode
631 unsigned int chanlistsize = chanList->size();
635 for (listIndex = 0; listIndex < chanlistsize; listIndex++)
637 chan = (*chanList)[listIndex];
639 if (chan->number == channelNumber) break;
642 sprintf(tempA, tr("Schedule - %s"), (*chanList)[listIndex]->name);
648 setTitleText(tr("Now"));
653 setTitleText(tr("Next"));
658 drawData(doIndexPop);
668 LOCALTIME_R(&now, &btime);
669 strftime(freeSpace, 299, "%d/%m/%y", &btime);
670 drawTextRJ(freeSpace, getWidth(), 5, DrawStyle::LIGHTTEXT);
677 w.nextSymbol = WSymbol::UP;
678 w.setPosition(20, area.h - 35);
681 w.nextSymbol = WSymbol::DOWN;
682 w.setPosition(50, area.h - 35);
685 w.nextSymbol = WSymbol::SKIPBACK;
686 w.setPosition(85, area.h - 35);
689 w.nextSymbol = WSymbol::SKIPFORWARD;
690 w.setPosition(115, area.h - 35);
693 drawTextRJ(tr("[ok] = info"), 560 + 70, sl.getY2() + 4, DrawStyle::LIGHTTEXT);
695 // All static stuff done
698 Event* VEpgListAdvanced::getCurrentOptionEvent(ULONG& channel)
700 if (mode == OneChannel)
702 channel = channelNumber;
704 EventList* eventList = eventLista[0];
705 if (!eventList) return NULL;
707 for (Event* currentEvent : *eventList)
709 if (currentEvent->index == sl.getCurrentOption()) return currentEvent;
712 else if ((mode == Now) || (mode == Next))
714 ULONG slCurrentOptionData = reinterpret_cast<ULONG>(sl.getCurrentOptionData());
715 EventList* eventList = eventLista[slCurrentOptionData];
716 if (!eventList) return NULL;
717 channel = (*chanList)[slCurrentOptionData]->number;
719 if ((mode == Now) && (eventList->size() > 0)) return (*eventList)[0];
720 else if ((mode == Next) && (eventList->size() > 1)) return (*eventList)[1];
726 void VEpgListAdvanced::updateSelection()
730 if (mode == OneChannel)
732 TVMediaInfo* info = new TVMediaInfo();
733 info->setChannelLogo(channelNumber);
734 info->setStaticFallback(sa_tv);
735 setTitleBarIcon(info);
738 Event* toShow = getCurrentOptionEvent(channel);
742 toShow->loadinfos(channel);
743 std::stringstream description;
745 description << "\n" << toShow->title << "\n\n";
746 description << toShow->subtitle << "\n";
747 description << toShow->description;
752 if (toShow->movieInfo)
754 poster = toShow->movieInfo->poster;
757 if (toShow->seriesInfo)
759 if (toShow->seriesInfo->seasonposter.height)
761 poster = toShow->seriesInfo->seasonposter;
763 else if (toShow->seriesInfo->posters.size())
765 poster = toShow->seriesInfo->posters[0];
771 epgTVmedia.setTVMedia(poster.info, WTVMedia::ZoomHorizontal);
772 epgTVmedia.setVisible(true);
776 if (toShow->epgImage)
779 info.setPosterThumb(channel, toShow->id);
780 epgTVmedia.setTVMedia(info, WTVMedia::ZoomHorizontal);
781 epgTVmedia.setVisible(true);
783 else if (mode != OneChannel)
786 info.setChannelLogo(channel);
787 epgTVmedia.setTVMedia(info, WTVMedia::ZoomHorizontal);
788 epgTVmedia.setVisible(true);
792 epgTVmedia.setVisible(false);
796 epg.setText(description.str().c_str());
802 if (mode != OneChannel)
805 info.setChannelLogo(channel);
806 epgTVmedia.setTVMedia(info, WTVMedia::ZoomHorizontal);
807 epgTVmedia.setVisible(true);
811 epgTVmedia.setVisible(false);
816 int VEpgListAdvanced::handleCommand(int command)
825 boxstack->update(this);
826 return BoxStack::COMMAND_HANDLED;
834 boxstack->update(this);
835 return BoxStack::COMMAND_HANDLED;
838 case Input::SKIPBACK:
843 boxstack->update(this);
844 return BoxStack::COMMAND_HANDLED;
847 case Input::SKIPFORWARD:
852 boxstack->update(this);
853 return BoxStack::COMMAND_HANDLED;
859 return BoxStack::COMMAND_HANDLED;
865 return BoxStack::COMMAND_HANDLED;
871 return BoxStack::COMMAND_HANDLED;
877 return BoxStack::COMMAND_HANDLED;
882 if (sl.getNumOptions() == 0) return 2;
885 Event* current = getCurrentOptionEvent(channel);
889 LogNT::getInstance()->debug(TAG, "Found the option you pointed at. {} {}", current->title.c_str(), current->id);
890 unsigned int chanlistsize = chanList->size();
894 for (listIndex = 0; listIndex < chanlistsize; listIndex++)
896 chan = (*chanList)[listIndex];
897 if (chan->number == channel) break;
900 VEpgSummary* vr = new VEpgSummary(current, (*chanList)[listIndex]);
903 boxstack->update(vr);
905 return BoxStack::COMMAND_HANDLED;
908 // should not get to here
909 return BoxStack::ABANDON_COMMAND;
914 return BoxStack::DELETE_ME;
918 // stop command getting to any more views
919 return BoxStack::ABANDON_COMMAND;
922 void VEpgListAdvanced::processMessage(Message* m)
924 LogNT::getInstance()->debug(TAG, "Got message value {}", m->message);
926 if (m->message == Message::MOUSE_MOVE)
928 if (sl.mouseMove(m->parameter - getScreenX(), m->tag - getScreenY()))
931 boxstack->update(this);
934 else if (m->message == Message::MOUSE_LBDOWN)
936 int x = m->parameter - getScreenX();
937 int y = m->tag - getScreenY();
938 if (sl.mouseLBDOWN(x, y))
940 Input::sendInputKey(Input::OK);
942 else if (boxRed.mouseLBDOWN(x, y))
944 boxstack->handleCommand(Input::RED);
946 else if (boxGreen.mouseLBDOWN(x, y))
948 boxstack->handleCommand(Input::GREEN); // FIXME FIXME FIXME all these green? is this right?
950 else if (boxYellow.mouseLBDOWN(x, y))
952 boxstack->handleCommand(Input::GREEN);
954 else if (boxBlue.mouseLBDOWN(x, y))
956 boxstack->handleCommand(Input::GREEN);
960 if (coordsOutsideBox(m))
962 Input::sendInputKey(Input::BACK);
968 void VEpgListAdvanced::quickUpdate() //only quick for plattform that need it!
972 #ifdef GRADIENT_DRAWING