]> git.vomp.tv Git - vompclient.git/blob - vtimerlist.cc
Message queue fix for VVideoRec
[vompclient.git] / vtimerlist.cc
1 /*
2     Copyright 2004-2020 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, see <https://www.gnu.org/licenses/>.
18 */
19
20 #include <stdio.h>
21 #include <string.h>
22 #include <cstdio>
23 #include <vector>
24
25 #include "message.h"
26 #include "input.h"
27 #include "wsymbol.h"
28 #include "colour.h"
29 #include "video.h"
30 #include "i18n.h"
31 #include "vtimeredit.h"
32 #include "control.h"
33 #include "boxstack.h"
34 #include "vinfo.h"
35 #include "log.h"
36 #include "staticartwork.h"
37
38 #include "vtimerlist.h"
39
40 static const char* TAG = "VTimerList";
41
42 VTimerList::VTimerList()
43 {
44   clockRegion.x = 420;
45   clockRegion.y = 0;
46   clockRegion.w = 150;
47   clockRegion.h = 30;
48
49   setSize(570, 420);
50   createBuffer();
51
52   indicatorsRegion.x = 6;
53   indicatorsRegion.y = 44;
54   indicatorsRegion.w = 18;
55   indicatorsRegion.h = 15 * (getFontHeight() + 1);
56
57   if (Video::getInstance()->getFormat() == Video::PAL)
58   {
59     setPosition(80, 70);
60   }
61   else
62   {
63     setPosition(70, 35);
64   }
65
66   setTitleBarOn(1);
67   setTitleText(tr("Timers"));
68   setTitleBarColour(DrawStyle::TITLEBARBACKGROUND);
69   TVMediaInfo *info= new TVMediaInfo();
70   info->setStaticArtwork(sa_timers);
71   setTitleBarIcon(info);
72
73   sl.setPosition(30, 30 + 5);
74   sl.setSize(area.w - 40, area.h - 30 - 15 - 30);
75   add(&sl);
76
77   MessageQueue::getInstance()->addReceiver(this);
78 }
79
80 void VTimerList::preDelete()
81 {
82   Timers::getInstance()->cancelTimer(this, 1);
83 }
84
85 VTimerList::~VTimerList()
86 {
87   MessageQueue::getInstance()->removeReceiver(this);
88
89   if (recTimerList)
90   {
91     for (UINT i = 0; i < recTimerList->size(); i++)
92     {
93       delete (*recTimerList)[i];
94     }
95
96     recTimerList->clear();
97     delete recTimerList;
98   }
99 }
100
101 void VTimerList::draw()
102 {
103   // Draw statics
104
105   TBBoxx::draw();
106
107   WSymbol w;
108   TEMPADD(&w);
109
110   w.nextSymbol = WSymbol::UP;
111   w.setPosition(20, 385);
112   w.draw();
113
114   w.nextSymbol = WSymbol::DOWN;
115   w.setPosition(50, 385);
116   w.draw();
117
118   w.nextSymbol = WSymbol::SKIPBACK;
119   w.setPosition(85, 385);
120   w.draw();
121
122   w.nextSymbol = WSymbol::SKIPFORWARD;
123   w.setPosition(115, 385);
124   w.draw();
125
126   drawTextRJ("[ok] = edit", 560, 385, DrawStyle::LIGHTTEXT);
127
128   drawClock();
129   drawShowing();
130   drawIndicators();
131 }
132
133 bool VTimerList::load()
134 {
135   recTimerList = VDR::getInstance()->getRecTimersList();
136
137   if (!recTimerList) return false;
138
139   char strA[300];
140   char strB[300];
141
142   struct tm btime;
143
144   // FIXME all drawing stuff in this class and sl.clear somewhere?!
145
146   sl.addColumn(0);
147   sl.addColumn(110);
148
149   RecTimer* recTimer;
150   int first = 1;
151
152   for (UINT i = 0; i < recTimerList->size(); i++)
153   {
154     recTimer = (*recTimerList)[i];
155     time_t rectime = recTimer->startTime;
156     LOCALTIME_R(&rectime, &btime);
157     strftime(strA, 299, "%d/%m %H:%M ", &btime);
158     int check = SNPRINTF(strB, 300, "%s\t%s", strA, recTimer->getName());
159     if ((check < 0) || (check > 299)) LogNT::getInstance()->error(TAG, "String too big");
160     sl.addOption(strB, recTimer, first);
161     first = 0;
162   }
163
164   return true;
165 }
166
167 void VTimerList::drawClock()
168 {
169   // Blank the area first
170 #ifndef GRADIENT_DRAWING
171   rectangle(area.w - 150, 0, 150, 30, titleBarColour);
172 #endif
173
174   char timeString[20];
175   time_t t;
176   time(&t);
177   struct tm tms;
178   LOCALTIME_R(&t, &tms);
179   strftime(timeString, 19, "%d/%m %H:%M:%S", &tms);
180   drawTextRJ(timeString, 560, 5, DrawStyle::LIGHTTEXT);
181
182   Timers::getInstance()->setTimerT(this, 1, t + 1);
183 }
184
185 void VTimerList::drawShowing()
186 {
187   int topOption = sl.getTopOption() + 1;
188   if (sl.getNumOptions() == 0) topOption = 0;
189 #ifndef GRADIENT_DRAWING
190   rectangle(220, 385, 180, 25, DrawStyle::VIEWBACKGROUND);
191 #endif
192   char showing[200];
193   sprintf(showing, tr("%i to %i of %i"), topOption, sl.getBottomOption(), sl.getNumOptions());
194   drawText(showing, 220, 385, DrawStyle::LIGHTTEXT);
195 }
196
197 void VTimerList::quickUpdate() { //only quick for plattform that need it!
198 #ifdef GRADIENT_DRAWING
199       draw();
200 #else
201       sl.draw();
202       drawShowing();
203       drawIndicators();
204 #endif
205 }
206
207 void VTimerList::drawIndicators()
208 {
209   int top = sl.getTopOption();
210   int bottom = sl.getBottomOption();
211   int yinc = getFontHeight() + 1;
212   RecTimer* recTimer;
213 #ifndef GRADIENT_DRAWING
214   rectangle(6, 44, 18, 15*yinc, DrawStyle::VIEWBACKGROUND);
215 #endif
216   // The indexes recorded from the wselectlist into the index member of the RecTimer
217   // Is the same as the position in the vector of RecTimers
218   // Because they are in order, they don't change order and wselectlist starts from 0 up consecutively
219
220   int ypos = 44;
221   for (int current = top; current < bottom; current++)
222   {
223     recTimer = (*recTimerList)[current];
224
225     if (recTimer->recording) // Flashing red square
226     {
227       if (flipflop)
228       {
229         rectangle(6, ypos, 18, 16, DrawStyle::RED);
230         drawText("R", 8, ypos-3, DrawStyle::LIGHTTEXT);
231       }
232     }
233     else if (recTimer->pending)
234     {
235       rectangle(6, ypos, 18, 16, DrawStyle::RED);
236       drawText("X", 8, ypos-3, DrawStyle::BLACK);
237     }
238     else if (recTimer->active == 0)
239     {
240       rectangle(6, ypos, 18, 16, DrawStyle::SELECTHIGHLIGHT);
241       drawText("X", 8, ypos-3, DrawStyle::BLACK);
242     }
243     else
244     {
245 //      if (flipflop) rectangle(6, ypos, 18, 16, DrawStyle::GREEN);
246     }
247
248     ypos += yinc;
249   }
250 }
251
252 void VTimerList::timercall(int /* clientReference */)
253 {
254         flipflop = !flipflop;
255 #ifndef GRADIENT_DRAWING
256   drawClock();
257   BoxStack::getInstance()->update(this, &clockRegion);
258
259   drawIndicators();
260   BoxStack::getInstance()->update(this, &indicatorsRegion);
261 #else
262   draw();
263   BoxStack::getInstance()->update(this);
264 #endif
265 }
266
267 int VTimerList::handleCommand(int command)
268 {
269   switch(command)
270   {
271     case Input::UP:
272     {
273       sl.up();
274       quickUpdate();
275       BoxStack::getInstance()->update(this);
276       return BoxStack::COMMAND_HANDLED;
277     }
278     case Input::DOWN:
279     {
280       sl.down();
281       quickUpdate();
282       BoxStack::getInstance()->update(this);
283       return BoxStack::COMMAND_HANDLED;
284     }
285     case Input::SKIPBACK:
286     {
287       sl.pageUp();
288       quickUpdate();
289       BoxStack::getInstance()->update(this);
290       return BoxStack::COMMAND_HANDLED;
291     }
292     case Input::SKIPFORWARD:
293     {
294       sl.pageDown();
295       quickUpdate();
296       BoxStack::getInstance()->update(this);
297       return BoxStack::COMMAND_HANDLED;
298     }
299     case Input::OK:
300     {
301       RecTimer* recTimer = NULL;
302       if (recTimerList) recTimer = reinterpret_cast<RecTimer*>(sl.getCurrentOptionData());
303       if (recTimer == NULL) return BoxStack::COMMAND_HANDLED;
304
305       VTimerEdit* v = new VTimerEdit(recTimer);
306       v->setParent(this);
307       v->draw();
308       BoxStack::getInstance()->add(v);
309       BoxStack::getInstance()->update(v);
310
311       return BoxStack::COMMAND_HANDLED;
312     }
313     case Input::BACK:
314     {
315       return BoxStack::DELETE_ME;
316     }
317   }
318   // stop command getting to any more views
319   return BoxStack::ABANDON_COMMAND;
320 }
321
322 void VTimerList::processMessage(Message* m)
323 {
324   if (m->message == Message::MOUSE_MOVE)
325   {
326     if (sl.mouseMove(m->parameter - getScreenX(), m->tag - getScreenY()))
327     {
328       quickUpdate();
329       BoxStack::getInstance()->update(this);
330     }
331   }
332   else if (m->message == Message::MOUSE_LBDOWN)
333   {
334     if (sl.mouseLBDOWN(m->parameter - getScreenX(), m->tag - getScreenY()))
335     {
336       Input::sendInputKey(Input::OK);
337     }
338     else if (coordsOutsideBox(m))
339     {
340       Input::sendInputKey(Input::BACK);
341     }
342   }
343   else if (m->message == Message::DELETE_SELECTED_TIMER)
344   {
345     RecTimer* recTimer = reinterpret_cast<RecTimer*>(sl.getCurrentOptionData());
346     if (recTimer == NULL) return;
347     LogNT::getInstance()->debug(TAG, "Got timer to delete");
348
349   
350     ULONG retval = VDR::getInstance()->deleteTimer(recTimer);
351     if (!VDR::getInstance()->isConnected()) { Control::getInstance()->connectionLost(); return; }
352     LogNT::getInstance()->debug(TAG, "Got return fron delete timer: {}", retval);
353     
354     if (retval != 10)
355     {
356       VInfo* errorBox = new VInfo();
357       errorBox->setSize(360, 200);
358       errorBox->createBuffer();
359       if (Video::getInstance()->getFormat() == Video::PAL)
360         errorBox->setPosition(190, 170);
361       else
362         errorBox->setPosition(180, 120);
363
364     
365       if (retval == 1) errorBox->setOneLiner(tr("Timers being edited at VDR, please try later"));
366       else if (retval == 3)  errorBox->setOneLiner(tr("Unable to delete timer - timer is running"));
367       else if (retval == 4)  errorBox->setOneLiner(tr("Error - timer not found at VDR"));
368       else                   errorBox->setOneLiner(tr("Unknown error"));
369
370       errorBox->setExitable();
371       errorBox->setBorderOn(1);
372       errorBox->setTitleBarColour(DrawStyle::DANGER);
373       errorBox->okButton();
374       errorBox->draw();
375       BoxStack::getInstance()->add(errorBox);
376       BoxStack::getInstance()->update(errorBox);
377     }
378     
379     int saveIndex = sl.getCurrentOption();
380     int saveTop = sl.getTopOption();
381      
382     if (recTimerList)
383     {
384       for (UINT i = 0; i < recTimerList->size(); i++)
385       {
386         delete (*recTimerList)[i];
387       }
388
389       recTimerList->clear();
390       delete recTimerList;
391     }
392
393     sl.clear();
394     load();
395
396     sl.hintSetCurrent(saveIndex);
397     sl.hintSetTop(saveTop);
398     draw();
399     BoxStack::getInstance()->update(this);
400   }
401 }
402