]> git.vomp.tv Git - vompclient-marten.git/blob - vpicture.cc
*** empty log message ***
[vompclient-marten.git] / vpicture.cc
1 /*
2     Copyright 2004-2005 Chris Tallon, Andreas Vogel
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 <time.h>
22
23 #include "vpicture.h"
24
25 #include "vpicturebanner.h"
26 #include "timers.h"
27 #include "boxx.h"
28 #include "wselectlist.h"
29 #include "remote.h"
30 #include "wsymbol.h"
31 #include "boxstack.h"
32 #include "vdr.h"
33 #include "media.h"
34 #include "video.h"
35 #include "vinfo.h"
36 #include "i18n.h"
37 #include "message.h"
38 #include "command.h"
39
40 Colour VPicture::pictureBack=Colour(140,140,140);
41 Colour VPicture::infoBack=Colour(110,110,110);
42 //the jpeg reader
43
44 class VPreader : public JpegReader {
45   private:
46     VPicture * parent;
47   public:
48   VPreader(VPicture *p){
49      parent=p;};
50   virtual ULONG readChunk(ULONG offset,ULONG len,char ** buf) {
51      Log::getInstance()->log("VPicture::jpegReader", Log::DEBUG, "read chunk o=%d,len=%d,buf=%p",
52         offset,len,*buf);
53      UINT numrec=0;
54      *buf=(char *)VDR::getInstance()->getImageBlock(offset,(UINT)len,&numrec);
55      Log::getInstance()->log("VPicture::jpegReader", Log::DEBUG, "got n=%d,buf=%p",
56         numrec,*buf);
57      return numrec;
58      }
59   virtual ULONG initRead(const char *filename) {
60      Log::getInstance()->log("VPicture::jpegReader", Log::DEBUG, "load image %s",filename);
61      Video* video = Video::getInstance();
62      ULONG size=VDR::getInstance()->loadImage(filename,video->getScreenWidth(), video->getScreenHeight());
63      Log::getInstance()->log("VPicture::jpegReader", Log::DEBUG, "load image %s returned %d",filename,size);
64      return size;
65      }
66 };
67
68 VPicture::VPicture(VMediaList *p)
69 {
70   parent=p;
71   reader=new VPreader(this);
72   needDraw=false;
73   Video* video = Video::getInstance();
74   setSize(video->getScreenWidth(), video->getScreenHeight());
75   createBuffer();
76 //  jpeg.setSurface(surface);
77   jpeg.setDimensions(area.w,area.h);
78   banner=NULL;
79   fullname=NULL;
80   filename=NULL;
81   ftime=0;
82   slideshow=false;
83   showtime=INITIAL_SHOWTIME;
84   mediaError=NULL;
85   currentMedia=NULL;
86   shortBanner=false;
87   rotate=0;
88   info=NULL;
89   jpeg.setBackgroundColour(pictureBack);
90   add(&jpeg);
91 }
92
93 void VPicture::preDelete()
94 {
95   Timers::getInstance()->cancelTimer(this,1);
96   Timers::getInstance()->cancelTimer(this,2);
97   Timers::getInstance()->cancelTimer(this,3);
98 }
99
100 VPicture::~VPicture()
101 {
102   delete reader;
103   if (banner) BoxStack::getInstance()->remove(banner);
104   if (fullname) delete fullname;
105   if (filename) delete filename;
106
107   destroyInfo();
108   
109 }
110
111 void VPicture::draw()
112 {
113   Log::getInstance()->log("VPicture::draw", Log::DEBUG, "needDraw=%d,p=%p", needDraw,this);
114   Boxx::draw();
115   
116   if (mediaError) {
117     drawText(mediaError,20,area.h-10,Colour::LIGHTTEXT);
118     return;
119     }
120 }
121
122
123 int VPicture::handleCommand(int command)
124 {
125   Timers::getInstance()->cancelTimer(this,1);
126   int rt=1;
127   switch(command)
128   {
129     case Remote::DF_UP:
130     case Remote::UP:
131     case Remote::SKIPBACK:
132       showPicture(VMediaList::MV_PREV);
133       BoxStack::getInstance()->update(this);
134       rt= 2;
135       break;
136     case Remote::FORWARD:
137       if (showtime > 1) showtime--;
138       updateBanner(true);
139       break;
140     case Remote::DF_DOWN:
141     case Remote::DOWN:
142     case Remote::SKIPFORWARD:
143       showPicture(VMediaList::MV_NEXT);
144       BoxStack::getInstance()->update(this);
145       rt= 2;
146       break;
147     case Remote::REVERSE:
148       if (showtime < 50 ) showtime++;
149       updateBanner(true);
150       break;
151     case Remote::OK:
152     {
153       if (banner) {
154         destroyBanner();
155         destroyInfo();
156         }
157       else showBanner();
158       rt= 2;
159     }
160     break;
161     case Remote::PLAY:
162     {
163       slideshow=true;
164       showPicture(VMediaList::MV_NEXT);
165       BoxStack::getInstance()->update(this);
166       rt= 2;
167     }
168     break;
169     case Remote::PAUSE:
170       slideshow=false;
171       updateBanner();
172       rt= 2;
173       break;
174     case Remote::STOP:
175       slideshow=false;
176       showtime=INITIAL_SHOWTIME;
177       updateBanner();
178       rt= 2;
179       break;
180     case Remote::RED:
181       switch(rotate) {
182         case WJpeg::ROT_0:
183           rotate=WJpeg::ROT_90;
184           break;
185         case WJpeg::ROT_90:
186           rotate=WJpeg::ROT_180;
187           break;
188         case WJpeg::ROT_180:
189           rotate=WJpeg::ROT_270;
190           break;
191         case WJpeg::ROT_270:
192           rotate=WJpeg::ROT_0;
193           break;
194         }
195       showPicture(VMediaList::MV_NONE,rotate);
196       BoxStack::getInstance()->update(this);
197       rt=2;
198       break;
199     case Remote::GREEN:
200       if (info) destroyInfo();
201       else showInfo();
202       rt=2;
203       break;
204     case Remote::BACK:
205     {
206       destroyBanner();
207       rt= 4;
208     }
209     break;
210   }
211   if (slideshow) startSlideshow();
212   // stop command getting to any more views
213   return rt;
214 }
215
216 void VPicture::processMessage(Message* m)
217 {
218   if (m->message == Message::MOUSE_MOVE)
219   {
220     ;
221   }
222   else if (m->message == Message::MOUSE_LBDOWN)
223   {
224     
225     //check if press is outside this view! then simulate cancel
226     int x=(m->parameter>>16)-getScreenX();
227     int y=(m->parameter&0xFFFF)-getScreenY();
228     if (x<0 || y <0 || x>(int)getWidth() || y>(int)getHeight())
229     {
230       BoxStack::getInstance()->handleCommand(Remote::BACK); //simulate cancel press
231     }
232   }
233 }
234
235 VPicture * VPicture::createViewer(VMediaList * mparent, bool bslideshow) {
236    Log::getInstance()->log("VPicture::createViewer", Log::DEBUG, "p=%p",
237         mparent);
238    VPicture *vmn=new VPicture(mparent);
239    BoxStack::getInstance()->add(vmn);
240    BoxStack::getInstance()->update(vmn);
241    vmn->showPicture();
242    if (bslideshow) vmn->startSlideshow();
243    vmn->showBanner();
244    BoxStack::getInstance()->update(vmn);
245    return vmn;
246 }
247
248 void VPicture::startSlideshow() {
249    slideshow=true;
250    Timers::getInstance()->setTimerD(this,1,showtime);
251 }
252
253 void VPicture::showPicture(ULONG move, int rt) {
254   rotate=rt;
255   currentMedia=parent->getMedia(MEDIA_TYPE_PICTURE,move);
256   load(currentMedia);
257   if (mediaError || jpeg.hasError()) destroyInfo();
258   else updateInfo();
259   BoxStack::getInstance()->update(this);
260 }
261
262
263 int VPicture::load(Media *md) {
264   jpeg.init(NULL,false,NULL);
265   mediaError=tr("No media found");
266   needDraw=false;
267   if (! md) return 1;
268   const char *fname=md->getFileName();
269   ftime=md->getTime();
270   int len=strlen(fname)+2+strlen(parent->getDirname());
271   if (fullname) {
272      delete fullname;
273      fullname=NULL;
274      }
275   fullname=new char[len];
276   sprintf(fullname,"%s/%s",parent->getDirname(),fname);
277   if (filename) delete filename;
278   len=strlen(fname)+1;
279   filename=new char[len];
280   strcpy(filename,fname);
281   Log::getInstance()->log("VPicture::load", Log::DEBUG, "filename=%s,p=%p",
282         fullname,this);
283   VDR* vdr=VDR::getInstance();
284   //do we have a banner?
285   bool haveBanner=banner!=NULL && ! shortBanner;
286   if (vdr->isConnected()) {
287      showBanner(true);
288      jpeg.init(fullname,false,reader);
289      jpeg.setRotate(rotate);
290      needDraw=true;
291      mediaError=NULL;
292      draw();
293      //only show the banner if it was there before
294      if (haveBanner) showBanner();
295      else {
296         if(banner) destroyBanner();
297         }
298      Log::getInstance()->log("VPicture::load", Log::DEBUG, "success: filename=%s,p=%p",
299         fullname,this);
300      return 0;
301   }
302   else {
303     mediaError=tr("no VDR connection");
304     }
305   return 1;
306 }
307
308 void VPicture::showBanner(bool loading,int shortDisplay) {
309         //we are in the main thread - so we can (and must) safely hard destroy/create the banner
310   Timers::getInstance()->cancelTimer(this,2);
311   if (! filename || ! currentMedia) {
312     //hmm...
313     destroyBanner(!loading);
314     return;
315     }
316   if (banner) destroyBanner(!loading);
317   banner= new VPictureBanner(this, loading, slideshow);
318   banner->fillColour(infoBack);
319   if (! loading) {
320     int len=strlen(filename)+Media::TIMEBUFLEN+20;
321     char *buf=new char[len];
322     char tbuf[Media::TIMEBUFLEN];
323     SNPRINTF(buf,len,"%c%02ds%c %s %s ",
324       slideshow?' ':'[',
325       showtime,
326       slideshow?' ':']',
327       currentMedia->getTimeString(tbuf),
328       filename);
329     banner->setText(buf);
330     delete [] buf;
331   }
332   else {
333     banner->setText(filename);
334   }
335   banner->draw();
336   if (shortDisplay != 0) shortBanner=true;
337   if (! slideshow && shortDisplay == 0) shortDisplay=8;
338   //OK we start timer if we don't load and either shortDisplay or no slideshow
339   if (! loading && shortDisplay != 0)   Timers::getInstance()->setTimerD(this,2,shortDisplay);
340         BoxStack::getInstance()->add(banner);
341         BoxStack::getInstance()->update(banner);
342
343   }
344
345 void VPicture::destroyBanner(bool fromTimer) {
346   shortBanner=false;
347   if (banner) {
348     if (fromTimer) sendViewMsg(banner,true); 
349                 else BoxStack::getInstance()->remove(banner);
350     banner=NULL;
351     if (! fromTimer) Timers::getInstance()->cancelTimer(this,2);
352     }
353 }
354 void VPicture::updateBanner(bool shortDisplay) {
355   if (banner && ! shortBanner) {
356     showBanner(false);
357     }
358   else if (shortDisplay) {
359     showBanner(false,2);
360     }
361 }
362 void VPicture::timercall(int clientref) {
363    switch(clientref)
364    {
365       case 1:
366         if (! slideshow) return;
367         Log::getInstance()->log("VPicture::timercall", Log::DEBUG, "slideshow");
368                                 sendCommandMsg(Remote::PLAY);
369         break;
370       case 2:
371         destroyBanner(true);
372         break;
373       case 3:
374         destroyInfo(true);
375         break;
376     }
377    
378   }
379
380 #define INFOBUF 1000
381 void VPicture::showInfo(){
382   if (info) destroyInfo();
383   if (! currentMedia) return;
384
385   info=new VInfo();
386   info->setTitleText(currentMedia->getFileName());
387   info->setDropThrough();
388   info->setSize(500, 300);
389   info->createBuffer();
390   info->setBorderOn(1);
391   info->setTitleBarOn(1);
392
393   if (Video::getInstance()->getFormat() == Video::PAL)
394         info->setPosition(100, 180);
395   else
396         info->setPosition(100, 150);
397   char buf[INFOBUF];
398   char tbuf[Media::TIMEBUFLEN];
399   SNPRINTF(buf,INFOBUF,"%s= %s\n%s= %ld x %ld\n%s= %ld kBytes\n%s= %s\n%s= %ld\n%s= 1/%ld",
400      tr("Directory"), parent->getDirname(),
401      tr("Format(px)"),jpeg.getJpegInfo(WJpeg::JPEG_WIDTH),jpeg.getJpegInfo(WJpeg::JPEG_HEIGHT),
402      tr("Filesize"),jpeg.getJpegInfo(WJpeg::JPEG_SIZE)/1000,
403      tr("Time"),currentMedia->getTimeString(tbuf),
404      tr("Rotation"),90*jpeg.getJpegInfo(WJpeg::JPEG_ROTATE),
405      tr("Scale"),jpeg.getJpegInfo(WJpeg::JPEG_SCALE));
406   info->setMainText(buf);
407   info->draw();
408   sendViewMsg(info,false);
409   Timers::getInstance()->setTimerD(this,3,8);
410 }
411 void VPicture::updateInfo(){
412   if (info) {
413     showInfo();
414     }
415 }
416 void VPicture::destroyInfo(bool fromTimer){
417   if (info) {
418     sendViewMsg(info,true);
419     info=NULL;
420     }
421   if (! fromTimer) Timers::getInstance()->cancelTimer(this,3);
422 }
423
424 void VPicture::sendViewMsg(Boxx *v,bool vdestroy) {
425         Message* m = new Message(); 
426   m->message = vdestroy?Message::CLOSE_ME:Message::ADD_VIEW;
427   m->to = BoxStack::getInstance();
428   m->from = v;
429         m->parameter=(ULONG)v;
430   Command::getInstance()->postMessageFromOuterSpace(m);
431 }
432 void VPicture::sendCommandMsg(int command) {
433         Message* m = new Message(); 
434   m->message = Message::UDP_BUTTON;
435   m->to = Command::getInstance();
436   m->from = this;
437         m->parameter=command;
438   Command::getInstance()->postMessageFromOuterSpace(m);
439 }