1 #include "enigma_epg.h"
4 #include "enigma_lcd.h"
5 #include "epgactions.h"
7 #include "enigma_event.h"
9 #include <lib/dvb/epgcache.h>
10 #include <lib/dvb/service.h>
11 #include <lib/dvb/si.h>
12 #include <lib/dvb/serviceplaylist.h>
13 #include <lib/gui/eskin.h>
14 #include <lib/gui/elabel.h>
15 #include <lib/gui/guiactions.h>
16 #include <lib/gui/statusbar.h>
17 #include <lib/gdi/font.h>
18 #include <lib/gui/numberactions.h>
20 gPixmap
*eZapEPG::entry::inTimer
=0;
21 gPixmap
*eZapEPG::entry::inTimerRec
=0;
23 static eString
buildShortName( const eString
&str
)
26 static char stropen
[3] = { 0xc2, 0x86, 0x00 };
27 static char strclose
[3] = { 0xc2, 0x87, 0x00 };
28 unsigned int open
=eString::npos
-1;
30 while ( (open
= str
.find(stropen
, open
+2)) != eString::npos
)
32 unsigned int close
= str
.find(strclose
, open
);
33 if ( close
!= eString::npos
)
34 tmp
+=str
.mid( open
+2, close
-(open
+2) );
40 :eWidget(0,1), offs(0), focusColumn(0), hours(3)
41 ,numservices(8), eventWidget(0), NowTimeLineXPos(-1)
43 eConfig::getInstance()->getKey("/elitedvb/multiepg/hours", hours
);
45 resize(eSize(590, 470));
46 timeLine
.setAutoDelete(true);
47 timeFont
= eSkin::getActive()->queryFont("epg.time");
48 titleFont
= eSkin::getActive()->queryFont("epg.title");
49 descrFont
= eSkin::getActive()->queryFont("epg.description");
50 entryColor
= eSkin::getActive()->queryColor("epg.entry.background");
51 entryColorSelected
= eSkin::getActive()->queryColor("epg.entry.background.selected");
52 entry::inTimer
= eSkin::getActive()->queryImage("timer_symbol");
53 entry::inTimerRec
= eSkin::getActive()->queryImage("timer_rec_symbol");
54 addActionMap( &i_epgSelectorActions
->map
);
55 addActionMap( &i_focusActions
->map
);
56 addActionMap( &i_cursorActions
->map
);
57 addActionMap( &i_numberActions
->map
);
60 addActionToHelpList( &i_epgSelectorActions
->addDVRTimerEvent
);
62 #ifndef DISABLE_NETWORK
63 addActionToHelpList( &i_epgSelectorActions
->addNGRABTimerEvent
);
65 addActionToHelpList( &i_epgSelectorActions
->addSwitchTimerEvent
);
66 addActionToHelpList( &i_epgSelectorActions
->removeTimerEvent
);
68 Signal1
<void,const eServiceReference
& > callback
;
69 CONNECT( callback
, eZapEPG::addToList
);
70 eZap::getInstance()->getServiceSelector()->forEachServiceRef( callback
, false );
71 curS
= curE
= services
.begin();
72 sbar
= new eStatusBar(this);
73 sbar
->move( ePoint(0, clientrect
.height()-50) );
74 sbar
->resize( eSize( clientrect
.width(), 50) );
76 sbar
->setFlags( eStatusBar::flagOwnerDraw
|RS_WRAP
);
78 eLabel
*l
= new eLabel(this);
79 l
->move(ePoint(100, clientrect
.height()-80) );
80 l
->setFont( eSkin::getActive()->queryFont("eStatusBar") );
81 l
->resize( eSize( clientrect
.width()-100, 30) );
82 l
->setText(_("press 1 ... 6 to select count of visible hours"));
83 l
->setFlags( eLabel::flagVCenter
);
90 eConfig::getInstance()->setKey("/elitedvb/multiepg/hours", hours
);
93 void eZapEPG::addToList( const eServiceReference
& ref
)
95 if ( ref
.type
== eServiceReference::idDVB
)
96 services
.push_back( (const eServiceReferenceDVB
&) ref
);
99 eZapEPG::entry::entry(eWidget
*parent
, gFont
&timeFont
, gFont
&titleFont
,
100 gFont
&descrFont
, gColor entryColor
, gColor entryColorSelected
, eWidget
*sbar
)
101 : eWidget(parent
), timeFont(timeFont
),
102 titleFont(titleFont
), descrFont(descrFont
), entryColor(entryColor
),
103 entryColorSelected(entryColorSelected
),
104 sbar(sbar
), para(0), xOffs(0), yOffs(0)
106 setBackgroundColor(entryColor
);
109 eZapEPG::entry::~entry()
119 void eZapEPG::entry::redrawWidget(gPainter
*target
, const eRect
&area
)
123 para
=new eTextPara( eRect(0, 0, size
.width(), size
.height() ) );
124 para
->setFont(titleFont
);
125 para
->renderString(title
, RS_WRAP
);
126 int bboxHeight
= para
->getBoundBox().height();
127 int bboxWidth
= para
->getBoundBox().width();
128 yOffs
= (bboxHeight
< size
.height()) ? (( size
.height() - bboxHeight
) / 2) - para
->getBoundBox().top() : 0;
129 xOffs
= (bboxWidth
< size
.width()) ? (( size
.width() - bboxWidth
) / 2) - para
->getBoundBox().left() : 0;
132 target
->renderPara(*para
, ePoint( area
.left()+xOffs
, area
.top()+yOffs
) );
135 if ( (p
= eTimerManager::getInstance()->findEvent( &service
->service
, (EITEvent
*)event
)) )
137 if ( p
->type
& ePlaylistEntry::SwitchTimerEntry
)
138 target
->blit( *inTimer
, ePoint( size
.width()-inTimer
->x
-1, size
.height()-inTimerRec
->y
-1 ), eRect(), gPixmap::blitAlphaTest
);
139 else if ( p
->type
& ePlaylistEntry::RecTimerEntry
)
140 target
->blit( *inTimerRec
, ePoint(size
.width()-inTimerRec
->x
-1, size
.height()-inTimerRec
->y
-1), eRect(), gPixmap::blitAlphaTest
);
143 target
->setForegroundColor(gColor(entryColorSelected
));
144 target
->fill(eRect(0, size
.height()-1, size
.width(), 1));
145 target
->fill(eRect(size
.width()-1, 0, 1, size
.height()));
146 if (backgroundColor
==entryColorSelected
)
150 void eZapEPG::entry::gotFocus()
153 eZapLCD
* pLCD
= eZapLCD::getInstance();
154 unsigned int pos
= 0;
155 for (int i
=0; i
< 4; ++i
)
156 pos
= helptext
.find(' ', pos
+1);
157 if ( pos
!= eString::npos
&& (pos
+1) < helptext
.length() )
161 title
.removeChars(' ');
162 pLCD
->lcdMenu
->Title
->setText(title
);
163 pLCD
->lcdMenu
->Element
->setText(helptext
.mid(pos
+1));
166 sbar
->setText( helptext
);
167 setBackgroundColor(entryColorSelected
);
170 void eZapEPG::entry::lostFocus()
172 // setForegroundColor(normalF,false);
173 setBackgroundColor(entryColor
);
176 int eZapEPG::eventHandler(const eWidgetEvent
&event
)
180 case eWidgetEvent::evtAction
:
183 int servicevalid
= current_service
!= serviceentries
.end();
185 if ( servicevalid
&& current_service
->current_entry
!= current_service
->entries
.end())
187 if ( (addtype
= i_epgSelectorActions
->checkTimerActions( event
.action
)) != -1 )
189 else if (event
.action
== &i_epgSelectorActions
->removeTimerEvent
)
192 if ( eTimerManager::getInstance()->removeEventFromTimerList( this, ¤t_service
->service
, current_service
->current_entry
->event
) )
193 current_service
->current_entry
->invalidate();
195 else if (event
.action
== &i_focusActions
->left
)
197 else if (event
.action
== &i_focusActions
->right
)
199 else if (event
.action
== &i_focusActions
->up
)
201 else if (event
.action
== &i_focusActions
->down
)
203 else if (event
.action
== &i_cursorActions
->ok
)
204 close(eventvalid
?0:-1);
205 else if (event
.action
== &i_cursorActions
->cancel
)
207 else if ((event
.action
== &i_epgSelectorActions
->showExtendedInfo
) && eventvalid
)
209 eService
*service
=eDVB::getInstance()->settings
->getTransponders()->searchService(current_service
->service
);
210 eEventDisplay
ei(service
? service
->service_name
.c_str() : "", current_service
->service
, 0, (EITEvent
*)current_service
->current_entry
->event
);
213 eZapLCD
* pLCD
= eZapLCD::getInstance();
214 pLCD
->lcdMain
->hide();
215 pLCD
->lcdMenu
->show();
216 ei
.setLCD(pLCD
->lcdMenu
->Title
, pLCD
->lcdMenu
->Element
);
221 while((ret
= ei
.exec()))
228 break; // close EventDisplay
230 ei
.setEvent((EITEvent
*)current_service
->current_entry
->event
);
236 else if (event
.action
== &i_numberActions
->key1
)
241 else if (event
.action
== &i_numberActions
->key2
)
246 else if (event
.action
== &i_numberActions
->key3
)
251 else if (event
.action
== &i_numberActions
->key4
)
256 else if (event
.action
== &i_numberActions
->key5
)
261 else if (event
.action
== &i_numberActions
->key6
)
268 if (eventvalid
&& (addtype
!= -1))
270 if ( !eTimerManager::getInstance()->eventAlreadyInList( this, *(EITEvent
*)current_service
->current_entry
->event
, current_service
->service
) )
273 eTimerEditView
v( *(EITEvent
*)current_service
->current_entry
->event
, addtype
, current_service
->service
);
285 return eWidget::eventHandler(event
);
288 void eZapEPG::buildService(serviceentry
&service
)
290 int width
= service
.pos
.width();
291 service
.entries
.setAutoDelete(1);
292 eEPGCache
*epgcache
=eEPGCache::getInstance();
294 const timeMap
*evmap
= epgcache
->getTimeMap(service
.service
);
301 timeMap::const_iterator ibegin
= evmap
->lower_bound(start
);
302 if ((ibegin
!= evmap
->end()) && (ibegin
!= evmap
->begin()) )
304 if ( ibegin
->first
!= start
)
308 ibegin
=evmap
->begin();
310 timeMap::const_iterator iend
= evmap
->lower_bound(end
);
313 (service
.service
.getTransportStreamID().get()<<16) | service
.service
.getOriginalNetworkID().get();
315 for (timeMap::const_iterator
event(ibegin
); event
!= iend
; ++event
)
317 EITEvent
*ev
= new EITEvent(*event
->second
,tsidonid
);
318 if (((ev
->start_time
+ev
->duration
)>= start
) && (ev
->start_time
<= end
))
321 entry
*e
= new entry(eventWidget
, timeFont
, titleFont
, descrFont
, entryColor
, entryColorSelected
, sbar
);
322 e
->service
= &service
;
323 int xpos
= (ev
->start_time
- start
) * width
/ (end
- start
);
324 int ewidth
= (ev
->start_time
+ ev
->duration
- start
) * width
/ (end
- start
);
333 if ((xpos
+ewidth
) > width
)
334 ewidth
= width
- xpos
;
336 e
->move(ePoint(service
.pos
.x() + xpos
, service
.pos
.y()));
337 e
->resize(eSize(ewidth
, service
.pos
.height()));
338 CONNECT( e
->redrawed
, eZapEPG::drawTimeLines
);
339 service
.entries
.push_back(e
);
342 led
.getLocalData(ev
, &e
->title
, &description
);
343 tm
*begin
=localtime(&ev
->start_time
);
344 while ( description
[0] == ' ' )
345 description
.erase(0);
346 if ( description
!= e
->title
)
349 description
= " - "+description
;
354 tmp
.sprintf("%02d.%02d. %02d:%02d - ",
360 time_t endTime
= ev
->start_time
+ ev
->duration
;
361 tm
*end
=localtime(&endTime
);
362 tmp
+=eString().sprintf("%02d:%02d %s%s",
363 end
->tm_hour
, end
->tm_min
,
364 e
->title
.c_str(), description
.c_str());
375 void eZapEPG::selService(int dir
)
377 if (serviceentries
.begin() == serviceentries
.end())
380 ePtrList
<entry
>::iterator l
= current_service
->current_entry
;
381 isok
= l
!= current_service
->entries
.end();
387 if (current_service
== serviceentries
.end())
396 while(current_service
->entries
.empty());
397 } else if (dir
== -1)
401 if (current_service
!= serviceentries
.begin())
409 focusColumn
=numservices
-1;
413 while(current_service
->entries
.empty());
420 last_time
= l
->event
->start_time
;
423 if (current_service
->current_entry
!= current_service
->entries
.end())
428 ePtrList
<entry
>::iterator best
=current_service
->entries
.end();
429 for (ePtrList
<entry
>::iterator
i(current_service
->entries
.begin());
430 i
!= current_service
->entries
.end(); ++i
)
432 if ((best
== current_service
->entries
.end()) || abs(i
->event
->start_time
-last_time
) < best_diff
)
435 best_diff
= abs(i
->event
->start_time
-last_time
);
439 if (best
!= current_service
->entries
.end())
440 current_service
->current_entry
= best
;
442 current_service
->current_entry
->gotFocus();
446 void eZapEPG::selEntry(int dir
)
448 if (current_service
== serviceentries
.end() || current_service
->entries
.empty())
450 if ( dir
== -1 && offs
>= hours
*3600 )
456 eDebug("invalid service");*/
459 ePtrList
<entry
>::iterator l
= current_service
->current_entry
;
462 ++current_service
->current_entry
;
463 if (current_service
->current_entry
== current_service
->entries
.end())
465 if ( eventWidget
->isVisible() )
471 --current_service
->current_entry
;
476 if (current_service
->current_entry
== current_service
->entries
.begin())
478 if ( offs
>= hours
*3600 )
485 --current_service
->current_entry
;
487 if (l
!= current_service
->entries
.end())
489 current_service
->current_entry
->gotFocus();
492 void eZapEPG::buildPage(int direction
)
498 direction 4 -> right */
499 NowTimeLineXPos
= -1;
505 serviceentries
.clear();
506 current_service
= serviceentries
.end();
509 eventWidget
= new eWidget( this );
510 eventWidget
->move(ePoint(0,0));
511 eSize tmps
= clientrect
.size();
512 tmps
.setHeight( clientrect
.height()-80 );
513 eventWidget
->resize( tmps
);
516 eventWidget
->setLCD( LCDTitle
, LCDElement
);
519 start
=time(0)+eDVB::getInstance()->time_difference
+offs
;
520 unsigned int tmp
= start
% 900; // align to 15min
522 end
=start
+hours
*3600;
524 if ( direction
== 1 )
525 // go left.. we must count "numservices" back
527 std::list
<eServiceReferenceDVB
>::iterator
s(curS
);
531 if ( s
== services
.end() )
533 if ( ++cnt
> numservices
)
535 if ( s
!= services
.begin() )
540 if (s
!= services
.begin())
549 else if ( direction
== 2 ) // right
551 else if ( direction
> 2 ) // up or down
554 int width
= clientrect
.width();
555 int serviceheight
= (eventWidget
->height()-40) / numservices
;
557 time_t tmpTime
=start
;
558 int timeWidth
= (width
- 100) / (hours
>3?hours
:hours
*2);
559 for (unsigned int i
=0; i
< (hours
>3?hours
:hours
*2); ++i
)
561 tmpTime
+=i
?(hours
>3?3600:1800):0;
562 eLabel
*l
= new eLabel(eventWidget
);
563 l
->move(ePoint( i
*timeWidth
-(timeWidth
/2)+100, 0));
564 l
->resize(eSize(timeWidth
,30));
565 l
->setFlags(eLabel::flagVCenter
);
566 l
->setAlign(eTextPara::dirCenter
);
567 tm
*bla
= localtime(&tmpTime
);
568 l
->setText(eString().sprintf("%d:%02d", bla
->tm_hour
, bla
->tm_min
));
569 timeLine
.push_back(l
);
573 std::set
<int> nonEmptyServices
;
577 if ( curE
== services
.end() )
580 // const eventData *e = (const eventData*) eEPGCache::getInstance()->lookupEvent( *curE, (time_t)(start+tmp), true );
583 serviceentries
.push_back(serviceentry());
584 serviceentry
&service
= serviceentries
.back();
585 service
.header
= new eLabel(eventWidget
);
586 service
.header
->move(ePoint(0, p
* serviceheight
+ 35));
587 service
.header
->resize(eSize(90, serviceheight
));
588 service
.pos
= eRect(100, p
* serviceheight
+ 35, width
- 100, serviceheight
);
591 if ( curE
->descr
) // have changed service name?
592 stext
=curE
->descr
; // use this...
595 eService
*sv
=eServiceInterface::getInstance()->addRef(*curE
);
598 eString shortname
= buildShortName( sv
->service_name
);
599 stext
=shortname
?shortname
:sv
->service_name
;
600 eServiceInterface::getInstance()->removeRef(*curE
);
603 service
.service
= *curE
;
605 // set column service name
606 service
.header
->setText(stext
);
607 service
.header
->setFlags( eLabel::flagVCenter
);
609 buildService(service
);
611 if ( service
.entries
.empty() )
612 service
.current_entry
= service
.entries
.end();
616 if ( direction
== 3 ) // up pressed
617 // set focus to last line
618 service
.current_entry
= --service
.entries
.end();
619 else // set focus to first line
620 service
.current_entry
= service
.entries
.begin();
621 nonEmptyServices
.insert(p
);
625 if ( ++curE
== services
.end() ) // need wrap ?
626 curE
= services
.begin();
628 while( serviceentries
.size() < numservices
&& curE
!= curS
);
638 if ( serviceentries
.empty() )
644 std::set
<int>::iterator it
=
645 nonEmptyServices
.lower_bound(focusColumn
);
646 /* scroll back to the bottom non-empty service */
647 while ( it
== nonEmptyServices
.end() && it
!= nonEmptyServices
.begin() ) --it
;
648 if ( it
!= nonEmptyServices
.end() )
654 current_service
= serviceentries
.begin();
655 for (unsigned int i
=0; i
< focusColumn
; i
++ )
657 if (current_service
== --serviceentries
.end())
662 if (current_service
->current_entry
!= current_service
->entries
.end())
663 current_service
->current_entry
->gotFocus();
665 if (nonEmptyServices
.empty())
669 void eZapEPG::drawTimeLines()
671 if ( eventWidget
&& eventWidget
->isVisible() && timeLine
.size() )
673 gPainter
*p
= getPainter(eRect(eventWidget
->getPosition(),eventWidget
->getSize()));
674 int incWidth
=((eventWidget
->width()-100)/(hours
>3?hours
:hours
*2));
676 int lineheight
= eventWidget
->height();
677 if ( NowTimeLineXPos
!= -1 )
679 int tmp
=NowTimeLineXPos
;
681 invalidate( eRect( tmp
,30,2,lineheight
) );
683 p
->setForegroundColor( eSkin::getActive()->queryColor("epg.timeline") );
684 for (ePtrList
<eLabel
>::iterator
it(timeLine
); it
!= timeLine
.end(); ++it
)
686 p
->fill(eRect(pos
,30,1,lineheight
));
690 time_t now
=time(0)+eDVB::getInstance()->time_difference
;
691 if ( now
>= start
&& now
< end
)
693 int bla
= ((eventWidget
->width()-100)*1000) / (hours
*60);
694 NowTimeLineXPos
= ((now
/60) - (start
/60)) * bla
/ 1000;
695 NowTimeLineXPos
+=100;
696 p
->setForegroundColor( eSkin::getActive()->queryColor("epg.timeline.now") );
697 p
->fill(eRect(NowTimeLineXPos
,30,2,lineheight
));