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(VVideoLiveTV* 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();
127 VEpgListAdvanced::~VEpgListAdvanced()
132 void VEpgListAdvanced::setButtonText()
138 textRed.setText(tr("Record"));
139 textGreen.setText(tr("Now"));
140 textYellow.setText(tr("Next"));
141 textBlue.setText(tr("Guide"));
146 textRed.setText(tr("Record"));
147 textGreen.setText(tr("Next"));
148 textYellow.setText(tr("Schedule"));
149 textBlue.setText(tr("Switch"));
154 textRed.setText(tr("Record"));
155 textGreen.setText(tr("Now"));
156 textYellow.setText(tr("Schedule"));
157 textBlue.setText(tr("Switch"));
163 void VEpgListAdvanced::doRed()
168 void VEpgListAdvanced::doGreen()
186 void VEpgListAdvanced::doYellow()
204 void VEpgListAdvanced::doBlue()
222 void VEpgListAdvanced::doNext()
224 LogNT::getInstance()->debug(TAG, "doNext");
225 ULONG slCurrentOption = reinterpret_cast<ULONG>(sl.getCurrentOptionData());
227 if (mode != OneChannel)
229 Channel* chan = (*chanList)[slCurrentOption];
230 channelNumber = chan->number;
234 updateEpgDataNowNext(true);
236 TVMediaInfo* info = new TVMediaInfo();
237 info->setStaticArtwork(sa_tv);
238 setTitleBarIcon(info);
240 boxstack->update(this);
243 void VEpgListAdvanced::doNow()
245 LogNT::getInstance()->debug(TAG, "doNow");
246 ULONG slCurrentOption = reinterpret_cast<ULONG>(sl.getCurrentOptionData());
248 if (mode != OneChannel)
250 Channel* chan = (*chanList)[slCurrentOption];
251 channelNumber = chan->number;
255 updateEpgDataNowNext(true);
257 TVMediaInfo* info = new TVMediaInfo();
258 info->setStaticArtwork(sa_tv);
259 setTitleBarIcon(info);
261 boxstack->update(this);
264 void VEpgListAdvanced::doProgramm()
266 LogNT::getInstance()->debug(TAG, "doProgram");
268 ULONG slCurrentOption = reinterpret_cast<ULONG>(sl.getCurrentOptionData());
269 Channel* chan = (*chanList)[slCurrentOption];
270 channelNumber = chan->number;
271 updateEpgDataChannel();
273 TVMediaInfo* info = new TVMediaInfo();
274 info->setChannelLogo(channelNumber);
275 info->setStaticFallback(sa_tv);
276 setTitleBarIcon(info);
278 boxstack->update(this);
281 void VEpgListAdvanced::doSwitch()
285 if (mode != OneChannel)
287 ULONG slCurrentOption = reinterpret_cast<ULONG>(sl.getCurrentOptionData());
288 Channel* chan = (*chanList)[slCurrentOption];
289 channelNumber = chan->number;
292 LogNT::getInstance()->debug(TAG, "doSwitch {}", channelNumber);
293 Message* m = new Message(); // Must be done after this view deleted
296 m->message = Message::CHANNEL_CHANGE;
297 m->parameter = channelNumber;
299 MessageQueue::getInstance()->postMessage(m);
305 #pragma warning(disable : 4703)
308 void VEpgListAdvanced::doRecord()
311 Event* current = getCurrentOptionEvent(channel);
315 LogNT::getInstance()->debug(TAG, "Found the option you pointed at. {} {}", current->title, current->id);
316 unsigned int chanlistsize = chanList->size();
320 for (listIndex = 0; listIndex < chanlistsize; listIndex++)
322 chan = (*chanList)[listIndex];
324 if (chan->number == channel) break;
327 LogNT::getInstance()->debug(TAG, "ID {} TIME {} DURATION {} TITLE {}",
328 current->id, current->time, current->duration, current->title);
329 VEpgSetTimer* vs = new VEpgSetTimer(current, chan);
332 boxstack->update(vs);
336 void VEpgListAdvanced::doGrid()
338 if (mode != OneChannel)
340 ULONG slCurrentOption = reinterpret_cast<ULONG>(sl.getCurrentOptionData());
341 Channel* chan = (*chanList)[slCurrentOption];
342 channelNumber = chan->number;
346 unsigned int chanlistsize = chanList->size();
349 for (listIndex = 0; listIndex < chanlistsize; listIndex++)
351 chan = (*chanList)[listIndex];
352 if (chan->number == channelNumber) break;
355 VEpg* vepg = new VEpg(videolive, listIndex, chanList);
358 boxstack->update(vepg);
361 void VEpgListAdvanced::clearEventList()
363 std::vector<EventList*>::iterator itty = eventLista.begin();
365 while (itty != eventLista.end())
381 * if (!chanList) return;
383 for(UINT listIndex = 0; listIndex < gridRows; listIndex++)
385 if(listTop + listIndex >= UINT(chanListbox.getBottomOption()))
387 chan = (*chanList)[listTop + listIndex];
388 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
393 void VEpgListAdvanced::updateEpgData()
399 //updateEpgDataChannel();
405 updateEpgDataNowNext(false);
411 void VEpgListAdvanced::updateEpgDataNowNext(bool changeState)
416 UINT chanlistsize = chanList->size();
421 eventLista.resize(chanList->size());
424 for (UINT listIndex = 0; listIndex < chanlistsize; listIndex++)
426 if (listIndex >= chanlistsize) continue;
428 chan = (*chanList)[listIndex];
430 if (chan->number == channelNumber)
432 startupdate = listIndex - sl.getNumOptionsDisplayable() - 2;
433 endupdate = listIndex + sl.getNumOptionsDisplayable() + 2;
440 startupdate = sl.getTopOption() - 2;
441 endupdate = sl.getBottomOption() + 1;
449 for (int listIndex = startupdate; listIndex < endupdate; listIndex++)
451 if (listIndex < 0) continue;
452 if (listIndex >= static_cast<int>(chanlistsize)) continue;
454 chan = (*chanList)[listIndex];
456 if (!eventLista[listIndex]) eventLista[listIndex] = VDR::getInstance()->getChannelSchedule(chan->number, now, 4 * 60 * 60);
460 void VEpgListAdvanced::updateEpgDataChannel()
463 eventLista.resize(1);
466 eventLista[0] = VDR::getInstance()->getChannelSchedule(channelNumber, now, 24 * 60 * 60 * 30); // one month
467 LogNT::getInstance()->debug(TAG, "Eventlist {:#x} {}", (void*)eventLista[0], channelNumber);
470 void VEpgListAdvanced::drawData(bool doIndexPop)
472 if (mode == OneChannel) drawDataChannel(doIndexPop);
473 else if (mode == Next) drawDataNowNext(true, doIndexPop);
474 else if (mode == Now) drawDataNowNext(false, doIndexPop);
477 void VEpgListAdvanced::drawDataChannel(bool doIndexPop)
479 int saveIndex = sl.getCurrentOption();
480 int saveTop = sl.getTopOption();
484 sl.addColumn(25 + 7);
485 sl.addColumn(25 + 7 + 7);
492 char startTimeStr[16];
495 Event* currentEvent = NULL;
496 EventList::iterator j;
497 EventList* eventList = eventLista[0];
501 for (j = eventList->begin(); j != eventList->end(); j++)
504 time_t eventStartTime = static_cast<time_t>(currentEvent->time);
505 time_t eventEndTime = static_cast<time_t>(currentEvent->time + currentEvent->duration);
507 LOCALTIME_R(&eventStartTime, &btime);
508 strftime(startTimeStr, 16, "%d/%m/%y %H:%M", &btime);
509 LOCALTIME_R(&eventEndTime, &btime);
510 strftime(endTimeStr, 16, "%H:%M", &btime);
511 std::string eventText = fmt::format("\t {}\n \t \t{} - {}", currentEvent->title, startTimeStr, endTimeStr);
514 TVMediaInfo* info = new TVMediaInfo();
515 info->setPosterThumb(channelNumber, currentEvent->id);
516 info->setStaticFallback(sa_defposter);
518 currentEvent->index = sl.addOption(eventText, reinterpret_cast<void*>(currentEvent->id), first, info);
525 sl.hintSetCurrent(0);
529 sl.hintSetCurrent(saveIndex);
530 sl.hintSetTop(saveTop);
536 void VEpgListAdvanced::drawDataNowNext(bool next, bool doIndexPop)
538 int saveIndex = sl.getCurrentOption();
539 int saveTop = sl.getTopOption();
547 char startTimeStr[16];
551 Event* currentEvent = NULL;
552 EventList::iterator j;
555 if (next) minevents++;
557 int setcurrenthelper = 0;
559 unsigned int chanlistsize = chanList->size();
561 std::string eventText;
563 for (UINT listIndex = 0; listIndex < chanlistsize; listIndex++)
566 chan = (*chanList)[listIndex];
568 EventList* eventList = eventLista[listIndex];
570 if (eventList && (eventList->size() >= minevents))
572 j = eventList->begin();
574 currentEvent = j[minevents - 1];
575 time_t eventStartTime = static_cast<time_t>(currentEvent->time);
576 time_t eventEndTime = static_cast<time_t>(currentEvent->time + currentEvent->duration);
578 LOCALTIME_R(&eventStartTime, &btime);
579 strftime(startTimeStr, 16, "%H:%M", &btime);
580 LOCALTIME_R(&eventEndTime, &btime);
581 strftime(endTimeStr, 16, "%H:%M", &btime);
583 eventText = fmt::format("{}\n{}\t{} - {}", currentEvent->title, chan->name, startTimeStr, endTimeStr);
587 eventText = fmt::format("\n{}", chan->name);
590 TVMediaInfo* info = new TVMediaInfo();
592 if ((*chanList)[listIndex]->number == channelNumber)
595 setcurrenthelper = listIndex;
598 info->setChannelLogo((*chanList)[listIndex]->number);
599 info->setStaticFallback(sa_tv);
600 int index = sl.addOption(eventText, reinterpret_cast<void*>(listIndex), first, info);
602 if (currentEvent) currentEvent->index = index;
609 sl.hintSetCurrent(setcurrenthelper);
613 sl.hintSetCurrent(saveIndex);
614 sl.hintSetTop(saveTop);
620 void VEpgListAdvanced::draw(bool doIndexPop)
622 // Single channel mode
628 unsigned int chanlistsize = chanList->size();
632 for (listIndex = 0; listIndex < chanlistsize; listIndex++)
634 chan = (*chanList)[listIndex];
636 if (chan->number == channelNumber) break;
639 sprintf(tempA, tr("Schedule - %s"), (*chanList)[listIndex]->name);
645 setTitleText(tr("Now"));
650 setTitleText(tr("Next"));
655 drawData(doIndexPop);
665 LOCALTIME_R(&now, &btime);
666 strftime(freeSpace, 299, "%d/%m/%y", &btime);
667 drawTextRJ(freeSpace, getWidth(), 5, DrawStyle::LIGHTTEXT);
674 w.nextSymbol = WSymbol::UP;
675 w.setPosition(20, area.h - 35);
678 w.nextSymbol = WSymbol::DOWN;
679 w.setPosition(50, area.h - 35);
682 w.nextSymbol = WSymbol::SKIPBACK;
683 w.setPosition(85, area.h - 35);
686 w.nextSymbol = WSymbol::SKIPFORWARD;
687 w.setPosition(115, area.h - 35);
690 drawTextRJ(tr("[ok] = info"), 560 + 70, sl.getY2() + 4, DrawStyle::LIGHTTEXT);
692 // All static stuff done
695 Event* VEpgListAdvanced::getCurrentOptionEvent(ULONG& channel)
697 if (mode == OneChannel)
699 channel = channelNumber;
701 EventList* eventList = eventLista[0];
702 if (!eventList) return NULL;
704 for (Event* currentEvent : *eventList)
706 if (currentEvent->index == sl.getCurrentOption()) return currentEvent;
709 else if ((mode == Now) || (mode == Next))
711 ULONG slCurrentOptionData = reinterpret_cast<ULONG>(sl.getCurrentOptionData());
712 EventList* eventList = eventLista[slCurrentOptionData];
713 if (!eventList) return NULL;
714 channel = (*chanList)[slCurrentOptionData]->number;
716 if ((mode == Now) && (eventList->size() > 0)) return (*eventList)[0];
717 else if ((mode == Next) && (eventList->size() > 1)) return (*eventList)[1];
723 void VEpgListAdvanced::updateSelection()
727 if (mode == OneChannel)
729 TVMediaInfo* info = new TVMediaInfo();
730 info->setChannelLogo(channelNumber);
731 info->setStaticFallback(sa_tv);
732 setTitleBarIcon(info);
735 Event* toShow = getCurrentOptionEvent(channel);
739 toShow->loadinfos(channel);
740 std::stringstream description;
742 description << "\n" << toShow->title << "\n\n";
743 description << toShow->subtitle << "\n";
744 description << toShow->description;
749 if (toShow->movieInfo)
751 poster = toShow->movieInfo->poster;
754 if (toShow->seriesInfo)
756 if (toShow->seriesInfo->seasonposter.height)
758 poster = toShow->seriesInfo->seasonposter;
760 else if (toShow->seriesInfo->posters.size())
762 poster = toShow->seriesInfo->posters[0];
768 epgTVmedia.setTVMedia(poster.info, WTVMedia::ZoomHorizontal);
769 epgTVmedia.setVisible(true);
773 if (toShow->epgImage)
776 info.setPosterThumb(channel, toShow->id);
777 epgTVmedia.setTVMedia(info, WTVMedia::ZoomHorizontal);
778 epgTVmedia.setVisible(true);
780 else if (mode != OneChannel)
783 info.setChannelLogo(channel);
784 epgTVmedia.setTVMedia(info, WTVMedia::ZoomHorizontal);
785 epgTVmedia.setVisible(true);
789 epgTVmedia.setVisible(false);
793 epg.setText(description.str().c_str());
799 if (mode != OneChannel)
802 info.setChannelLogo(channel);
803 epgTVmedia.setTVMedia(info, WTVMedia::ZoomHorizontal);
804 epgTVmedia.setVisible(true);
808 epgTVmedia.setVisible(false);
813 int VEpgListAdvanced::handleCommand(int command)
822 boxstack->update(this);
823 return BoxStack::COMMAND_HANDLED;
831 boxstack->update(this);
832 return BoxStack::COMMAND_HANDLED;
835 case Input::SKIPBACK:
840 boxstack->update(this);
841 return BoxStack::COMMAND_HANDLED;
844 case Input::SKIPFORWARD:
849 boxstack->update(this);
850 return BoxStack::COMMAND_HANDLED;
856 return BoxStack::COMMAND_HANDLED;
862 return BoxStack::COMMAND_HANDLED;
868 return BoxStack::COMMAND_HANDLED;
874 return BoxStack::COMMAND_HANDLED;
879 if (sl.getNumOptions() == 0) return 2;
882 Event* current = getCurrentOptionEvent(channel);
886 LogNT::getInstance()->debug(TAG, "Found the option you pointed at. {} {}", current->title.c_str(), current->id);
887 unsigned int chanlistsize = chanList->size();
891 for (listIndex = 0; listIndex < chanlistsize; listIndex++)
893 chan = (*chanList)[listIndex];
894 if (chan->number == channel) break;
897 VEpgSummary* vr = new VEpgSummary(current, (*chanList)[listIndex]);
900 boxstack->update(vr);
902 return BoxStack::COMMAND_HANDLED;
905 // should not get to here
906 return BoxStack::ABANDON_COMMAND;
911 return BoxStack::DELETE_ME;
915 // stop command getting to any more views
916 return BoxStack::ABANDON_COMMAND;
919 void VEpgListAdvanced::processMessage(Message* m)
921 LogNT::getInstance()->debug(TAG, "Got message value {}", m->message);
923 if (m->message == Message::MOUSE_MOVE)
925 if (sl.mouseMove(m->parameter - getScreenX(), m->tag - getScreenY()))
928 boxstack->update(this);
931 else if (m->message == Message::MOUSE_LBDOWN)
933 int x = m->parameter - getScreenX();
934 int y = m->tag - getScreenY();
935 if (sl.mouseLBDOWN(x, y))
937 boxstack->handleCommand(Input::OK); //simulate OK press
939 else if (boxRed.mouseLBDOWN(x, y))
941 boxstack->handleCommand(Input::RED);
943 else if (boxGreen.mouseLBDOWN(x, y))
945 boxstack->handleCommand(Input::GREEN); // FIXME all these green? is this right?
947 else if (boxYellow.mouseLBDOWN(x, y))
949 boxstack->handleCommand(Input::GREEN);
951 else if (boxBlue.mouseLBDOWN(x, y))
953 boxstack->handleCommand(Input::GREEN);
957 if (coordsOutsideBox(m))
959 boxstack->handleCommand(Input::BACK); //simulate cancel press
965 void VEpgListAdvanced::quickUpdate() //only quick for plattform that need it!
969 #ifdef GRADIENT_DRAWING