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);
490 char tempA[300]; // FIXME this is guesswork!
491 char tempB[300]; // FIXME
492 char tempC[300]; // FIXME
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(tempA, 300, "%d/%m/%y %H:%M ", &btime);
509 LOCALTIME_R(&eventEndTime, &btime);
510 strftime(tempB, 300, "- %H:%M ", &btime);
511 int check = SNPRINTF(tempC, 300, "\t %s\n \t \t%s%s", currentEvent->title.c_str(), tempA, tempB);
513 if ((check < 0) || (check > 299)) LogNT::getInstance()->debug(TAG, "String too big");
516 TVMediaInfo* info = new TVMediaInfo();
517 info->setPosterThumb(channelNumber, currentEvent->id);
518 info->setStaticFallback(sa_defposter);
519 currentEvent->index = sl.addOption(tempC, reinterpret_cast<void*>(currentEvent->id), first, info);
526 sl.hintSetCurrent(0);
530 sl.hintSetCurrent(saveIndex);
531 sl.hintSetTop(saveTop);
537 void VEpgListAdvanced::drawDataNowNext(bool next, bool doIndexPop)
539 int saveIndex = sl.getCurrentOption();
540 int saveTop = sl.getTopOption();
548 char tempA[300]; // FIXME this is guesswork!
549 char tempB[300]; // FIXME
550 char tempC[300]; // FIXME
553 Event* currentEvent = NULL;
554 EventList::iterator j;
557 if (next) minevents++;
559 int setcurrenthelper = 0;
561 unsigned int chanlistsize = chanList->size();
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(tempA, 300, "%H:%M ", &btime);
580 LOCALTIME_R(&eventEndTime, &btime);
581 strftime(tempB, 300, "- %H:%M ", &btime);
582 int check = SNPRINTF(tempC, 300, "%s\n%s\t %s%s", currentEvent->title.c_str(), chan->name, tempA, tempB);
584 if ((check < 0) || (check > 299)) LogNT::getInstance()->debug(TAG, "String too big");
588 sprintf(tempC, "\n%s", chan->name);
591 TVMediaInfo* info = new TVMediaInfo();
593 if ((*chanList)[listIndex]->number == channelNumber)
596 setcurrenthelper = listIndex;
599 info->setChannelLogo((*chanList)[listIndex]->number);
600 info->setStaticFallback(sa_tv);
601 int index = sl.addOption(tempC, reinterpret_cast<void*>(listIndex), first, info);
603 if (currentEvent) currentEvent->index = index;
610 sl.hintSetCurrent(setcurrenthelper);
614 sl.hintSetCurrent(saveIndex);
615 sl.hintSetTop(saveTop);
621 void VEpgListAdvanced::draw(bool doIndexPop)
623 // Single channel mode
629 unsigned int chanlistsize = chanList->size();
633 for (listIndex = 0; listIndex < chanlistsize; listIndex++)
635 chan = (*chanList)[listIndex];
637 if (chan->number == channelNumber) break;
640 sprintf(tempA, tr("Schedule - %s"), (*chanList)[listIndex]->name);
646 setTitleText(tr("Now"));
651 setTitleText(tr("Next"));
656 drawData(doIndexPop);
666 LOCALTIME_R(&now, &btime);
667 strftime(freeSpace, 299, "%d/%m/%y", &btime);
668 drawTextRJ(freeSpace, getWidth(), 5, DrawStyle::LIGHTTEXT);
675 w.nextSymbol = WSymbol::UP;
676 w.setPosition(20, area.h - 35);
679 w.nextSymbol = WSymbol::DOWN;
680 w.setPosition(50, area.h - 35);
683 w.nextSymbol = WSymbol::SKIPBACK;
684 w.setPosition(85, area.h - 35);
687 w.nextSymbol = WSymbol::SKIPFORWARD;
688 w.setPosition(115, area.h - 35);
691 drawTextRJ(tr("[ok] = info"), 560 + 70, sl.getY2() + 4, DrawStyle::LIGHTTEXT);
693 // All static stuff done
696 Event* VEpgListAdvanced::getCurrentOptionEvent(ULONG& channel)
698 if (mode == OneChannel)
700 channel = channelNumber;
702 EventList* eventList = eventLista[0];
703 if (!eventList) return NULL;
705 for (Event* currentEvent : *eventList)
707 if (currentEvent->index == sl.getCurrentOption()) return currentEvent;
710 else if ((mode == Now) || (mode == Next))
712 ULONG slCurrentOptionData = reinterpret_cast<ULONG>(sl.getCurrentOptionData());
713 EventList* eventList = eventLista[slCurrentOptionData];
714 if (!eventList) return NULL;
715 channel = (*chanList)[slCurrentOptionData]->number;
717 if ((mode == Now) && (eventList->size() > 0)) return (*eventList)[0];
718 else if ((mode == Next) && (eventList->size() > 1)) return (*eventList)[1];
724 void VEpgListAdvanced::updateSelection()
728 if (mode == OneChannel)
730 TVMediaInfo* info = new TVMediaInfo();
731 info->setChannelLogo(channelNumber);
732 info->setStaticFallback(sa_tv);
733 setTitleBarIcon(info);
736 Event* toShow = getCurrentOptionEvent(channel);
740 toShow->loadinfos(channel);
741 std::stringstream description;
743 description << "\n" << toShow->title << "\n\n";
744 description << toShow->subtitle << "\n";
745 description << toShow->description;
750 if (toShow->movieInfo)
752 poster = toShow->movieInfo->poster;
755 if (toShow->seriesInfo)
757 if (toShow->seriesInfo->seasonposter.height)
759 poster = toShow->seriesInfo->seasonposter;
761 else if (toShow->seriesInfo->posters.size())
763 poster = toShow->seriesInfo->posters[0];
769 epgTVmedia.setTVMedia(poster.info, WTVMedia::ZoomHorizontal);
770 epgTVmedia.setVisible(true);
774 if (toShow->epgImage)
777 info.setPosterThumb(channel, toShow->id);
778 epgTVmedia.setTVMedia(info, WTVMedia::ZoomHorizontal);
779 epgTVmedia.setVisible(true);
781 else if (mode != OneChannel)
784 info.setChannelLogo(channel);
785 epgTVmedia.setTVMedia(info, WTVMedia::ZoomHorizontal);
786 epgTVmedia.setVisible(true);
790 epgTVmedia.setVisible(false);
794 epg.setText(description.str().c_str());
800 if (mode != OneChannel)
803 info.setChannelLogo(channel);
804 epgTVmedia.setTVMedia(info, WTVMedia::ZoomHorizontal);
805 epgTVmedia.setVisible(true);
809 epgTVmedia.setVisible(false);
814 int VEpgListAdvanced::handleCommand(int command)
823 boxstack->update(this);
832 boxstack->update(this);
836 case Input::SKIPBACK:
841 boxstack->update(this);
845 case Input::SKIPFORWARD:
850 boxstack->update(this);
880 if (sl.getNumOptions() == 0) return 2;
883 Event* current = getCurrentOptionEvent(channel);
887 LogNT::getInstance()->debug(TAG, "Found the option you pointed at. {} {}", current->title.c_str(), current->id);
888 unsigned int chanlistsize = chanList->size();
892 for (listIndex = 0; listIndex < chanlistsize; listIndex++)
894 chan = (*chanList)[listIndex];
895 if (chan->number == channel) break;
898 VEpgSummary* vr = new VEpgSummary(current, (*chanList)[listIndex]);
901 boxstack->update(vr);
906 // should not get to here
916 // stop command getting to any more views
920 void VEpgListAdvanced::processMessage(Message* m)
922 LogNT::getInstance()->debug(TAG, "Got message value {}", m->message);
924 if (m->message == Message::MOUSE_MOVE)
926 if (sl.mouseMove(m->parameter - getScreenX(), m->tag - getScreenY()))
929 boxstack->update(this);
932 else if (m->message == Message::MOUSE_LBDOWN)
934 int x = m->parameter - getScreenX();
935 int y = m->tag - getScreenY();
936 if (sl.mouseLBDOWN(x, y))
938 boxstack->handleCommand(Input::OK); //simulate OK press
940 else if (boxRed.mouseLBDOWN(x, y))
942 boxstack->handleCommand(Input::RED);
944 else if (boxGreen.mouseLBDOWN(x, y))
946 boxstack->handleCommand(Input::GREEN); // FIXME all these green? is this right?
948 else if (boxYellow.mouseLBDOWN(x, y))
950 boxstack->handleCommand(Input::GREEN);
952 else if (boxBlue.mouseLBDOWN(x, y))
954 boxstack->handleCommand(Input::GREEN);
958 if (coordsOutsideBox(m))
960 boxstack->handleCommand(Input::BACK); //simulate cancel press
966 void VEpgListAdvanced::quickUpdate() //only quick for plattform that need it!
970 #ifdef GRADIENT_DRAWING