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
178 void VEpg::preDelete()
180 Timers::getInstance()->cancelTimer(this, 1);
188 for(UINT listIndex = 0; listIndex < gridRows; listIndex++)
190 if (eventLista[listIndex])
192 (eventLista)[listIndex]->clear();
193 delete eventLista[listIndex];
196 // delete [] eventLista; // FIXME
198 // destroy dynamically allocated memory
201 VEpg* VEpg::getInstance()
206 void VEpg::setInfo(Event* event)
209 struct tm* btime; // to hold programme start and end time
210 char timeString[9]; // to hold programme start and end time
211 int length = strlen(event->title); // calculate length of programme title string
212 char* title = new char[length + 15]; // create string to hold start time, end time and programme title
213 btime = localtime((time_t*)&event->time); //get programme start time
215 strftime(timeString, 9, "%0H:%0M - ", btime); // and format it as hh:mm -
217 strftime(timeString, 9, "%H:%M - ", btime); // and format it as hh:mm -
219 strcpy(title, timeString); // put it in our buffer
220 t = event->time + event->duration; //get programme end time
221 btime = localtime(&t);
223 strftime(timeString, 7, "%0H:%0M ", btime); // and format it as hh:mm -
225 strftime(timeString, 7, "%H:%M ", btime); // and format it as hh:mm -
227 strcat(title, timeString); // put it in our buffer
228 strcat(title, event->title); // then add the programme title
229 progTitle.setText(title); // sput this sring in our text box
230 length = strlen(event->description);
231 char* info = new char[length + 1]; // create programme detail string
232 strcpy(info, event->description);
233 progInfo.setText(info); // show programme detail string
234 // destroy dynamically allocated memory
241 // View::draw(); // draw pallet
243 DrawStyle transparent = DrawStyle(0, 0, 0, 0);
244 fillColour(transparent);
247 // Moved all the dynamic data drawing to a seperate function
249 // Display the status and key stuff at the bottom
251 UINT keyx = chanListbox.getRootBoxOffsetX() + chanListbox.getColumn(0);
252 UINT keyy = chanListbox.getRootBoxOffsetY() + chanListbox.getHeight() + 2;
253 rectangle (0, keyy, Video::getInstance()->getScreenWidth() ,
254 Video::getInstance()->getScreenHeight()-keyy, DrawStyle::DARKGREY);
259 w.nextSymbol = WSymbol::LEFTARROW;
260 w.setPosition(keyx + 1, keyy + 20);
263 w.nextSymbol = WSymbol::UP;
264 w.setPosition(keyx + 26, keyy + 3);
267 w.nextSymbol = WSymbol::DOWN;
268 w.setPosition(keyx + 26, keyy + 36);
271 w.nextSymbol = WSymbol::RIGHTARROW;
272 w.setPosition(keyx + 50, keyy + 20);
275 drawTextCentre(tr("OK"), keyx + 35, keyy + 20, DrawStyle::LIGHTTEXT);
277 rectangle(keyx + 72, keyy + 4, 104, getFontHeight() + 2, DrawStyle::RED);
278 drawText(tr("Page up"), keyx + 74, keyy + 5, DrawStyle::LIGHTTEXT);
280 rectangle(keyx + 72, keyy + getFontHeight() + 8, 104, getFontHeight() + 2, DrawStyle::GREEN);
281 drawText(tr("Page down"), keyx + 74, keyy + getFontHeight() + 9, DrawStyle::LIGHTTEXT);
283 rectangle(keyx + 180, keyy + 4, 104, getFontHeight() + 2, DrawStyle::YELLOW);
284 drawText(tr("-24 hours"), keyx + 182, keyy + 5, DrawStyle::LIGHTTEXT);
286 rectangle(keyx + 180, keyy + getFontHeight() + 8, 104, getFontHeight() + 2, DrawStyle::BLUE);
287 drawText(tr("+24 hours"), keyx + 182, keyy + getFontHeight() + 9, DrawStyle::LIGHTTEXT);
289 rectangle(keyx + 290, keyy + 4, 180, getFontHeight() + 2, DrawStyle::GREY);
290 drawText(tr("Guide / Back: Close"), keyx + 292 , keyy + 5, DrawStyle::LIGHTTEXT);
292 rectangle(keyx + 290, keyy + getFontHeight() + 8, 180, getFontHeight() + 2, DrawStyle::GREY);
293 DrawStyle red = DrawStyle(130, 0, 0);
294 drawText(tr("Rec: Set timer"), keyx + 292, keyy + getFontHeight() + 9, red);
296 rectangle(keyx + 474, keyy + 4, 128, getFontHeight() + 2, DrawStyle::GREY);
297 w.nextSymbol = WSymbol::PLAY;
298 w.setPosition(keyx + 476, keyy + 5);
300 drawText(tr("Sel channel"), keyx + 496, keyy + 5, DrawStyle::LIGHTTEXT);
302 rectangle(keyx + 474, keyy + getFontHeight() + 8, 128, getFontHeight() + 2, DrawStyle::GREY);
303 drawText(tr("Go: Preview"), keyx + 476, keyy + getFontHeight() + 9, DrawStyle::LIGHTTEXT);
306 // Draw all the dynamic data
310 void VEpg::drawData()
312 // Not doing View::draw() every time causes
313 // things not to be cleared off the surface properly
314 // So, blank out the data area first
315 int screenwidth=Video::getInstance()->getScreenWidth();
317 chanListbox.getRootBoxOffsetX(),
318 chanListbox.getRootBoxOffsetY() - getFontHeight() - 3,
319 window_width * MINUTE_SCALE,
320 chanListbox.getHeight() + getFontHeight() + 4,
325 chanName.draw(); // TODO this should be dealt with by vvideolive
330 // Set timer to redraw to move the current time bar
334 if (dt == 0) dt = 60;
336 Timers::getInstance()->setTimerT(this, 1, dt);
339 void VEpg::timercall(int clientReference)
342 boxstack->update(this);
345 int VEpg::handleCommand(int command)
351 { // cursor up the channel list
354 boxstack->update(this);
357 case Remote::DF_DOWN:
359 { // cursor down the channel list
360 Log::getInstance()->log("VEPG", Log::DEBUG, "Down start");
364 boxstack->update(this);
365 Log::getInstance()->log("VEPG", Log::DEBUG, "Down end");
369 case Remote::DF_LEFT:
371 { // cursor left through time
372 selTime = thisEvent.time - 1;
374 boxstack->update(this);
377 case Remote::DF_RIGHT:
380 // cursor right through time
381 selTime = thisEvent.time + thisEvent.duration;
383 boxstack->update(this);
388 // cursor up one page
389 chanListbox.pageUp();
391 boxstack->update(this);
396 // cursor down one page
397 chanListbox.pageDown();
399 boxstack->update(this);
404 // step forward 24 hours
405 selTime += 24 * 60 * 60;
407 boxstack->update(this);
412 // step forward 24 hours
413 selTime -= 24 * 60 * 60;
415 boxstack->update(this);
420 if (!chanList) return 2;
421 Log::getInstance()->log("VEPG", Log::DEBUG, "ID %lu TIME %lu DURATION %lu TITLE %s", thisEvent.id, thisEvent.time, thisEvent.duration, thisEvent.title);
422 VEpgSetTimer* vs = new VEpgSetTimer(&thisEvent, (*chanList)[chanListbox.getCurrentOption()]);
425 boxstack->update(vs);
432 if (!chanList) return 2;
434 // select programme and display menu TODO currently just changes to selected channel
436 currentChannelIndex = chanListbox.getCurrentOption();
440 Message* m = new Message(); // Must be done after this view deleted
443 m->message = Message::CHANNEL_CHANGE;
444 m->parameter = (*chanList)[currentChannelIndex]->number;
445 Command::getInstance()->postMessageNoLock(m);
450 if(command == Remote::GO)
452 // GO just changes channel in preview, PLAY changes channel and returns to normal TV
457 // return to normal TV mode
458 if (parent) // ptr check done in case being tested from videorec
460 Message* m = new Message(); // Must be done after this view deleted
463 m->message = Message::EPG_CLOSE;
464 Command::getInstance()->postMessageNoLock(m);
468 case Remote::CHANNELUP:
470 if (currentChannelIndex == (chanList->size() - 1)) // at the end
471 currentChannelIndex = 0;
473 ++currentChannelIndex;
477 Message* m = new Message(); // Must be done after this view deleted
480 m->message = Message::CHANNEL_CHANGE;
481 m->parameter = (*chanList)[currentChannelIndex]->number;
482 Command::getInstance()->postMessageNoLock(m);
489 case Remote::CHANNELDOWN:
491 if (currentChannelIndex == 0) // at the start
492 currentChannelIndex = chanList->size() - 1; // so go to end
494 --currentChannelIndex;
498 Message* m = new Message(); // Must be done after this view deleted
501 m->message = Message::CHANNEL_CHANGE;
502 m->parameter = (*chanList)[currentChannelIndex]->number;
503 Command::getInstance()->postMessageNoLock(m);
511 // stop command getting to any more views
515 void VEpg::drawgrid() // redraws grid and select programme
517 // draw the grid of programmes
520 time(&t); // set t = now
522 selTime = t; // don't allow cursor in the past
523 if(listTop != chanListbox.getTopOption())
525 // chanListbox has scrolled TODO speed up by changing only rows that have changed
526 listTop = chanListbox.getTopOption();
529 if ((selTime >= ltime + window_width * 60) || (selTime <= ltime))
531 // we have cursored back before left time of window
532 //TODO check that this and above don't happen together
533 ltime = prevHour(&selTime);
537 DrawStyle white = DrawStyle(255, 255, 255, 255);
543 strftime(timeString, 19, "%a %d %b", tms);
544 int timey = chanListbox.getRootBoxOffsetY() - getFontHeight() - 3;
546 drawTextRJ(timeString, timex - 10, timey, DrawStyle::LIGHTTEXT); // print date
547 strftime(timeString, 19, "%H:%M", tms);
548 drawText(timeString, timex, timey, DrawStyle::LIGHTTEXT); // print left time
550 rectangle(155, timey + getFontHeight(), 2, 7, white);
553 strftime(timeString, 19, "%H:%M", tms);
554 drawText(timeString, timex + 180, timey, DrawStyle::LIGHTTEXT); // print middle time
555 rectangle(335, timey + getFontHeight(), 2, 7, white);
558 strftime(timeString, 19, "%H:%M", tms);
559 drawText(timeString, timex + 360, timey, DrawStyle::LIGHTTEXT); // print right time
560 rectangle(515, timey + getFontHeight(), 2, 7, white);
561 // pointer to selTime
562 //rectangle(155 + (selTime - ltime) / 20, timey + getFontHeight(), 2, 7, DrawStyle(255, 50, 50, 255));
566 if ((t >= ltime) && (t < (ltime + 9000)))
568 rectangle(155 + (t - ltime) / 20, timey + getFontHeight(), 2, ((getFontHeight() + 2) * gridRows) + 7 + 2, DrawStyle::RED);
571 // TODO should the above two comditional statements be combined to avoid calling updateEventList() twice?
573 Event noevent; // an event to use if there are gaps in the epg
574 thisEvent.setdescription(tr("There are no programme details available for this period"));
575 thisEvent.duration = window_width * 60;
576 thisEvent.time = ltime;
577 thisEvent.settitle(tr("No programme details"));
579 bool swapColour = false; // alternate cell colour
580 bool currentRow = false;
581 int y = chanListbox.getRootBoxOffsetY() + 5; // vertical position of cell
582 DrawStyle bg, fg; // background colour of cells in grid
583 // for each displayed channel, find programmes that fall in 2.5 hour time window
584 for(UINT listIndex = 0; listIndex < gridRows; listIndex++)
586 if (listTop + (int)listIndex >= chanListbox.getBottomOption())
587 continue; // ensure nothing populates grid below last channel
589 currentRow = (listTop + (int)listIndex == chanListbox.getCurrentOption());
590 noevent.time = ltime;
591 noevent.duration = window_width * 60;
592 noevent.settitle("");
593 paintCell(&noevent, y, DrawStyle::NOPROGRAMME, DrawStyle::LIGHTTEXT); // fill row with no programme colour to be painted ove with valid programmes
596 thisEvent.setdescription(tr("There are no programme details available for this period"));
597 thisEvent.duration = window_width * 60;
598 thisEvent.time = ltime;
599 thisEvent.settitle(tr("No programme details"));
602 if (eventLista[listIndex])
604 sort(eventLista[listIndex]->begin(), eventLista[listIndex]->end(), EventSorter());
605 for(e = 0; e < (eventLista[listIndex])->size(); e++) // step through events for this channel
607 fg = DrawStyle::LIGHTTEXT;
608 event = (*eventLista[listIndex])[e];
611 UINT end = event->time + event->duration; // programme end time
612 if(event->time >= UINT(ltime) + (window_width * 60)) // programme starts after RHS of window
613 continue; // that's enough of this channel's events
614 if(end <= UINT(ltime)) // programme ends before LHS of window
615 continue; // this event is before the window - let's try the next event
616 // this event is one we are interested in
617 bg = (swapColour)?DrawStyle::PROGRAMMEA:DrawStyle::PROGRAMMEB; // alternate cell colour
618 swapColour = !swapColour; // it wil be the other colour next time
619 if(event->time <= UINT(selTime) && end > UINT(selTime) && currentRow)
621 // this is the selected programme
622 thisEvent.setdescription(event->description);
623 thisEvent.duration = event->duration;
624 thisEvent.time = event->time;
625 thisEvent.settitle(event->title);
626 thisEvent.id = event->id;
627 if(thisEvent.id == 0)
629 bg = DrawStyle::SELECTHIGHLIGHT; // highlight cell
630 fg = DrawStyle::DARKTEXT;
634 if (currentRow && thisEvent.id == 0)
636 if (end <= UINT(selTime) && end > UINT(thisEvent.time))
637 thisEvent.time = end;
638 if (event->time > UINT(selTime) && event->time < thisEvent.time + thisEvent.duration)
639 thisEvent.duration = event->time - thisEvent.time;
642 paintCell(event, y, bg, fg);
648 // no event list for this channel. Already painted noevent colour so just highlight if selected
651 bg = DrawStyle::SELECTHIGHLIGHT; // highlight cell
652 fg = DrawStyle::DARKTEXT;
653 paintCell(&thisEvent, y, bg, fg);
657 bg = DrawStyle::NOPROGRAMME;
658 fg = DrawStyle::LIGHTTEXT;
659 noevent.settitle(tr("No programme details"));
660 paintCell(&noevent, y, bg, fg);
663 y += getFontHeight() + 2;
668 void VEpg::updateEventList()
670 if (!chanList) return;
672 for(UINT listIndex = 0; listIndex < gridRows; listIndex++)
674 if(listTop + listIndex >= UINT(chanListbox.getBottomOption()))
676 chan = (*chanList)[listTop + listIndex];
677 if (eventLista[listIndex])
679 (eventLista)[listIndex]->clear();
680 delete eventLista[listIndex];
682 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
686 void VEpg::setCurrentChannel()
688 chanName.setText((*chanList)[currentChannelIndex]->name);
691 chanName.getRootBoxRegion(&r);
692 boxstack->update(this, &r);
695 void VEpg::paintCell(Event* event, int yOffset, const DrawStyle& bg, const DrawStyle& fg)
698 w = x = 0; // keep compiler happy
700 h = getFontHeight(); // TODO if want border around text, need to increae this and wselectlist line height
701 UINT end = event->time + event->duration; // programme end time
702 if(event->time <= UINT(ltime) && end > UINT(ltime)) // spans start of displayed window
704 x = 155; // LHS of window
705 if (end > (UINT(ltime) + (window_width * 60)))
706 w = window_width * MINUTE_SCALE; // spans full 2 hour window
708 w = MINUTE_SCALE * (event->time + event->duration - ltime ) / 60; // get width of remaining programme
710 if((event->time >= UINT(ltime)) && (event->time <= UINT(ltime) + (window_width * 60))) // starts within window
712 x = 155 + (MINUTE_SCALE * (event->time - ltime) / 60);
713 w = MINUTE_SCALE * event->duration / 60;
714 //if (w > 155 + MINUTE_SCALE * WINDOW_WIDTH -x)
715 // w = w + x - 155 - MINUTE_SCALE * WINDOW_WIDTH; // ends outside window
717 if (w > 155 + window_width * MINUTE_SCALE - x)
718 w = 155 + window_width * MINUTE_SCALE -x; // limit cells to RHS of window
719 rectangle(x, y, w, h, bg);
720 char* tt = new char[strlen(event->title) + 1];
721 strcpy (tt, event->title);
723 unsigned int cur_length=1;
724 unsigned int text_max=strlen(tt);
726 for (textPos = 0; textPos <text_max; textPos+=cur_length)
728 wchar_t cur_char=getWChar(tt+textPos,&cur_length);
729 float thisCharWidth = charWidth(cur_char);
730 if (textWidth + thisCharWidth > w) // text will not fit in cell
734 textWidth += thisCharWidth;
736 char* tT = new char[textPos+1];
739 strncpy(tT, tt, textPos );
741 surface->drawText(tT, x+2, y, fg);
747 time_t VEpg::prevHour(time_t* t)
756 void VEpg::processMessage(Message* m)
758 if (m->message == Message::MOUSE_MOVE)
760 if (chanListbox.mouseMove((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))
763 boxstack->update(this);
766 else if (m->message == Message::MOUSE_LBDOWN)
768 if (chanListbox.mouseLBDOWN((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))
770 boxstack->handleCommand(Remote::OK); //simulate OK press
774 //check if press is outside this view! then simulate cancel
775 int x=(m->parameter>>16)-getScreenX();
776 int y=(m->parameter&0xFFFF)-getScreenY();
777 int keyx = chanListbox.getRootBoxOffsetX();
778 int keyy = chanListbox.getRootBoxOffsetY() + chanListbox.getHeight() + 2;
780 if (x<0 || y <0 || x>(int)getWidth() || y>(int)getHeight())
782 boxstack->handleCommand(Remote::BACK); //simulate cancel press
784 else if (x>=(keyx+72) && y>=(keyy+4) &&x<=(keyx+72+104) &&y<=(keyy+4+getFontHeight() + 2))
786 boxstack->handleCommand(Remote::RED);
788 else if (x>=(keyx+72) && y>=(keyy+ getFontHeight() + 8) &&x<=(keyx+72+104) &&y<=(keyy+8+2*getFontHeight() + 2))
790 boxstack->handleCommand(Remote::GREEN);
792 else if (x>=(keyx+180) && y>=(keyy+4) &&x<=(keyx+180+104) &&y<=(keyy+4+getFontHeight() + 2))
794 boxstack->handleCommand(Remote::YELLOW);
796 else if (x>=(keyx+180) && y>=(keyy+ getFontHeight() + 8) &&x<=(keyx+180+104) &&y<=(keyy+8+2*getFontHeight() + 2))
798 boxstack->handleCommand(Remote::BLUE);
800 else if (x>=(keyx+290) && y>=(keyy+4) &&x<=(keyx+180+290) &&y<=(keyy+4+getFontHeight() + 2))
802 boxstack->handleCommand(Remote::BACK);
804 else if (x>=(keyx+290) && y>=(keyy+ getFontHeight() + 8) &&x<=(keyx+290+180) &&y<=(keyy+8+2*getFontHeight() + 2))
806 boxstack->handleCommand(Remote::RECORD);
808 else if (x>=(keyx+474) && y>=(keyy+4) &&x<=(keyx+128+474) &&y<=(keyy+4+getFontHeight() + 2))
810 boxstack->handleCommand(Remote::PLAY);
812 else if (x>=(keyx+474) && y>=(keyy+ getFontHeight() + 8) &&x<=(keyx+238+474) &&y<=(keyy+8+2*getFontHeight() + 2))
814 boxstack->handleCommand(Remote::GO);
816 else if ( x>=(chanListbox.getRootBoxOffsetX())
817 && y>=(chanListbox.getRootBoxOffsetY() + 5)
818 // &&x<=(chanListbox.getOffsetX()+155 + window_width * MINUTE_SCALE)
819 &&y<=(chanListbox.getRootBoxOffsetY() - getFontHeight()
820 - 3+(int)chanListbox.getHeight() + getFontHeight() + 3)
823 int cy=y-(chanListbox.getRootBoxOffsetY() + 5);
824 int row=cy/(getFontHeight()+2);
825 int clistTop = chanListbox.getTopOption();
826 chanListbox.hintSetCurrent(clistTop+row);
828 time_t ttime = cx*60/MINUTE_SCALE+ltime;
829 //x = 155 + (MINUTE_SCALE * (event->time - ltime) / 60);
833 boxstack->update(this);