From patchwork Sat Jun 19 15:37:56 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Udo Richter X-Patchwork-Id: 12822 Received: from mail.tu-berlin.de ([130.149.7.33]) by www.linuxtv.org with esmtp (Exim 4.69) (envelope-from ) id 1OQ073-0003Of-My for vdr@linuxtv.org; Sat, 19 Jun 2010 17:37:42 +0200 X-tubIT-Incoming-IP: 213.165.64.20 Received: from mail.gmx.net ([213.165.64.20]) by mail.tu-berlin.de (exim-4.69/mailfrontend-d) with smtp for id 1OQ073-0003GQ-0D; Sat, 19 Jun 2010 17:37:41 +0200 Received: (qmail invoked by alias); 19 Jun 2010 15:37:39 -0000 Received: from p5B25137C.dip0.t-ipconnect.de (EHLO localhost) [91.37.19.124] by mail.gmx.net (mp050) with SMTP; 19 Jun 2010 17:37:39 +0200 X-Authenticated: #1417946 X-Provags-ID: V01U2FsdGVkX1/Js7VKPr/JoyF2w9c+/sllUwuE15cCc0T6RQRvVe XBH/Xu4+OtWSeJ Message-ID: <4C1CE454.5020706@gmx.de> Date: Sat, 19 Jun 2010 17:37:56 +0200 From: Udo Richter User-Agent: Mozilla/5.0 (X11; U; Linux i686; de; rv:1.9.1.10) Gecko/20100512 Lightning/1.0b1 Thunderbird/3.0.5 MIME-Version: 1.0 To: VDR Mailing List References: <17535410-9A18-4A0A-9886-5CEF3566C2BF@embl.de> <4C1A5B6D.3090606@gmx.de> In-Reply-To: <4C1A5B6D.3090606@gmx.de> X-Y-GMX-Trusted: 0 X-tubIT-Score: 0.0 () X-PMX-Version: 5.5.5.374460, Antispam-Engine: 2.7.1.369594, Antispam-Data: 2010.6.19.152413 X-PMX-Spam: Gauge=IIIIIIII, Probability=8%, Report=' MIME_TEXT_ONLY_MP_MIXED 0.05, MSGID_ADDED_BY_MTA 0.05, BODYTEXTP_SIZE_3000_LESS 0, BODY_SIZE_10000_PLUS 0, __BAT_BOUNDARY 0, __BOUNCE_CHALLENGE_SUBJ 0, __BOUNCE_NDR_SUBJ_EXEMPT 0, __CT 0, __CTYPE_HAS_BOUNDARY 0, __CTYPE_MULTIPART 0, __CTYPE_MULTIPART_MIXED 0, __HAS_MSGID 0, __MIME_TEXT_ONLY 0, __MIME_VERSION 0, __MOZILLA_MSGID 0, __SANE_MSGID 0, __TO_MALFORMED_2 0, __URI_NO_MAILTO 0, __URI_NO_PATH 0, __URI_NO_WWW 0, __USER_AGENT 0' X-LSpam-Score: -3.6 (---) X-LSpam-Report: No, score=-3.6 required=5.0 tests=AWL=0.038, BAYES_00=-2.599, RCVD_IN_DNSWL_LOW=-1 autolearn=ham Subject: Re: [vdr] Feature request: program guide scroll X-BeenThere: vdr@linuxtv.org X-Mailman-Version: 2.1.11 Precedence: list Reply-To: VDR Mailing List List-Id: VDR Mailing List List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 19 Jun 2010 15:37:42 -0000 Status: O X-Status: X-Keywords: X-UID: 23071 Am 17.06.2010 19:29, schrieb Udo Richter: > Am 17.06.2010 17:31, schrieb martinez: >> Can any kind person write this patch? > > I'll see if I can come up with something on the weekend. As always, the more close you look on it, the more complicated it gets. In other words, it got a little more than 12 lines... ;) The cMenuEvent can now switch through the list of events of the parent menu with the green and yellow buttons. Depending on the parent menu, the buttons either show channel names or event starting times. From timer menu (blue button), the green and yellow buttons stay empty. To gain access to the list of events, I've added an abstract cEventSequence class that is implemented by cMenuWhatsOn and cMenuSchedule. That way these two and the cMenuScheduleItem can continue to be private to menu.c. Since now the cMenuEvent can handle different events, a convenient shortcut had to be removed: Previously, the red and blue buttons were handled by the parent menu, not cMenuEvent itself. cMenuEvent now does this on its own. Also the constructor parameters CanSwitch and Buttons were dropped and replaced by dynamic code. By this change, the event info on blue key in timers menu gains the red and blue button for free. cMenuEvent had its ProcessKey re-arranged, as the original version could not handle sub-menus. (the parent menu did.) Timer menu got a bug fix to handle sub-sub-menus without overwriting the button bar. The attached patch is against vdr-1.6, but also cleanly applies and compiles on vdr-1.7.15. A little testing help and feedback is welcome. Check that the green and yellow buttons work in program, whats now, whats next and timer info menu, and keep an eye on button bar text in the event menu and the parent menu after exiting. Also, the t and T markers on events should change, and in the timer menu the '>' for active timers, if you change that. Try adding timers from the event menu for running and future events. Try whether the blue key switches to the right channel. And try whatever else you can imagine. Cheers, Udo diff -Naur vdr-1.6.0/menu.h vdr-1.6.0-MenuEventNext/menu.h --- vdr-1.6.0/menu.h 2008-02-10 17:01:53.000000000 +0100 +++ vdr-1.6.0-MenuEventNext/menu.h 2010-06-19 15:33:20.000000000 +0200 @@ -45,12 +45,28 @@ virtual eOSState ProcessKey(eKeys Key); }; +class cEventSequence { +public: + virtual const cEvent* GetEvent(int Nr) const = 0; + virtual int GetEventCount() const = 0; +}; + class cMenuEvent : public cOsdMenu { private: const cEvent *event; -public: - cMenuEvent(const cEvent *Event, bool CanSwitch = false, bool Buttons = false); + const cEventSequence *eventSequence; + int eventNr; + int otherChannel; + char *green; + char *yellow; + void UpdateEvent(); +public: + cMenuEvent(const cEvent *Event); + cMenuEvent(const cEventSequence *Events, int EventNr); + virtual ~cMenuEvent(); virtual void Display(void); + eOSState Record(void); + eOSState Switch(void); virtual eOSState ProcessKey(eKeys Key); }; diff -Naur vdr-1.6.0/menu.c vdr-1.6.0-MenuEventNext/menu.c --- vdr-1.6.0/menu.c 2008-03-16 12:15:28.000000000 +0100 +++ vdr-1.6.0-MenuEventNext/menu.c 2010-06-19 16:38:35.000000000 +0200 @@ -974,27 +974,99 @@ Add(new cMenuTimerItem(Timers.Get(TimerNumber)), true); Display(); } - if (Key != kNone) + if (Key != kNone && !HasSubMenu()) SetHelpKeys(); return state; } // --- cMenuEvent ------------------------------------------------------------ -cMenuEvent::cMenuEvent(const cEvent *Event, bool CanSwitch, bool Buttons) +cMenuEvent::cMenuEvent(const cEvent *Event) :cOsdMenu(tr("Event")) { event = Event; + eventNr = 0; + eventSequence = NULL; + green = NULL; + yellow = NULL; + UpdateEvent(); +} + +cMenuEvent::cMenuEvent(const cEventSequence *Events, int EventNr) +:cOsdMenu(tr("Event")) +{ + eventSequence = Events; + eventNr = EventNr; + green = NULL; + yellow = NULL; + UpdateEvent(); +} + +cMenuEvent::~cMenuEvent() { + if (green) + free(green); + if (yellow) + free(yellow); +} + +void cMenuEvent::UpdateEvent() +{ + const cEvent *eventPrev = NULL; + const cEvent *eventNext = NULL; + int TimerMatch = tmNone; + otherChannel = 0; + + if (eventSequence) { + event = eventSequence->GetEvent(eventNr); + eventPrev = eventSequence->GetEvent(eventNr-1); + eventNext = eventSequence->GetEvent(eventNr+1); + } + if (event) { cChannel *channel = Channels.GetByChannelID(event->ChannelID(), true); if (channel) { SetTitle(channel->Name()); - int TimerMatch = tmNone; - Timers.GetMatch(event, &TimerMatch); - if (Buttons) - SetHelp(TimerMatch == tmFull ? tr("Button$Timer") : tr("Button$Record"), NULL, NULL, CanSwitch ? tr("Button$Switch") : NULL); + if (channel->Number() != cDevice::CurrentChannel()) + otherChannel = channel->Number(); } + Timers.GetMatch(event, &TimerMatch); } + + if (green) { + free(green); + green = NULL; + } + if (eventPrev) { + if (eventPrev->ChannelID() == event->ChannelID()) { + time_t tstart = eventPrev->StartTime(); + struct tm tm_r; + struct tm *time = localtime_r(&tstart, &tm_r); + asprintf(&green, "%02d:%02d", time->tm_hour, time->tm_min); + } + else { + cChannel *channel = Channels.GetByChannelID(eventPrev->ChannelID(), true); + green = strdup(channel->Name()); + } + } + + if (yellow) { + free(yellow); + yellow = NULL; + } + if (eventNext) { + if (eventNext->ChannelID() == event->ChannelID()) { + time_t tstart = eventNext->StartTime(); + struct tm tm_r; + struct tm *time = localtime_r(&tstart, &tm_r); + asprintf(&yellow, "%02d:%02d", time->tm_hour, time->tm_min); + } + else { + cChannel *channel = Channels.GetByChannelID(eventNext->ChannelID(), true); + yellow = strdup(channel->Name()); + } + } + + SetHelp(TimerMatch == tmFull ? tr("Button$Timer") : tr("Button$Record"), green, yellow, otherChannel ? tr("Button$Switch") : NULL); } void cMenuEvent::Display(void) @@ -1005,34 +1077,87 @@ cStatus::MsgOsdTextItem(event->Description()); } -eOSState cMenuEvent::ProcessKey(eKeys Key) +eOSState cMenuEvent::Record(void) { - switch (Key) { - case kUp|k_Repeat: - case kUp: - case kDown|k_Repeat: - case kDown: - case kLeft|k_Repeat: - case kLeft: - case kRight|k_Repeat: - case kRight: - DisplayMenu()->Scroll(NORMALKEY(Key) == kUp || NORMALKEY(Key) == kLeft, NORMALKEY(Key) == kLeft || NORMALKEY(Key) == kRight); - cStatus::MsgOsdTextItem(NULL, NORMALKEY(Key) == kUp || NORMALKEY(Key) == kLeft); - return osContinue; - case kInfo: return osBack; - default: break; - } + if (event) { + int tm = tmNone; + cTimer *timer = Timers.GetMatch(event, &tm); + if (timer) + return AddSubMenu(new cMenuEditTimer(timer)); + timer = new cTimer(event); + cTimer *t = Timers.GetTimer(timer); + if (t) { + delete timer; + timer = t; + return AddSubMenu(new cMenuEditTimer(timer)); + } + else { + Timers.Add(timer); + Timers.SetModified(); + isyslog("timer %s added (active)", *timer->ToDescr()); + if (timer->Matches(0, false, NEWTIMERLIMIT)) + return AddSubMenu(new cMenuEditTimer(timer)); + UpdateEvent(); + Display(); + } + } + return osContinue; +} + +eOSState cMenuEvent::Switch(void) +{ + if (otherChannel) { + if (Channels.SwitchTo(otherChannel)) + return osEnd; + } + Skins.Message(mtError, tr("Can't switch channel!")); + return osContinue; +} + +eOSState cMenuEvent::ProcessKey(eKeys Key) +{ + bool HadSubMenu = HasSubMenu(); eOSState state = cOsdMenu::ProcessKey(Key); if (state == osUnknown) { switch (Key) { - case kGreen: - case kYellow: return osContinue; + case kUp|k_Repeat: + case kUp: + case kDown|k_Repeat: + case kDown: + case kLeft|k_Repeat: + case kLeft: + case kRight|k_Repeat: + case kRight: + DisplayMenu()->Scroll(NORMALKEY(Key) == kUp || NORMALKEY(Key) == kLeft, NORMALKEY(Key) == kLeft || NORMALKEY(Key) == kRight); + cStatus::MsgOsdTextItem(NULL, NORMALKEY(Key) == kUp || NORMALKEY(Key) == kLeft); + return osContinue; + case kInfo: return osBack; + case kRecord: + case kRed: return Record(); + case kGreen: if (eventSequence && eventNr > 0) { + eventNr--; + UpdateEvent(); + Display(); + } + return osContinue; + case kYellow: if (eventSequence && eventNr < eventSequence->GetEventCount()-1) { + eventNr++; + UpdateEvent(); + Display(); + } + return osContinue; + case kBlue: return Switch(); case kOk: return osBack; default: break; } } + else if (!HasSubMenu() && HadSubMenu) { + UpdateEvent(); + Display(); + } + return state; } @@ -1106,7 +1231,7 @@ // --- cMenuWhatsOn ---------------------------------------------------------- -class cMenuWhatsOn : public cOsdMenu { +class cMenuWhatsOn : public cOsdMenu, public cEventSequence { private: bool now; int helpKeys; @@ -1123,6 +1248,8 @@ static void SetCurrentChannel(int ChannelNr) { currentChannel = ChannelNr; } static const cEvent *ScheduleEvent(void); virtual eOSState ProcessKey(eKeys Key); + virtual const cEvent* GetEvent(int Nr) const; + virtual int GetEventCount() const; }; int cMenuWhatsOn::currentChannel = 0; @@ -1253,7 +1380,7 @@ case kBlue: return Switch(); case kInfo: case kOk: if (Count()) - return AddSubMenu(new cMenuEvent(((cMenuScheduleItem *)Get(Current()))->event, true, true)); + return AddSubMenu(new cMenuEvent(this, Current())); break; default: break; } @@ -1267,9 +1394,19 @@ return state; } +const cEvent* cMenuWhatsOn::GetEvent(int Nr) const { + if (Nr >= 0 && Nr < Count()) + return ((cMenuScheduleItem *)Get(Nr))->event; + return NULL; + } + +int cMenuWhatsOn::GetEventCount() const { + return Count(); + } + // --- cMenuSchedule --------------------------------------------------------- -class cMenuSchedule : public cOsdMenu { +class cMenuSchedule : public cOsdMenu, public cEventSequence { private: cSchedulesLock schedulesLock; const cSchedules *schedules; @@ -1290,6 +1427,8 @@ cMenuSchedule(void); virtual ~cMenuSchedule(); virtual eOSState ProcessKey(eKeys Key); + virtual const cEvent* GetEvent(int Nr) const; + virtual int GetEventCount() const; }; cMenuSchedule::cMenuSchedule(void) @@ -1518,7 +1657,7 @@ break; case kInfo: case kOk: if (Count()) - return AddSubMenu(new cMenuEvent(((cMenuScheduleItem *)Get(Current()))->event, otherChannel, true)); + return AddSubMenu(new cMenuEvent(this, Current())); break; default: break; } @@ -1546,6 +1685,16 @@ return state; } +const cEvent* cMenuSchedule::GetEvent(int Nr) const { + if (Nr >= 0 && Nr < Count()) + return ((cMenuScheduleItem *)Get(Nr))->event; + return NULL; + } + +int cMenuSchedule::GetEventCount() const { + return Count(); + } + // --- cMenuCommands --------------------------------------------------------- class cMenuCommands : public cOsdMenu {