2 Copyright 2005 Brian Walton
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, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 vepg presents a 2 dimensional electronic programme guide with channels down
22 the y axis and time along the x axis.
23 Programmes are layed on the x axis as alterate coloured blocks with as much
24 of the programme title as will fit inside the block shown as text.
25 Up and down commands step through the channels whilst left and right commands
26 move through the programmes of the currently selected channel.
27 When a programme is selected, it highlights in the grid and full programe details
28 (start time, title and description) are displayed in an area at te top left of the screen.
29 Any currently programmed timers will display in the grid and in the orogramme detail window as red
30 It is possible to select a programme to be recorded by pressing the record button.
31 The video stream currently being viewed is shown as quarter screen in the top right.
37 #include "vchannellist.h"
40 #include "vepgsettimer.h"
51 VEpg* VEpg::instance = NULL;
53 VEpg::VEpg(void* tparent, UINT tcurrentChannelIndex, ChannelList* tchanList)
56 currentChannelIndex = tcurrentChannelIndex;
58 // PAL / NTSC sizes -----------------------
61 //int summaryLines, summaryLowerPadding;
63 int fontHeight=getFontHeight() + 4;
64 //UINT gridRows; // is a class member
67 if (Video::getInstance()->getFormat() == Video::PAL)
84 //summaryLowerPadding = 28;
88 int screenwidthhalf=Video::getInstance()->getScreenWidth()/2;
89 int screenheighthalf=Video::getInstance()->getScreenHeight()/2;
90 // summaryLines = ((float)screenheighthalf)/((float)fontHeight))-1;
91 // summaryLowerPadding = screenheighthalf-summaryLines*(fontHeight);
92 gridRows = (screenheighthalf-fontHeight*2-40)/fontHeight;
95 // initialise variables and pointers
96 boxstack = BoxStack::getInstance();
102 eventLista.resize(gridRows);
103 for(UINT listIndex = 0; listIndex < gridRows; listIndex++)
105 // initialise array of pointers to eventlist structures
106 eventLista[listIndex] = NULL;
109 // Create pallet on which to paint our epg view and position it in centre of screen.
110 // Need to reduce size to deal with overscanning TVs.
112 setSize(Video::getInstance()->getScreenWidth(), Video::getInstance()->getScreenHeight());
117 // DrawStyle transparent = DrawStyle(0, 0, 0, 0);
118 // setBackgroundColour(transparent);
120 // progTitle.setSurface(surface);
121 progTitle.setPosition(0,0);
122 progTitle.setSize(screenwidthhalf,(fontHeight) * 1 + ypos); //paragraph line seperation is 4 pixels
123 progTitle.setBackgroundColour(DrawStyle::TITLEBARBACKGROUND);
124 progTitle.setTextPos(xpos, ypos);
128 // progInfo.setSurface(surface);
129 progInfo.setBackgroundColour(DrawStyle::VIEWBACKGROUND);
130 progInfo.setPosition(0, progTitle.getY2());
131 progInfo.setSize(screenwidthhalf,screenheighthalf-progTitle.getY2()+10);
132 progInfo.setTextPos(xpos, 0);
136 // chanName.setSurface(surface);
137 chanName.setSize(510, (fontHeight));
138 chanName.setPosition(screenwidthhalf, screenheighthalf - 2*fontHeight);
139 DrawStyle t1(0, 0, 0, 90);
140 chanName.setBackgroundColour(t1);
143 // create area to display list of channels
144 // chanListbox.setSurface(surface); // add channel list
145 chanListbox.setPosition(0, progInfo.getY2() + fontHeight + 4); // position channel list
146 chanListbox.setSize(150, ((getFontHeight() + 2) * gridRows) + 5); //listbox line seperation is 2 pixels
147 chanListbox.setGap(2);
148 chanListbox.addColumn(xpos);
151 // populate channel list
156 for (UINT i = 0; i < chanList->size(); i++)
158 chan = (*chanList)[i];
159 if (i == currentChannelIndex)
161 chan->index = chanListbox.addOption(chan->name, 0, first);
164 chanName.setText((*chanList)[chanListbox.getCurrentOption()]->name);
167 window_x= chanListbox.getRootBoxOffsetX() + chanListbox.getWidth() + 5;
168 window_width=(Video::getInstance()->getScreenWidth() - window_x +3)/3;
170 listTop = chanListbox.getTopOption();
171 chanListbox.draw(); // doing this to allow chanListbox.getBottomOption() in updateEventList() to work
172 time(<ime); // set ltime to now
173 ltime = prevHour(<ime); // set ltime to previous hour TODO make this half hour?
174 time(&selTime); // set selTime to now
175 updateEventList(); // get list of programmes
177 vdisplay.mode=Window;
178 vdisplay.fallbackMode=Quarter;
179 vdisplay.x=Video::getInstance()->getScreenWidth()/2;
181 vdisplay.width=Video::getInstance()->getScreenWidth()/2;
182 vdisplay.height=Video::getInstance()->getScreenHeight()/2;
185 void VEpg::preDelete()
187 Timers::getInstance()->cancelTimer(this, 1);
195 for(UINT listIndex = 0; listIndex < gridRows; listIndex++)
197 if (eventLista[listIndex])
199 (eventLista)[listIndex]->clear();
200 delete eventLista[listIndex];
203 // delete [] eventLista; // FIXME
205 // destroy dynamically allocated memory
208 VEpg* VEpg::getInstance()
213 void VEpg::setInfo(Event* event)
216 struct tm* btime; // to hold programme start and end time
217 char timeString[9]; // to hold programme start and end time
218 int length = strlen(event->title); // calculate length of programme title string
219 char* title = new char[length + 15]; // create string to hold start time, end time and programme title
220 btime = localtime((time_t*)&event->time); //get programme start time
222 strftime(timeString, 9, "%0H:%0M - ", btime); // and format it as hh:mm -
224 strftime(timeString, 9, "%H:%M - ", btime); // and format it as hh:mm -
226 strcpy(title, timeString); // put it in our buffer
227 t = event->time + event->duration; //get programme end time
228 btime = localtime(&t);
230 strftime(timeString, 7, "%0H:%0M ", btime); // and format it as hh:mm -
232 strftime(timeString, 7, "%H:%M ", btime); // and format it as hh:mm -
234 strcat(title, timeString); // put it in our buffer
235 strcat(title, event->title); // then add the programme title
236 progTitle.setText(title); // sput this sring in our text box
237 length = strlen(event->description);
238 char* info = new char[length + 1]; // create programme detail string
239 strcpy(info, event->description);
240 progInfo.setText(info); // show programme detail string
241 // destroy dynamically allocated memory
248 // View::draw(); // draw pallet
250 DrawStyle transparent = DrawStyle(0, 0, 0, 0);
251 fillColour(transparent);
254 // Moved all the dynamic data drawing to a seperate function
256 // Display the status and key stuff at the bottom
258 UINT keyx = chanListbox.getRootBoxOffsetX() + chanListbox.getColumn(0);
259 UINT keyy = chanListbox.getRootBoxOffsetY() + chanListbox.getHeight() + 2;
260 rectangle (0, keyy, Video::getInstance()->getScreenWidth() ,
261 Video::getInstance()->getScreenHeight()-keyy, DrawStyle::DARKGREY);
266 w.nextSymbol = WSymbol::LEFTARROW;
267 w.setPosition(keyx + 1, keyy + 20);
270 w.nextSymbol = WSymbol::UP;
271 w.setPosition(keyx + 26, keyy + 3);
274 w.nextSymbol = WSymbol::DOWN;
275 w.setPosition(keyx + 26, keyy + 36);
278 w.nextSymbol = WSymbol::RIGHTARROW;
279 w.setPosition(keyx + 50, keyy + 20);
282 drawTextCentre(tr("OK"), keyx + 35, keyy + 20, DrawStyle::LIGHTTEXT);
284 rectangle(keyx + 72, keyy + 4, 104, getFontHeight() + 2, DrawStyle::RED);
285 drawText(tr("Page up"), keyx + 74, keyy + 5, DrawStyle::LIGHTTEXT);
287 rectangle(keyx + 72, keyy + getFontHeight() + 8, 104, getFontHeight() + 2, DrawStyle::GREEN);
288 drawText(tr("Page down"), keyx + 74, keyy + getFontHeight() + 9, DrawStyle::LIGHTTEXT);
290 rectangle(keyx + 180, keyy + 4, 104, getFontHeight() + 2, DrawStyle::YELLOW);
291 drawText(tr("-24 hours"), keyx + 182, keyy + 5, DrawStyle::LIGHTTEXT);
293 rectangle(keyx + 180, keyy + getFontHeight() + 8, 104, getFontHeight() + 2, DrawStyle::BLUE);
294 drawText(tr("+24 hours"), keyx + 182, keyy + getFontHeight() + 9, DrawStyle::LIGHTTEXT);
296 rectangle(keyx + 290, keyy + 4, 180, getFontHeight() + 2, DrawStyle::GREY);
297 drawText(tr("Guide / Back: Close"), keyx + 292 , keyy + 5, DrawStyle::LIGHTTEXT);
299 rectangle(keyx + 290, keyy + getFontHeight() + 8, 180, getFontHeight() + 2, DrawStyle::GREY);
300 DrawStyle red = DrawStyle(130, 0, 0);
301 drawText(tr("Rec: Set timer"), keyx + 292, keyy + getFontHeight() + 9, red);
303 rectangle(keyx + 474, keyy + 4, 128, getFontHeight() + 2, DrawStyle::GREY);
304 w.nextSymbol = WSymbol::PLAY;
305 w.setPosition(keyx + 476, keyy + 5);
307 drawText(tr("Sel channel"), keyx + 496, keyy + 5, DrawStyle::LIGHTTEXT);
309 rectangle(keyx + 474, keyy + getFontHeight() + 8, 128, getFontHeight() + 2, DrawStyle::GREY);
310 drawText(tr("Go: Preview"), keyx + 476, keyy + getFontHeight() + 9, DrawStyle::LIGHTTEXT);
313 // Draw all the dynamic data
317 void VEpg::drawData()
319 // Not doing View::draw() every time causes
320 // things not to be cleared off the surface properly
321 // So, blank out the data area first
322 int screenwidth=Video::getInstance()->getScreenWidth();
324 chanListbox.getRootBoxOffsetX(),
325 chanListbox.getRootBoxOffsetY() - getFontHeight() - 3,
326 window_width * MINUTE_SCALE,
327 chanListbox.getHeight() + getFontHeight() + 4,
332 chanName.draw(); // TODO this should be dealt with by vvideolive
337 // Set timer to redraw to move the current time bar
341 if (dt == 0) dt = 60;
343 Timers::getInstance()->setTimerT(this, 1, dt);
346 void VEpg::timercall(int clientReference)
349 boxstack->update(this);
352 int VEpg::handleCommand(int command)
358 { // cursor up the channel list
361 boxstack->update(this);
364 case Remote::DF_DOWN:
366 { // cursor down the channel list
367 Log::getInstance()->log("VEPG", Log::DEBUG, "Down start");
371 boxstack->update(this);
372 Log::getInstance()->log("VEPG", Log::DEBUG, "Down end");
376 case Remote::DF_LEFT:
378 { // cursor left through time
379 selTime = thisEvent.time - 1;
381 boxstack->update(this);
384 case Remote::DF_RIGHT:
387 // cursor right through time
388 selTime = thisEvent.time + thisEvent.duration;
390 boxstack->update(this);
395 // cursor up one page
396 chanListbox.pageUp();
398 boxstack->update(this);
403 // cursor down one page
404 chanListbox.pageDown();
406 boxstack->update(this);
411 // step forward 24 hours
412 selTime += 24 * 60 * 60;
414 boxstack->update(this);
419 // step forward 24 hours
420 selTime -= 24 * 60 * 60;
422 boxstack->update(this);
427 if (!chanList) return 2;
428 Log::getInstance()->log("VEPG", Log::DEBUG, "ID %lu TIME %lu DURATION %lu TITLE %s", thisEvent.id, thisEvent.time, thisEvent.duration, thisEvent.title);
429 VEpgSetTimer* vs = new VEpgSetTimer(&thisEvent, (*chanList)[chanListbox.getCurrentOption()]);
432 boxstack->update(vs);
439 if (!chanList) return 2;
441 // select programme and display menu TODO currently just changes to selected channel
443 currentChannelIndex = chanListbox.getCurrentOption();
447 Message* m = new Message(); // Must be done after this view deleted
450 m->message = Message::CHANNEL_CHANGE;
451 m->parameter = (*chanList)[currentChannelIndex]->number;
452 Command::getInstance()->postMessageNoLock(m);
457 if(command == Remote::GO)
459 // GO just changes channel in preview, PLAY changes channel and returns to normal TV
466 case Remote::CHANNELUP:
468 if (currentChannelIndex == (chanList->size() - 1)) // at the end
469 currentChannelIndex = 0;
471 ++currentChannelIndex;
475 Message* m = new Message(); // Must be done after this view deleted
478 m->message = Message::CHANNEL_CHANGE;
479 m->parameter = (*chanList)[currentChannelIndex]->number;
480 Command::getInstance()->postMessageNoLock(m);
487 case Remote::CHANNELDOWN:
489 if (currentChannelIndex == 0) // at the start
490 currentChannelIndex = chanList->size() - 1; // so go to end
492 --currentChannelIndex;
496 Message* m = new Message(); // Must be done after this view deleted
499 m->message = Message::CHANNEL_CHANGE;
500 m->parameter = (*chanList)[currentChannelIndex]->number;
501 Command::getInstance()->postMessageNoLock(m);
509 // stop command getting to any more views
513 void VEpg::drawgrid() // redraws grid and select programme
515 // draw the grid of programmes
518 time(&t); // set t = now
520 selTime = t; // don't allow cursor in the past
521 if(listTop != chanListbox.getTopOption())
523 // chanListbox has scrolled TODO speed up by changing only rows that have changed
524 listTop = chanListbox.getTopOption();
527 if ((selTime >= ltime + window_width * 60) || (selTime <= ltime))
529 // we have cursored back before left time of window
530 //TODO check that this and above don't happen together
531 ltime = prevHour(&selTime);
535 DrawStyle white = DrawStyle(255, 255, 255, 255);
541 strftime(timeString, 19, "%a %d %b", tms);
542 int timey = chanListbox.getRootBoxOffsetY() - getFontHeight() - 3;
544 drawTextRJ(timeString, timex - 10, timey, DrawStyle::LIGHTTEXT); // print date
545 strftime(timeString, 19, "%H:%M", tms);
546 drawText(timeString, timex, timey, DrawStyle::LIGHTTEXT); // print left time
548 rectangle(155, timey + getFontHeight(), 2, 7, white);
551 strftime(timeString, 19, "%H:%M", tms);
552 drawText(timeString, timex + 180, timey, DrawStyle::LIGHTTEXT); // print middle time
553 rectangle(335, timey + getFontHeight(), 2, 7, white);
556 strftime(timeString, 19, "%H:%M", tms);
557 drawText(timeString, timex + 360, timey, DrawStyle::LIGHTTEXT); // print right time
558 rectangle(515, timey + getFontHeight(), 2, 7, white);
559 // pointer to selTime
560 //rectangle(155 + (selTime - ltime) / 20, timey + getFontHeight(), 2, 7, DrawStyle(255, 50, 50, 255));
564 if ((t >= ltime) && (t < (ltime + 9000)))
566 rectangle(155 + (t - ltime) / 20, timey + getFontHeight(), 2, ((getFontHeight() + 2) * gridRows) + 7 + 2, DrawStyle::RED);
569 // TODO should the above two comditional statements be combined to avoid calling updateEventList() twice?
571 Event noevent; // an event to use if there are gaps in the epg
572 thisEvent.setdescription(tr("There are no programme details available for this period"));
573 thisEvent.duration = window_width * 60;
574 thisEvent.time = ltime;
575 thisEvent.settitle(tr("No programme details"));
577 bool swapColour = false; // alternate cell colour
578 bool currentRow = false;
579 int y = chanListbox.getRootBoxOffsetY() + 5; // vertical position of cell
580 DrawStyle bg, fg; // background colour of cells in grid
581 // for each displayed channel, find programmes that fall in 2.5 hour time window
582 for(UINT listIndex = 0; listIndex < gridRows; listIndex++)
584 if (listTop + (int)listIndex >= chanListbox.getBottomOption())
585 continue; // ensure nothing populates grid below last channel
587 currentRow = (listTop + (int)listIndex == chanListbox.getCurrentOption());
588 noevent.time = ltime;
589 noevent.duration = window_width * 60;
590 noevent.settitle("");
591 paintCell(&noevent, y, DrawStyle::NOPROGRAMME, DrawStyle::LIGHTTEXT); // fill row with no programme colour to be painted ove with valid programmes
594 thisEvent.setdescription(tr("There are no programme details available for this period"));
595 thisEvent.duration = window_width * 60;
596 thisEvent.time = ltime;
597 thisEvent.settitle(tr("No programme details"));
600 if (eventLista[listIndex])
602 sort(eventLista[listIndex]->begin(), eventLista[listIndex]->end(), EventSorter());
603 for(e = 0; e < (eventLista[listIndex])->size(); e++) // step through events for this channel
605 fg = DrawStyle::LIGHTTEXT;
606 event = (*eventLista[listIndex])[e];
609 UINT end = event->time + event->duration; // programme end time
610 if(event->time >= UINT(ltime) + (window_width * 60)) // programme starts after RHS of window
611 continue; // that's enough of this channel's events
612 if(end <= UINT(ltime)) // programme ends before LHS of window
613 continue; // this event is before the window - let's try the next event
614 // this event is one we are interested in
615 bg = (swapColour)?DrawStyle::PROGRAMMEA:DrawStyle::PROGRAMMEB; // alternate cell colour
616 swapColour = !swapColour; // it wil be the other colour next time
617 if(event->time <= UINT(selTime) && end > UINT(selTime) && currentRow)
619 // this is the selected programme
620 thisEvent.setdescription(event->description);
621 thisEvent.duration = event->duration;
622 thisEvent.time = event->time;
623 thisEvent.settitle(event->title);
624 thisEvent.id = event->id;
625 if(thisEvent.id == 0)
627 bg = DrawStyle::SELECTHIGHLIGHT; // highlight cell
628 fg = DrawStyle::DARKTEXT;
632 if (currentRow && thisEvent.id == 0)
634 if (end <= UINT(selTime) && end > UINT(thisEvent.time))
635 thisEvent.time = end;
636 if (event->time > UINT(selTime) && event->time < thisEvent.time + thisEvent.duration)
637 thisEvent.duration = event->time - thisEvent.time;
640 paintCell(event, y, bg, fg);
646 // no event list for this channel. Already painted noevent colour so just highlight if selected
649 bg = DrawStyle::SELECTHIGHLIGHT; // highlight cell
650 fg = DrawStyle::DARKTEXT;
651 paintCell(&thisEvent, y, bg, fg);
655 bg = DrawStyle::NOPROGRAMME;
656 fg = DrawStyle::LIGHTTEXT;
657 noevent.settitle(tr("No programme details"));
658 paintCell(&noevent, y, bg, fg);
661 y += getFontHeight() + 2;
666 void VEpg::updateEventList()
668 if (!chanList) return;
670 for(UINT listIndex = 0; listIndex < gridRows; listIndex++)
672 if(listTop + listIndex >= UINT(chanListbox.getBottomOption()))
674 chan = (*chanList)[listTop + listIndex];
675 if (eventLista[listIndex])
677 (eventLista)[listIndex]->clear();
678 delete eventLista[listIndex];
680 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
684 void VEpg::setCurrentChannel()
686 chanName.setText((*chanList)[currentChannelIndex]->name);
689 chanName.getRootBoxRegion(&r);
690 boxstack->update(this, &r);
693 void VEpg::paintCell(Event* event, int yOffset, const DrawStyle& bg, const DrawStyle& fg)
696 w = x = 0; // keep compiler happy
698 h = getFontHeight(); // TODO if want border around text, need to increae this and wselectlist line height
699 UINT end = event->time + event->duration; // programme end time
700 if(event->time <= UINT(ltime) && end > UINT(ltime)) // spans start of displayed window
702 x = 155; // LHS of window
703 if (end > (UINT(ltime) + (window_width * 60)))
704 w = window_width * MINUTE_SCALE; // spans full 2 hour window
706 w = MINUTE_SCALE * (event->time + event->duration - ltime ) / 60; // get width of remaining programme
708 if((event->time >= UINT(ltime)) && (event->time <= UINT(ltime) + (window_width * 60))) // starts within window
710 x = 155 + (MINUTE_SCALE * (event->time - ltime) / 60);
711 w = MINUTE_SCALE * event->duration / 60;
712 //if (w > 155 + MINUTE_SCALE * WINDOW_WIDTH -x)
713 // w = w + x - 155 - MINUTE_SCALE * WINDOW_WIDTH; // ends outside window
715 if (w > 155 + window_width * MINUTE_SCALE - x)
716 w = 155 + window_width * MINUTE_SCALE -x; // limit cells to RHS of window
717 rectangle(x, y, w, h, bg);
718 char* tt = new char[strlen(event->title) + 1];
719 strcpy (tt, event->title);
721 unsigned int cur_length=1;
722 unsigned int text_max=strlen(tt);
724 for (textPos = 0; textPos <text_max; textPos+=cur_length)
726 wchar_t cur_char=getWChar(tt+textPos,&cur_length);
727 float thisCharWidth = charWidth(cur_char);
728 if (textWidth + thisCharWidth > w) // text will not fit in cell
732 textWidth += thisCharWidth;
734 char* tT = new char[textPos+1];
737 strncpy(tT, tt, textPos );
739 surface->drawText(tT, x+2, y, fg);
745 time_t VEpg::prevHour(time_t* t)
754 void VEpg::processMessage(Message* m)
756 if (m->message == Message::MOUSE_MOVE)
758 if (chanListbox.mouseMove((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))
761 boxstack->update(this);
764 else if (m->message == Message::MOUSE_LBDOWN)
766 if (chanListbox.mouseLBDOWN((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))
768 boxstack->handleCommand(Remote::OK); //simulate OK press
772 //check if press is outside this view! then simulate cancel
773 int x=(m->parameter>>16)-getScreenX();
774 int y=(m->parameter&0xFFFF)-getScreenY();
775 int keyx = chanListbox.getRootBoxOffsetX();
776 int keyy = chanListbox.getRootBoxOffsetY() + chanListbox.getHeight() + 2;
778 if (x<0 || y <0 || x>(int)getWidth() || y>(int)getHeight())
780 boxstack->handleCommand(Remote::BACK); //simulate cancel press
782 else if (x>=(keyx+72) && y>=(keyy+4) &&x<=(keyx+72+104) &&y<=(keyy+4+getFontHeight() + 2))
784 boxstack->handleCommand(Remote::RED);
786 else if (x>=(keyx+72) && y>=(keyy+ getFontHeight() + 8) &&x<=(keyx+72+104) &&y<=(keyy+8+2*getFontHeight() + 2))
788 boxstack->handleCommand(Remote::GREEN);
790 else if (x>=(keyx+180) && y>=(keyy+4) &&x<=(keyx+180+104) &&y<=(keyy+4+getFontHeight() + 2))
792 boxstack->handleCommand(Remote::YELLOW);
794 else if (x>=(keyx+180) && y>=(keyy+ getFontHeight() + 8) &&x<=(keyx+180+104) &&y<=(keyy+8+2*getFontHeight() + 2))
796 boxstack->handleCommand(Remote::BLUE);
798 else if (x>=(keyx+290) && y>=(keyy+4) &&x<=(keyx+180+290) &&y<=(keyy+4+getFontHeight() + 2))
800 boxstack->handleCommand(Remote::BACK);
802 else if (x>=(keyx+290) && y>=(keyy+ getFontHeight() + 8) &&x<=(keyx+290+180) &&y<=(keyy+8+2*getFontHeight() + 2))
804 boxstack->handleCommand(Remote::RECORD);
806 else if (x>=(keyx+474) && y>=(keyy+4) &&x<=(keyx+128+474) &&y<=(keyy+4+getFontHeight() + 2))
808 boxstack->handleCommand(Remote::PLAY);
810 else if (x>=(keyx+474) && y>=(keyy+ getFontHeight() + 8) &&x<=(keyx+238+474) &&y<=(keyy+8+2*getFontHeight() + 2))
812 boxstack->handleCommand(Remote::GO);
814 else if ( x>=(chanListbox.getRootBoxOffsetX())
815 && y>=(chanListbox.getRootBoxOffsetY() + 5)
816 // &&x<=(chanListbox.getOffsetX()+155 + window_width * MINUTE_SCALE)
817 &&y<=(chanListbox.getRootBoxOffsetY() - getFontHeight()
818 - 3+(int)chanListbox.getHeight() + getFontHeight() + 3)
821 int cy=y-(chanListbox.getRootBoxOffsetY() + 5);
822 int row=cy/(getFontHeight()+2);
823 int clistTop = chanListbox.getTopOption();
824 chanListbox.hintSetCurrent(clistTop+row);
826 time_t ttime = cx*60/MINUTE_SCALE+ltime;
827 //x = 155 + (MINUTE_SCALE * (event->time - ltime) / 60);
831 boxstack->update(this);