]> git.vomp.tv Git - vompclient.git/blob - vrecording.cc
Fix text corruption in channel number display on live tv
[vompclient.git] / vrecording.cc
1 /*
2     Copyright 2004-2019 Chris Tallon
3
4     This file is part of VOMP.
5
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.
10
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.
15
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.
19 */
20
21 #include "vrecording.h"
22
23 #include "remote.h"
24 #include "recinfo.h"
25 #include "vquestion.h"
26 #include "vinfo.h"
27 #include "vdr.h"
28 #include "colour.h"
29 #include "video.h"
30 #include "i18n.h"
31 #include "command.h"
32 #include "vrecmove.h"
33 #include "boxstack.h"
34 #include "recman.h"
35 #include "vrecordinglist.h"
36 #include "recording.h"
37 #include "message.h"
38 #include "log.h"
39 #include "wmovieview.h"
40 #include "wseriesview.h"
41 #include "wpictureview.h"
42
43 VRecording::VRecording(RecMan* trecman, Recording* trec)
44 {
45   rec = trec;
46   recman = trecman;
47   buttons = true;
48   selected = RESUME;
49   
50   Log::getInstance()->log("VRecording", Log::DEBUG, "%s", rec->getProgName());
51   rec->loadRecInfo();
52   Log::getInstance()->log("VRecording", Log::DEBUG, "%s", rec->getProgName());
53
54
55   if (Video::getInstance()->getFormat() == Video::PAL)
56   {
57     setSize(640, 500);
58         createBuffer();
59   }
60   else
61   {
62         setSize(560, 400);
63         createBuffer();
64   }
65   setPosition(40, 40);
66
67   setTitleBarOn(1);
68   setBorderOn(1);
69   if (rec->recInfo && strlen(rec->recInfo->title))
70           setTitleText(rec->recInfo->title);
71   else
72           setTitleText(rec->getProgName());
73   setTitleBarColour(DrawStyle::TITLEBARBACKGROUND);
74
75   tabbar.setPosition(10+130+10, 30 + 5);
76   tabbar.setSize(area.w - 20-10-130, area.h - 30 - 10);
77   add(&tabbar);
78
79
80
81   epgSummaryTextBox = new WTextbox();
82
83   epgSummaryTextBox->setParaMode(true);
84
85   if (rec->recInfo)
86     epgSummaryTextBox->setText(rec->recInfo->buildSummaryWithDetails());
87   else
88     epgSummaryTextBox->setText(tr("Summary unavailable"));
89
90   OsdVector *osdv=dynamic_cast<OsdVector*>(Osd::getInstance());
91
92   tabbar.addTab(tr("EPG"), epgSummaryTextBox);
93   if (rec->movieInfo) {
94           WMovieView *movieview = new WMovieView(rec->movieInfo);
95           movieview->setParaMode(true);
96           tabbar.addTab(tr("TheTVDB Info"), movieview);
97           if (osdv) {
98                   if (rec->movieInfo->actors.size() > 0 && osdv)
99                   {
100                           WActorGallery *gallery= new WActorGallery(rec->movieInfo->actors);
101                           tabbar.addTab(tr("Cast"),gallery);
102                   }
103                   WArtworkGallery *artgallery= new WArtworkGallery(*rec->movieInfo);
104                   tabbar.addTab(tr("Gallery"),artgallery);
105           }
106   } else if (rec->seriesInfo) {
107           WSeriesView *seriesview = new WSeriesView(rec->seriesInfo);
108           seriesview->setParaMode(true);
109           tabbar.addTab(tr("TheTVDB Info"), seriesview);
110           if (osdv) {
111                   if (rec->seriesInfo->actors.size() > 0 && osdv)
112                   {
113                           WActorGallery *gallery= new WActorGallery(rec->seriesInfo->actors);
114                           tabbar.addTab(tr("Cast"),gallery);
115                   }
116                   WArtworkGallery *artgallery= new WArtworkGallery(*rec->seriesInfo);
117                   tabbar.addTab(tr("Gallery"),artgallery);
118           }
119
120   }
121
122
123   
124   int sfh = getFontHeight();
125   buttonRegion.x = 10;
126   buttonRegion.y = 10+30;
127   buttonRegion.w = 130;
128   buttonRegion.h = sfh*2*last;
129
130   button[PLAY].setText(tr("Play"));
131   button[RESUME].setText(tr("Resume"));
132   button[MARKASNEW].setText(tr("Mark as new"));
133   button[MOVE].setText(tr("Move"));
134   button[A_DELETE].setText(tr("Delete"));
135   
136   for (int i=PLAY, ver=10+30; i<last; i++, ver+= sfh*2)
137   {
138     button[i].setPosition(10, ver);
139     button[i].setSize(130, sfh);
140     add(&button[i]);
141   }
142   
143
144   button[selected].setActive(1);
145   tabbar.activateFocus(false);
146 }
147
148 VRecording::~VRecording()
149 {
150 }
151
152 void VRecording::setParent(VRecordingList* tvRecList)
153 {
154   vRecList = tvRecList;
155 }
156
157 void VRecording::draw()
158 {
159   TBBoxx::draw();
160   OsdVector *osdv=dynamic_cast<OsdVector*>(Osd::getInstance());
161   if (osdv) {
162           TVMedia poster;
163           if (rec->movieInfo) {
164                   poster=rec->movieInfo->poster;
165           }
166           if (rec->seriesInfo) {
167                   if (rec->seriesInfo->seasonposter.height) {
168                           poster=rec->seriesInfo->seasonposter;
169                   }
170                   else
171                   if (rec->seriesInfo->posters.size()) {
172                           poster=rec->seriesInfo->posters[0];
173                   }
174           }
175           if (poster.height) {
176                  // float aspect=((float)poster.height)/((float)poster.width)/Osd::getInstance()->getPixelAspect();
177                   drawTVMedia(poster.info,buttonRegion.x,
178                                          tabbar.getY2()-3,
179                                                 buttonRegion.w,/*buttonRegion.w*aspect*/0.f,BottomLeft);
180           }
181   }
182
183 }
184
185 int VRecording::handleCommand(int command)
186 {
187         if (command==Remote::BACK) {
188                 return 4;
189         }
190         if (buttons) {
191                 switch(command)
192                 {
193                 case Remote::DF_UP:
194                 case Remote::UP:
195                 {
196                         tabbar.activateFocus(false);
197                         moveCursor(LEFT);
198                         return 2;
199                 }
200
201                 case Remote::DF_DOWN:
202                 case Remote::DOWN:
203                 {
204                         tabbar.activateFocus(false);
205                         moveCursor(RIGHT);
206                         return 2;
207                 }
208                 case Remote::LEFT:
209                 case Remote::DF_LEFT:
210                 case Remote::RIGHT:
211                 case Remote::DF_RIGHT:
212                 {
213                         buttons = false;
214                         button[selected].setActive(0);
215                         tabbar.activateFocus(true);
216                         button[selected].draw();
217                         tabbar.draw();
218                         BoxStack::getInstance()->update(this);
219                         return 2;
220                 }
221                 case Remote::OK:
222                 {
223
224                         if (selected == PLAY)
225                         {
226                                 Message* m = new Message(); // Must be done after this view deleted
227                                 m->from = this;
228                                 m->to = vRecList;
229                                 m->message = Message::PLAY_SELECTED_RECORDING;
230                                 Command::getInstance()->postMessageNoLock(m);
231                                 return 4;
232                         }
233
234                         if (selected == RESUME)
235                         {
236                                 Message* m = new Message(); // Must be done after this view deleted
237                                 m->from = this;
238                                 m->to = vRecList;
239                                 m->message = Message::RESUME_SELECTED_RECORDING;
240                                 Command::getInstance()->postMessageNoLock(m);
241                                 return 4;
242                         }
243
244                         if (selected == MARKASNEW)
245             {
246               int ret = rec->resetResume();
247
248               VInfo* vi = new VInfo();
249               vi->setSize(400, 150);
250               vi->createBuffer();
251               vi->setExitable();
252               vi->setBorderOn(1);
253               vi->setTitleBarOn(0);
254
255               if (Video::getInstance()->getFormat() == Video::PAL)
256               vi->setPosition(170, 200);
257               else
258               vi->setPosition(160, 150);
259
260               if (ret == 1) vi->setOneLiner(tr("Success"));
261               else if (ret == 2) vi->setOneLiner(tr("No resume point exists"));
262               else if (ret == 4) vi->setOneLiner(tr("Failure deleting resume point"));
263               else if (ret == 5) vi->setOneLiner(tr("Not supported with VDR < 2.4.0"));
264               vi->draw();
265
266               Message* m = new Message();
267               m->message = Message::ADD_VIEW;
268               m->to = BoxStack::getInstance();
269               m->parameter.num = (ULONG)vi;
270               Command::getInstance()->postMessageNoLock(m);
271
272               if (ret == 1)
273               {
274                 // Change Resume at text in summary
275                 rec->recInfo->resumePoint = 0;
276                 epgSummaryTextBox->setText(rec->recInfo->buildSummaryWithDetails(true));
277                 draw();
278                 BoxStack::getInstance()->update(this);
279
280                 // Update vrecordingslist to remove the * for new
281                 rec->setNew(true);
282                 Message* m2 = new Message();
283                 m2->from = this;
284                 m2->to = vRecList;
285                 m2->message = Message::REDRAW;
286                 Command::getInstance()->postMessageNoLock(m2);
287               }
288
289               return 2;
290             }
291
292                         if (selected == MOVE)
293                         {
294                                 VRecMove* vrm = new VRecMove(recman);
295                                 vrm->setParent(this);
296                                 vrm->draw();
297                                 BoxStack::getInstance()->add(vrm);
298                                 BoxStack::getInstance()->update(vrm);
299                                 return 2;
300                         }
301
302                         if (selected == A_DELETE)
303                         {
304                                 VQuestion* v = new VQuestion(this);
305                                 v->setSize(260, 180);
306                                 v->createBuffer();
307                                 v->setTitleBarColour(DrawStyle::DANGER);
308                                 v->setTitleBarOn(1);
309                                 v->setBorderOn(1);
310                                 v->setTitleText(tr("Delete recording"));
311                                 v->setMainText(tr("Are you sure you want to delete this recording?"));
312                                 v->setDefault(VQuestion::NO);
313                                 if (Video::getInstance()->getFormat() == Video::PAL)
314                                 {
315                                         v->setPosition(230, 160);
316                                 }
317                                 else
318                                 {
319                                         v->setPosition(220, 140);
320                                 }
321
322                                 v->draw();
323                                 BoxStack::getInstance()->add(v);
324                                 BoxStack::getInstance()->update(v);
325                                 return 2;
326                         }
327                 }
328                 }
329         } else {
330                 // Pass to tabbar
331                 int retval = tabbar.handleCommand(command);
332                 if (retval == 1)
333                 {
334                         BoxStack::getInstance()->update(this);
335                         return 2;
336                 }
337                 else if (retval == 2)
338                 {
339                         // command was taken and actively ignored
340                         if (command==Remote::LEFT || command==Remote::DF_LEFT
341                                         || command==Remote::RIGHT || command==Remote::DF_RIGHT)
342                         {
343                                 buttons=true;
344                                 button[selected].setActive(1);
345                                 tabbar.activateFocus(false);
346                                 button[selected].draw();
347                                 tabbar.draw();
348                                 BoxStack::getInstance()->update(this);
349                         }
350                         return 2;
351                 }
352         }
353
354
355         // stop command getting to any more views
356         return 1;
357 }
358
359 void VRecording::moveCursor(Direction direction)
360 {
361   button[selected].setActive(0);
362   button[selected].draw();
363   if (direction == RIGHT)
364   { 
365     if (++selected == last) selected = PLAY;
366   }
367   else
368   {
369     if (--selected < 0) selected = last - 1;
370   }
371   button[selected].setActive(1);
372   button[selected].draw();
373   BoxStack::getInstance()->update(this, &buttonRegion);
374 }
375
376 void VRecording::processMessage(Message* m)
377 {
378   if (m->message == Message::MOUSE_MOVE)
379   {
380     for (int i = PLAY; i < last; i++)
381     {
382           if (button[i].mouseMove((m->parameter.num >> 16) - getScreenX(), (m->parameter.num & 0xFFFF) - getScreenY()))
383       {
384         for (int j = PLAY; j < last; j++)
385           button[j].setActive(0);
386         button[i].setActive(1);
387                 tabbar.activateFocus(false);
388                 buttons = true;
389         selected=i;
390         draw();
391         BoxStack::getInstance()->update(this);
392         break;
393       }
394     }
395         if (tabbar.mouseMove((m->parameter.num >> 16) - getScreenX(), (m->parameter.num & 0xFFFF) - getScreenY()))
396         {
397                 BoxStack::getInstance()->update(this);
398                 return;
399         }
400   }
401   else if (m->message == Message::MOUSE_SCROLL)
402   {
403           if (tabbar.mouseAndroidScroll((m->tag >> 16) - getScreenX(), (m->tag & 0xFFFF) - getScreenY(),
404                   (short)(m->parameter.num >> 16), (short) (m->parameter.num & 0xFFFF)))
405           {
406                   BoxStack::getInstance()->update(this);
407                   return;
408           }
409   }
410   else if (m->message == Message::MOUSE_LBDOWN)
411   {
412     int cancel = true;
413     for (int i = PLAY; i < last; i++)
414     {
415       if (button[i].mouseLBDOWN((m->parameter.num>>16)-getScreenX(),(m->parameter.num&0xFFFF)-getScreenY()))
416       {
417         BoxStack::getInstance()->handleCommand(Remote::OK); //simulate OK press
418                 buttons = true;
419         cancel = false;
420         break;
421       }
422     }
423         if (cancel && tabbar.mouseLBDOWN((m->parameter.num >> 16) - getScreenX(), (m->parameter.num & 0xFFFF) - getScreenY()))
424         {
425                 buttons = false;
426                 button[selected].setActive(0);
427
428                 BoxStack::getInstance()->update(this);
429                 cancel = false;
430         }
431     if (cancel)
432     {
433       //check if press is outside this view! then simulate cancel
434       int x=(m->parameter.num>>16)-getScreenX();
435       int y=(m->parameter.num&0xFFFF)-getScreenY();
436       if (x<0 || y <0 || x>(int)getWidth() || y>(int)getHeight())
437       {
438         BoxStack::getInstance()->handleCommand(Remote::BACK); //simulate cancel press
439       }
440     }
441   }
442   else if (m->message == Message::QUESTION_YES)
443   {
444     if (selected == A_DELETE)
445     {
446       Message* m2 = new Message(); // Delete self
447       m2->from = this;
448       m2->to = BoxStack::getInstance();
449       m2->message = Message::CLOSE_ME;
450       Command::getInstance()->postMessageNoLock(m2);
451
452       m2 = new Message(); // OK. Want this to delete before this message does its job
453       m2->from = this;
454       m2->to = vRecList;
455       m2->message = Message::DELETE_SELECTED_RECORDING;
456       Command::getInstance()->postMessageNoLock(m2);
457     }
458   }
459   else if (m->message == Message::MOVE_RECORDING)
460   {
461     Message* m2 = new Message(); // Delete self
462     m2->from = this;
463     m2->to = BoxStack::getInstance();
464     m2->message = Message::CLOSE_ME;
465     Command::getInstance()->postMessageNoLock(m2);
466
467     m2 = new Message();
468     m2->from = this;
469     m2->to = vRecList;
470     m2->message = Message::MOVE_RECORDING;
471     m2->parameter.num = m->parameter.num;
472     Command::getInstance()->postMessageNoLock(m2);
473   }
474 }
475