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*3-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 time_t eventtime = event->time;
221 btime = localtime((time_t*)&eventtime); //get programme start time
223 strftime(timeString, 9, "%0H:%0M - ", btime); // and format it as hh:mm -
225 strftime(timeString, 9, "%H:%M - ", btime); // and format it as hh:mm -
227 strcpy(title, timeString); // put it in our buffer
228 t = event->time + event->duration; //get programme end time
229 btime = localtime(&t);
231 strftime(timeString, 7, "%0H:%0M ", btime); // and format it as hh:mm -
233 strftime(timeString, 7, "%H:%M ", btime); // and format it as hh:mm -
235 strcat(title, timeString); // put it in our buffer
236 strcat(title, event->title); // then add the programme title
237 progTitle.setText(title); // sput this sring in our text box
238 length = strlen(event->description);
239 char* info = new char[length + 1]; // create programme detail string
240 strcpy(info, event->description);
241 progInfo.setText(info); // show programme detail string
242 // destroy dynamically allocated memory
249 // View::draw(); // draw pallet
251 DrawStyle transparent = DrawStyle(0, 0, 0, 0);
252 fillColour(transparent);
255 // Moved all the dynamic data drawing to a seperate function
257 // Display the status and key stuff at the bottom
259 UINT keyx = chanListbox.getRootBoxOffsetX() + chanListbox.getColumn(0);
260 UINT keyy = chanListbox.getRootBoxOffsetY() + chanListbox.getHeight() + 2;
261 rectangle (0, keyy, Video::getInstance()->getScreenWidth() ,
262 Video::getInstance()->getScreenHeight()-keyy, DrawStyle::DARKGREY);
267 w.nextSymbol = WSymbol::LEFTARROW;
268 w.setPosition(keyx + 1, keyy + 20);
271 w.nextSymbol = WSymbol::UP;
272 w.setPosition(keyx + 26, keyy + 3);
275 w.nextSymbol = WSymbol::DOWN;
276 w.setPosition(keyx + 26, keyy + 36);
279 w.nextSymbol = WSymbol::RIGHTARROW;
280 w.setPosition(keyx + 50, keyy + 20);
283 drawTextCentre(tr("OK"), keyx + 35, keyy + 20, DrawStyle::LIGHTTEXT);
285 rectangle(keyx + 72, keyy + 4, 104, getFontHeight() + 2, DrawStyle::RED);
286 drawText(tr("Page up"), keyx + 74, keyy + 5, DrawStyle::LIGHTTEXT);
288 rectangle(keyx + 72, keyy + getFontHeight() + 8, 104, getFontHeight() + 2, DrawStyle::GREEN);
289 drawText(tr("Page down"), keyx + 74, keyy + getFontHeight() + 9, DrawStyle::LIGHTTEXT);
291 rectangle(keyx + 180, keyy + 4, 104, getFontHeight() + 2, DrawStyle::YELLOW);
292 drawText(tr("-24 hours"), keyx + 182, keyy + 5, DrawStyle::LIGHTTEXT);
294 rectangle(keyx + 180, keyy + getFontHeight() + 8, 104, getFontHeight() + 2, DrawStyle::BLUE);
295 drawText(tr("+24 hours"), keyx + 182, keyy + getFontHeight() + 9, DrawStyle::LIGHTTEXT);
297 rectangle(keyx + 290, keyy + 4, 180, getFontHeight() + 2, DrawStyle::GREY);
298 drawText(tr("Guide / Back: Close"), keyx + 292 , keyy + 5, DrawStyle::LIGHTTEXT);
300 rectangle(keyx + 290, keyy + getFontHeight() + 8, 180, getFontHeight() + 2, DrawStyle::GREY);
301 DrawStyle red = DrawStyle(130, 0, 0);
302 drawText(tr("Rec: Set timer"), keyx + 292, keyy + getFontHeight() + 9, red);
304 rectangle(keyx + 474, keyy + 4, 128, getFontHeight() + 2, DrawStyle::GREY);
305 w.nextSymbol = WSymbol::PLAY;
306 w.setPosition(keyx + 476, keyy + 5);
308 drawText(tr("Sel channel"), keyx + 496, keyy + 5, DrawStyle::LIGHTTEXT);
310 rectangle(keyx + 474, keyy + getFontHeight() + 8, 128, getFontHeight() + 2, DrawStyle::GREY);
311 drawText(tr("Go: Preview"), keyx + 476, keyy + getFontHeight() + 9, DrawStyle::LIGHTTEXT);
314 // Draw all the dynamic data
318 void VEpg::drawData()
320 // Not doing View::draw() every time causes
321 // things not to be cleared off the surface properly
322 // So, blank out the data area first
323 int screenwidth=Video::getInstance()->getScreenWidth();
325 chanListbox.getRootBoxOffsetX(),
326 chanListbox.getRootBoxOffsetY() - getFontHeight() - 3,
327 window_width * MINUTE_SCALE,
328 chanListbox.getHeight() + getFontHeight() + 4,
333 chanName.draw(); // TODO this should be dealt with by vvideolive
338 // Set timer to redraw to move the current time bar
342 if (dt == 0) dt = 60;
344 Timers::getInstance()->setTimerT(this, 1, dt);
347 void VEpg::timercall(int clientReference)
350 boxstack->update(this);
353 int VEpg::handleCommand(int command)
359 { // cursor up the channel list
362 boxstack->update(this);
365 case Remote::DF_DOWN:
367 { // cursor down the channel list
368 Log::getInstance()->log("VEPG", Log::DEBUG, "Down start");
372 boxstack->update(this);
373 Log::getInstance()->log("VEPG", Log::DEBUG, "Down end");
377 case Remote::DF_LEFT:
379 { // cursor left through time
380 selTime = thisEvent.time - 1;
382 boxstack->update(this);
385 case Remote::DF_RIGHT:
388 // cursor right through time
389 selTime = thisEvent.time + thisEvent.duration;
391 boxstack->update(this);
396 // cursor up one page
397 chanListbox.pageUp();
399 boxstack->update(this);
404 // cursor down one page
405 chanListbox.pageDown();
407 boxstack->update(this);
412 // step forward 24 hours
413 selTime += 24 * 60 * 60;
415 boxstack->update(this);
420 // step forward 24 hours
421 selTime -= 24 * 60 * 60;
423 boxstack->update(this);
428 if (!chanList) return 2;
429 Log::getInstance()->log("VEPG", Log::DEBUG, "ID %lu TIME %lu DURATION %lu TITLE %s", thisEvent.id, thisEvent.time, thisEvent.duration, thisEvent.title);
430 VEpgSetTimer* vs = new VEpgSetTimer(&thisEvent, (*chanList)[chanListbox.getCurrentOption()]);
433 boxstack->update(vs);
440 if (!chanList) return 2;
442 // select programme and display menu TODO currently just changes to selected channel
444 currentChannelIndex = chanListbox.getCurrentOption();
448 Message* m = new Message(); // Must be done after this view deleted
451 m->message = Message::CHANNEL_CHANGE;
452 m->parameter = (*chanList)[currentChannelIndex]->number;
453 Command::getInstance()->postMessageNoLock(m);
458 if(command == Remote::GO)
460 // GO just changes channel in preview, PLAY changes channel and returns to normal TV
467 case Remote::CHANNELUP:
469 if (currentChannelIndex == (chanList->size() - 1)) // at the end
470 currentChannelIndex = 0;
472 ++currentChannelIndex;
476 Message* m = new Message(); // Must be done after this view deleted
479 m->message = Message::CHANNEL_CHANGE;
480 m->parameter = (*chanList)[currentChannelIndex]->number;
481 Command::getInstance()->postMessageNoLock(m);
488 case Remote::CHANNELDOWN:
490 if (currentChannelIndex == 0) // at the start
491 currentChannelIndex = chanList->size() - 1; // so go to end
493 --currentChannelIndex;
497 Message* m = new Message(); // Must be done after this view deleted
500 m->message = Message::CHANNEL_CHANGE;
501 m->parameter = (*chanList)[currentChannelIndex]->number;
502 Command::getInstance()->postMessageNoLock(m);
510 // stop command getting to any more views
514 void VEpg::drawgrid() // redraws grid and select programme
516 // draw the grid of programmes
519 time(&t); // set t = now
521 selTime = t; // don't allow cursor in the past
522 if(listTop != chanListbox.getTopOption())
524 // chanListbox has scrolled TODO speed up by changing only rows that have changed
525 listTop = chanListbox.getTopOption();
528 if ((selTime >= ltime + window_width * 60) || (selTime <= ltime))
530 // we have cursored back before left time of window
531 //TODO check that this and above don't happen together
532 ltime = prevHour(&selTime);
536 DrawStyle white = DrawStyle(255, 255, 255, 255);
542 strftime(timeString, 19, "%a %d %b", tms);
543 int timey = chanListbox.getRootBoxOffsetY() - getFontHeight() - 3;
545 drawTextRJ(timeString, timex - 10, timey, DrawStyle::LIGHTTEXT); // print date
546 strftime(timeString, 19, "%H:%M", tms);
547 drawText(timeString, timex, timey, DrawStyle::LIGHTTEXT); // print left time
549 rectangle(155, timey + getFontHeight(), 2, 7, white);
552 strftime(timeString, 19, "%H:%M", tms);
553 drawText(timeString, timex + 180, timey, DrawStyle::LIGHTTEXT); // print middle time
554 rectangle(335, timey + getFontHeight(), 2, 7, white);
557 strftime(timeString, 19, "%H:%M", tms);
558 drawText(timeString, timex + 360, timey, DrawStyle::LIGHTTEXT); // print right time
559 rectangle(515, timey + getFontHeight(), 2, 7, white);
560 // pointer to selTime
561 //rectangle(155 + (selTime - ltime) / 20, timey + getFontHeight(), 2, 7, DrawStyle(255, 50, 50, 255));
565 if ((t >= ltime) && (t < (ltime + 9000)))
567 rectangle(155 + (t - ltime) / 20, timey + getFontHeight(), 2, ((getFontHeight() + 2) * gridRows) + 7 + 2, DrawStyle::RED);
570 // TODO should the above two comditional statements be combined to avoid calling updateEventList() twice?
572 Event noevent; // an event to use if there are gaps in the epg
573 thisEvent.setdescription(tr("There are no programme details available for this period"));
574 thisEvent.duration = window_width * 60;
575 thisEvent.time = ltime;
576 thisEvent.settitle(tr("No programme details"));
578 bool swapColour = false; // alternate cell colour
579 bool currentRow = false;
580 int y = chanListbox.getRootBoxOffsetY() + 5; // vertical position of cell
581 DrawStyle bg, fg; // background colour of cells in grid
582 // for each displayed channel, find programmes that fall in 2.5 hour time window
583 for(UINT listIndex = 0; listIndex < gridRows; listIndex++)
585 if (listTop + (int)listIndex >= chanListbox.getBottomOption())
586 continue; // ensure nothing populates grid below last channel
588 currentRow = (listTop + (int)listIndex == chanListbox.getCurrentOption());
589 noevent.time = ltime;
590 noevent.duration = window_width * 60;
591 noevent.settitle("");
592 paintCell(&noevent, y, DrawStyle::NOPROGRAMME, DrawStyle::LIGHTTEXT); // fill row with no programme colour to be painted ove with valid programmes
595 thisEvent.setdescription(tr("There are no programme details available for this period"));
596 thisEvent.duration = window_width * 60;
597 thisEvent.time = ltime;
598 thisEvent.settitle(tr("No programme details"));
601 if (eventLista[listIndex])
603 sort(eventLista[listIndex]->begin(), eventLista[listIndex]->end(), EventSorter());
604 for(e = 0; e < (eventLista[listIndex])->size(); e++) // step through events for this channel
606 fg = DrawStyle::LIGHTTEXT;
607 event = (*eventLista[listIndex])[e];
610 UINT end = event->time + event->duration; // programme end time
611 if(event->time >= UINT(ltime) + (window_width * 60)) // programme starts after RHS of window
612 continue; // that's enough of this channel's events
613 if(end <= UINT(ltime)) // programme ends before LHS of window
614 continue; // this event is before the window - let's try the next event
615 // this event is one we are interested in
616 bg = (swapColour)?DrawStyle::PROGRAMMEA:DrawStyle::PROGRAMMEB; // alternate cell colour
617 swapColour = !swapColour; // it wil be the other colour next time
618 if(event->time <= UINT(selTime) && end > UINT(selTime) && currentRow)
620 // this is the selected programme
621 thisEvent.setdescription(event->description);
622 thisEvent.duration = event->duration;
623 thisEvent.time = event->time;
624 thisEvent.settitle(event->title);
625 thisEvent.id = event->id;
626 if(thisEvent.id == 0)
628 bg = DrawStyle::SELECTHIGHLIGHT; // highlight cell
629 fg = DrawStyle::DARKTEXT;
633 if (currentRow && thisEvent.id == 0)
635 if (end <= UINT(selTime) && end > UINT(thisEvent.time))
636 thisEvent.time = end;
637 if (event->time > UINT(selTime) && event->time < thisEvent.time + thisEvent.duration)
638 thisEvent.duration = event->time - thisEvent.time;
641 paintCell(event, y, bg, fg);
647 // no event list for this channel. Already painted noevent colour so just highlight if selected
650 bg = DrawStyle::SELECTHIGHLIGHT; // highlight cell
651 fg = DrawStyle::DARKTEXT;
652 paintCell(&thisEvent, y, bg, fg);
656 bg = DrawStyle::NOPROGRAMME;
657 fg = DrawStyle::LIGHTTEXT;
658 noevent.settitle(tr("No programme details"));
659 paintCell(&noevent, y, bg, fg);
662 y += getFontHeight() + 2;
667 void VEpg::updateEventList()
669 if (!chanList) return;
671 for(UINT listIndex = 0; listIndex < gridRows; listIndex++)
673 if(listTop + listIndex >= UINT(chanListbox.getBottomOption()))
675 chan = (*chanList)[listTop + listIndex];
676 if (eventLista[listIndex])
678 (eventLista)[listIndex]->clear();
679 delete eventLista[listIndex];
681 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
685 void VEpg::setCurrentChannel()
687 chanName.setText((*chanList)[currentChannelIndex]->name);
690 chanName.getRootBoxRegion(&r);
691 boxstack->update(this, &r);
694 void VEpg::paintCell(Event* event, int yOffset, const DrawStyle& bg, const DrawStyle& fg)
697 w = x = 0; // keep compiler happy
699 h = getFontHeight(); // TODO if want border around text, need to increae this and wselectlist line height
700 UINT end = event->time + event->duration; // programme end time
701 if(event->time <= UINT(ltime) && end > UINT(ltime)) // spans start of displayed window
703 x = 155; // LHS of window
704 if (end > (UINT(ltime) + (window_width * 60)))
705 w = window_width * MINUTE_SCALE; // spans full 2 hour window
707 w = MINUTE_SCALE * (event->time + event->duration - ltime ) / 60; // get width of remaining programme
709 if((event->time >= UINT(ltime)) && (event->time <= UINT(ltime) + (window_width * 60))) // starts within window
711 x = 155 + (MINUTE_SCALE * (event->time - ltime) / 60);
712 w = MINUTE_SCALE * event->duration / 60;
713 //if (w > 155 + MINUTE_SCALE * WINDOW_WIDTH -x)
714 // w = w + x - 155 - MINUTE_SCALE * WINDOW_WIDTH; // ends outside window
716 if (w > 155 + window_width * MINUTE_SCALE - x)
717 w = 155 + window_width * MINUTE_SCALE -x; // limit cells to RHS of window
718 rectangle(x, y, w, h, bg);
719 char* tt = new char[strlen(event->title) + 1];
720 strcpy (tt, event->title);
722 unsigned int cur_length=1;
723 unsigned int text_max=strlen(tt);
725 if (Osd::getInstance()->charSet()!=1) mchar=true;
727 memset((void*)&state,0,sizeof(state));
730 for (textPos = 0; textPos <text_max; textPos+=cur_length)
734 cur_length = mbrtowc(&cur_char, tt + textPos, text_max-textPos, &state);
735 if (cur_length <= 0){
738 } else cur_char= *(tt+textPos);
739 float thisCharWidth = charWidth(cur_char);
740 if (textWidth + thisCharWidth > w) // text will not fit in cell
744 textWidth += thisCharWidth;
746 char* tT = new char[textPos+1];
749 strncpy(tT, tt, textPos );
751 surface->drawText(tT, x+2, y, fg);
757 time_t VEpg::prevHour(time_t* t)
766 void VEpg::processMessage(Message* m)
768 if (m->message == Message::MOUSE_MOVE)
770 if (chanListbox.mouseMove((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))
773 boxstack->update(this);
776 else if (m->message == Message::MOUSE_LBDOWN)
778 if (chanListbox.mouseLBDOWN((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))
780 boxstack->handleCommand(Remote::OK); //simulate OK press
784 //check if press is outside this view! then simulate cancel
785 int x=(m->parameter>>16)-getScreenX();
786 int y=(m->parameter&0xFFFF)-getScreenY();
787 int keyx = chanListbox.getRootBoxOffsetX();
788 int keyy = chanListbox.getRootBoxOffsetY() + chanListbox.getHeight() + 2;
790 if (x<0 || y <0 || x>(int)getWidth() || y>(int)getHeight())
792 boxstack->handleCommand(Remote::BACK); //simulate cancel press
794 else if (x>=(keyx+72) && y>=(keyy+4) &&x<=(keyx+72+104) &&y<=(keyy+4+getFontHeight() + 2))
796 boxstack->handleCommand(Remote::RED);
798 else if (x>=(keyx+72) && y>=(keyy+ getFontHeight() + 8) &&x<=(keyx+72+104) &&y<=(keyy+8+2*getFontHeight() + 2))
800 boxstack->handleCommand(Remote::GREEN);
802 else if (x>=(keyx+180) && y>=(keyy+4) &&x<=(keyx+180+104) &&y<=(keyy+4+getFontHeight() + 2))
804 boxstack->handleCommand(Remote::YELLOW);
806 else if (x>=(keyx+180) && y>=(keyy+ getFontHeight() + 8) &&x<=(keyx+180+104) &&y<=(keyy+8+2*getFontHeight() + 2))
808 boxstack->handleCommand(Remote::BLUE);
810 else if (x>=(keyx+290) && y>=(keyy+4) &&x<=(keyx+180+290) &&y<=(keyy+4+getFontHeight() + 2))
812 boxstack->handleCommand(Remote::BACK);
814 else if (x>=(keyx+290) && y>=(keyy+ getFontHeight() + 8) &&x<=(keyx+290+180) &&y<=(keyy+8+2*getFontHeight() + 2))
816 boxstack->handleCommand(Remote::RECORD);
818 else if (x>=(keyx+474) && y>=(keyy+4) &&x<=(keyx+128+474) &&y<=(keyy+4+getFontHeight() + 2))
820 boxstack->handleCommand(Remote::PLAY);
822 else if (x>=(keyx+474) && y>=(keyy+ getFontHeight() + 8) &&x<=(keyx+238+474) &&y<=(keyy+8+2*getFontHeight() + 2))
824 boxstack->handleCommand(Remote::GO);
826 else if ( x>=(chanListbox.getRootBoxOffsetX())
827 && y>=(chanListbox.getRootBoxOffsetY() + 5)
828 // &&x<=(chanListbox.getOffsetX()+155 + window_width * MINUTE_SCALE)
829 &&y<=(chanListbox.getRootBoxOffsetY() - getFontHeight()
830 - 3+(int)chanListbox.getHeight() + getFontHeight() + 3)
833 int cy=y-(chanListbox.getRootBoxOffsetY() + 5);
834 int row=cy/(getFontHeight()+2);
835 int clistTop = chanListbox.getTopOption();
836 chanListbox.hintSetCurrent(clistTop+row);
838 time_t ttime = cx*60/MINUTE_SCALE+ltime;
839 //x = 155 + (MINUTE_SCALE * (event->time - ltime) / 60);
843 boxstack->update(this);