]> git.vomp.tv Git - vompclient.git/blob - vmediaview.cc
Preparations for dynamic mode switching
[vompclient.git] / vmediaview.cc
1 /*\r
2     Copyright 2004-2005 Chris Tallon, Andreas Vogel\r
3 \r
4     This file is part of VOMP.\r
5 \r
6     VOMP is free software; you can redistribute it and/or modify\r
7     it under the terms of the GNU General Public License as published by\r
8     the Free Software Foundation; either version 2 of the License, or\r
9     (at your option) any later version.\r
10 \r
11     VOMP is distributed in the hope that it will be useful,\r
12     but WITHOUT ANY WARRANTY; without even the implied warranty of\r
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
14     GNU General Public License for more details.\r
15 \r
16     You should have received a copy of the GNU General Public License\r
17     along with VOMP; if not, write to the Free Software\r
18     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
19 */\r
20 \r
21 #include <time.h>\r
22 \r
23 #include "vmediaview.h"\r
24 \r
25 #include "vpicturebanner.h"\r
26 #include "vcolourtuner.h"\r
27 #include "audioplayer.h"\r
28 #include "timers.h"\r
29 #include "boxx.h"\r
30 #include "wselectlist.h"\r
31 #include "remote.h"\r
32 #include "wsymbol.h"\r
33 #include "boxstack.h"\r
34 #include "vdr.h"\r
35 #include "media.h"\r
36 #include "video.h"\r
37 #include "vinfo.h"\r
38 #include "i18n.h"\r
39 #include "message.h"\r
40 #include "command.h"\r
41 #include "mediaoptions.h"\r
42 #include "mediaplayer.h"\r
43 #include "log.h"\r
44 \r
45 const int VMediaView::EVENT_SLIDESHOW=100;\r
46 const int VMediaView::EVENT_DRAWINGDONE=101;\r
47 const int VMediaView::EVENT_DRAWINGERROR=102;\r
48 const int VMediaView::EVENT_DIRECTORYDONE=103;\r
49 \r
50 \r
51 /**\r
52   * the combined user interface for pictures and audio\r
53   * has 2 surfaces to enable drawing in a separate thread\r
54   * the info display can either show a picture info or and audio info\r
55   * if the audio player comes on top it disables the picture info display\r
56   * basically we have 3 modes:\r
57   *   - HIDDEN viewer is hidden (pictureEnabled=false, audioEnabled=false)\r
58   *     if justPlaying=true the audioplayer is still running\r
59   *   - PICTURE picture viewer on top ("slide show") - pictureEnabled=true, audioEnabled=false\r
60   *     no AudioBanner visible\r
61   *     if justPlaying=true the audio player runs in bg\r
62   *   - AUDIO audioPlayer on top ("playlist mode") - pictureEnabled=true, audioEnabled=true\r
63   *     the picture viewer is currently halted (should be able to continue if no AudioInfo)\r
64   *     no picture banner (we should have an audio banner to indicate the audio player on top!)\r
65   * state transitions (via setPictureMode, setAudioMode)\r
66   *   - show Picture -> pictureEnabled=true, \r
67   *     only called from command handler if audioEnabled=false\r
68   *     call from mediaList only possible if audioEnabled=false\r
69   *         *** TODO: would be better to have separate function for external call/internal call\r
70   *   - play [Audio] -> if activate is set -> audioEnabled=true (-> Mode AUDIO)\r
71   *                     used for calls from medialist\r
72   *                     internal calls do not set activate!\r
73   *   - YELLOW key - toggle\r
74   *     if audioActive==true -> audioActive=false (new mode depends on pictureEnabled - either HIDDEN or PICTURE)\r
75   *     if audioActive==false -> audioActive=true (new mode AUDIO)\r
76   *          *** open handling if no audio file there (ignore key???) - currently empty player\r
77   *   - BACK if mode AUDIO -> audioEnabled=false, justPlaying=false\r
78   *   - BACK if mode PICTURE -> pictureEnabled=false;\r
79   *   - player StreamEnd -> audioEnabled=false (new mode depends on pciture - either HIDDEN or PICTURE)\r
80   * info/banner handling:\r
81   *   - AudioInfo - alternativ to pictureInfo\r
82   *     off when disabling audio or after timer or with OK in AUDIO mode\r
83   *     on currently any command or player event (end/new song) when audioEnabled==true and retriggerAudioInfo=true\r
84   *     on on OK in AUDIO mode\r
85   *   - Picture Info\r
86   *     off when disabling Picture or after timer, OK, green\r
87   *     on only on green when pictureEnabled==true\r
88   *   - PictureBanner\r
89   *     2 modes: loading/normal\r
90   *       normal:\r
91   *       off when disabling picture, OK, after timer\r
92   *       on when enabling picture, with OK\r
93   *       loading:\r
94   *       off when disabling picture and when loading done\r
95   *       on on start loading\r
96   *          *** open: do not show when audio enabled and slide show running (currently slideshow is paused)\r
97   *   - AudioBanner\r
98   *       always shown when audioEnabled=true\r
99   *       on when enabling Audio\r
100   *       off when disabling audio\r
101   *       update in play\r
102   * timers: 1 - slide show\r
103   *         2 - pictureBanner\r
104   *         3 - info showtime\r
105   *         4 - audio short update\r
106   */\r
107 \r
108 #define DRAWING_THREAD\r
109 \r
110 DrawStyle VMediaView::pictureBack=DrawStyle(140,140,140);\r
111 DrawStyle VMediaView::infoBack=DrawStyle(110,110,110);\r
112 DrawStyle VMediaView::audioBannerBack=DrawStyle(110,110,110,20);\r
113 //the jpeg reader\r
114 \r
115 //how long do we wait for a single picture chunk\r
116 //the unit is 100ms (the timeout on the server side)\r
117 #define MAXTRY 100 \r
118 class VPreader : public JpegReader {\r
119   private:\r
120     ImageReader *reader;\r
121     VMediaView * parent;\r
122     ULLONG size;\r
123     bool dobreak;;\r
124   public:\r
125   VPreader(VMediaView *p,ImageReader *r){ \r
126     parent=p;\r
127     size=0;\r
128     reader=r;\r
129     dobreak=false;\r
130   };\r
131   virtual ULONG readChunk(ULONG offset,ULONG len,char ** buf) {\r
132      Log::getInstance()->log("VMediaView::jpegReader", Log::DEBUG, "read chunk o=%d,len=%d,buf=%p",\r
133         offset,len,*buf);\r
134      UINT numrec=0;\r
135      int rt=0;\r
136      for (int trycount=0;trycount < MAXTRY && ! dobreak && numrec == 0 && rt == 0;trycount++) {\r
137        if (dobreak) {\r
138          *buf=NULL;\r
139          rt=-1;\r
140        }\r
141        else {\r
142          rt=reader->getImageChunk((ULLONG)offset,(UINT)len,&numrec,(UCHAR **)buf);\r
143        }\r
144      }\r
145      Log::getInstance()->log("VMediaView::jpegReader", Log::DEBUG, "got n=%d,buf=%p,rt=%d",\r
146         numrec,*buf,rt);\r
147      return numrec;\r
148      }\r
149   virtual int initRead(const MediaURI *uri,ULLONG *sz,ULONG factor=100) {\r
150      Log::getInstance()->log("VMediaView::jpegReader", Log::DEBUG, "load image %s",uri->getDisplayName());\r
151      Video* video = Video::getInstance();\r
152      dobreak=false;\r
153      int rt=MediaPlayer::getInstance()->openMedium(1,uri,sz,video->getScreenWidth()*factor/100, video->getScreenHeight()*factor/100);\r
154      if (rt < 0) *sz=0;\r
155      size=*sz;\r
156      Log::getInstance()->log("VMediaView::jpegReader", Log::DEBUG, "load image %s returned %llu",uri->getDisplayName(),size);\r
157      return rt;\r
158      }\r
159   virtual ULONG getSize() {return size;}\r
160   //seems to be thread safe (more or less...)\r
161   void setBreak() {\r
162     dobreak=true;\r
163   }\r
164 };\r
165 \r
166 /**\r
167   * a separate thread for drawing pictures\r
168   * will be started with the sfc and the draw control\r
169   * will send a player event when done\r
170   */\r
171 class DrawingThread : public Thread_TYPE {\r
172   private:\r
173     VMediaView *_parent;\r
174     VPreader * _reader;\r
175     WJpegComplex::JpegControl *_ctl;\r
176     Surface *_sfc;\r
177     DrawStyle _colour;\r
178     bool _interrupted;\r
179   public:\r
180     DrawingThread(VMediaView *parent) {\r
181       _parent=parent;\r
182       _reader=NULL;\r
183       _ctl=NULL;\r
184       _sfc=NULL;\r
185       _interrupted=false;\r
186     }\r
187     virtual ~DrawingThread(){}\r
188     bool isRunning() {\r
189       return (threadIsActive()!=0);\r
190     }\r
191     bool start(WJpegComplex::JpegControl *ctl,Surface *sfc,VPreader *reader,DrawStyle &c) {\r
192       if (isRunning()) {\r
193         return false;\r
194       }\r
195       _interrupted=false;\r
196       _ctl=ctl;\r
197       _sfc=sfc;\r
198       _reader=reader;\r
199       _colour=c;\r
200       return (threadStart() == 1);\r
201     }\r
202     bool stop() {\r
203       Log::getInstance()->log("DrawingThread",Log::DEBUG,"stop initiated");\r
204       if (threadIsActive()) {\r
205         _interrupted=true;\r
206         if (_reader) _reader->setBreak();\r
207         threadStop();\r
208       }\r
209       Log::getInstance()->log("DrawingThread",Log::DEBUG,"stop done");\r
210       _reader=NULL;\r
211       return true;\r
212     }\r
213   protected:\r
214     virtual void threadMethod() {\r
215       Log::getInstance()->log("DrawingThread",Log::DEBUG,"started");\r
216       bool rt=WJpegComplex::drawJpeg(_ctl,_sfc,_reader,_colour);\r
217       _reader=NULL;\r
218       if (! _interrupted) {\r
219         Message* m = new Message(); \r
220         //we misuse PLAYER_EVENT here\r
221         m->message = Message::PLAYER_EVENT;\r
222         m->to = _parent;\r
223         m->from = _parent;\r
224         m->parameter= rt?VMediaView::EVENT_DRAWINGDONE:VMediaView::EVENT_DRAWINGERROR;\r
225         Command::getInstance()->postMessageFromOuterSpace(m);\r
226       }\r
227       Log::getInstance()->log("DrawingThread",Log::DEBUG,"finishing interrupt=%d",(int)_interrupted);\r
228     }\r
229     virtual void threadPostStopCleanup() {}\r
230 \r
231 };\r
232 \r
233 \r
234 VMediaView::VMediaView(VMediaList *p)\r
235 {\r
236   Log::getInstance()->log("VMediaView::VMediaView", Log::DEBUG, "p=%p", this);\r
237   audioEnabled=false;\r
238   pictureEnabled=false;\r
239   parent=p;\r
240   ireader=new ImageReader(1,MediaPlayer::getInstance());\r
241   reader=new VPreader(this,ireader);\r
242   //the surface handling\r
243   Video* video = Video::getInstance();\r
244   setSize(video->getScreenWidth(), video->getScreenHeight());\r
245   createBuffer();\r
246   sfc2=getSurface();\r
247   surface=NULL;\r
248   //create the second surface\r
249   createBuffer();\r
250   sfc1=getSurface();\r
251   originalh=area.h;\r
252   originalw=area.w;\r
253   //disable the surface\r
254   area.h=1;\r
255   area.w=1;\r
256   //banners and infos\r
257   pictureBanner=NULL;\r
258   slideshow=false;\r
259   pictureError=NULL;\r
260   currentPicture=NULL;\r
261   info=NULL;\r
262   pictureLoading=false;\r
263 \r
264   //picture settings\r
265   showtime=INITIAL_SHOWTIME;\r
266   rotate=WJpegComplex::ROT_0;\r
267   currentScale=1;\r
268   options=MediaOptions::getInstance();\r
269   VColourTuner::initFactors();\r
270   int st=options->getIntOption("SlideShowInterval");\r
271   if (st > 0) showtime=st;\r
272   ctl.area.w=originalw;\r
273   ctl.area.h=originalh;\r
274   ctl.enlarge=false;\r
275   ctl.scaleafter=options->getIntOption("ScaleFactor");\r
276   const char * mode=options->getStringOption("PictureMode");\r
277   if (strcmp(mode,"clip") == 0) ctl.mode=WJpegComplex::CROP;\r
278   else if (strcmp(mode,"letter") == 0) ctl.mode=WJpegComplex::LETTER;\r
279   else if (strcmp(mode,"clipfactor") == 0) ctl.mode=WJpegComplex::CROPPERCENT;\r
280   ctl.scaleAmount=options->getIntOption("PictureSize");\r
281   if (ctl.scaleAmount < 10) ctl.scaleAmount=10;\r
282   if (ctl.scaleAmount > 200) ctl.scaleAmount=200;\r
283   ctl2=ctl;\r
284   cropmode=ctl.mode;\r
285   //current control is the one used for DISPLAY (not the one for drawing - this is the other one)\r
286   //this is closely coupled to the surface - i.e. ctl is for sfc1, ctl2 for sfc2\r
287   currentControl=&ctl;\r
288   bannerEnabled=true;\r
289   pictureShowing=false;\r
290 \r
291   //audio player\r
292 \r
293   barBlue.set(0, 0, 150, 150);\r
294   audioError=NULL;\r
295   currentAudio=NULL;\r
296   justPlaying=false;\r
297   playall=false;\r
298   retriggerAudioInfo=false;\r
299   audioBanner=NULL;\r
300   drawingThread=new DrawingThread(this);\r
301 }\r
302 \r
303 VMediaView::~VMediaView()\r
304 {\r
305   Log::getInstance()->log("VMediaView::~VMediaView", Log::DEBUG, "p=%p,secondSfc=%s", this,(secondSurface()?"true":"false"));\r
306   destroyPictureBanner();\r
307   if (currentPicture) delete currentPicture;\r
308   Timers::getInstance()->cancelTimer(this,1);\r
309   Timers::getInstance()->cancelTimer(this,2);\r
310   Timers::getInstance()->cancelTimer(this,3);\r
311   Timers::getInstance()->cancelTimer(this,4);\r
312   Timers::getInstance()->cancelTimer(this,5);\r
313   destroyInfo();\r
314   destroyAudioBanner();\r
315   if (getPlayer(false)) {\r
316     AudioPlayer::getInstance(NULL,false)->shutdown();\r
317   }\r
318   if (currentAudio) delete currentAudio;\r
319   drawingThread->stop();\r
320   ireader->shutdown();\r
321   delete ireader;\r
322   delete reader;\r
323   if (secondSurface()) {\r
324     delete sfc1;\r
325     sfc1=NULL;\r
326   }\r
327   else {\r
328     delete sfc2;\r
329     sfc2=NULL;\r
330   }\r
331   MediaPlayer::getInstance()->closeMediaChannel(1);\r
332   MediaPlayer::getInstance()->closeMediaChannel(2);\r
333   Log::getInstance()->log("VMediaView::~VMediaView", Log::DEBUG, "done p=%p", this);\r
334 }\r
335 \r
336 void VMediaView::setPictureMode(bool act) {\r
337   Log::getInstance()->log("VMediaView", Log::DEBUG, "set pictureMode %d p=%d, a=%d", (int)act,(int)pictureEnabled,(int)audioEnabled);\r
338   if ( act) {\r
339     if ( ! pictureEnabled && ! audioEnabled) {\r
340       area.h=originalh;\r
341       area.w=originalw;\r
342       showPictureBanner();\r
343       parent->updateAll();\r
344     }\r
345     if (! pictureEnabled) {\r
346       //we newly enable the picture - so clear the screen\r
347       draw();\r
348       BoxStack::getInstance()->update(this);\r
349       if (slideshow) startSlideshow();\r
350     }\r
351   }\r
352   else \r
353   {\r
354     if ( pictureEnabled) {\r
355       destroyPictureBanner();\r
356       stopSlideshow(false);\r
357 #ifdef DRAWING_THREAD\r
358       drawingThread->stop();\r
359 #endif\r
360       if (! audioEnabled) {\r
361         destroyInfo();\r
362         area.w=1;\r
363         area.h=1;\r
364         draw();\r
365         parent->updateAll();\r
366       }\r
367     }\r
368     pictureShowing=false;\r
369   }\r
370   pictureEnabled=act;\r
371 }\r
372 \r
373 //we can disable audio without automatically hiding us\r
374 //this will become strange - we are visible but do not handle\r
375 //keys - so if you call setAudioMode(false,false) be sure\r
376 //to call setAudioMode(false,true) afterwards\r
377 //it is only here to give the list a chance to start a new play\r
378 //when we call directoryDone\r
379 void VMediaView::setAudioMode(bool act,bool doHiding) {\r
380   Log::getInstance()->log("VMediaView", Log::DEBUG, "setAudioMode  %d p=%d, a=%d", (int)act,(int)pictureEnabled,(int)audioEnabled);\r
381   if ( act) {\r
382     if (! audioEnabled) {\r
383       if (! pictureEnabled) {\r
384         area.w=originalw;\r
385         area.h=originalh;\r
386         draw(); //empty screen if no picture\r
387         parent->updateAll();\r
388       }\r
389       destroyPictureBanner();\r
390 \r
391     }\r
392     audioEnabled=true;\r
393     showAudioBanner();\r
394     showAudioInfo();\r
395   }\r
396   else \r
397   {\r
398     if ( audioEnabled) {\r
399       audioEnabled=false;\r
400       destroyInfo();\r
401       destroyAudioBanner();\r
402     }\r
403     if (! pictureEnabled  && doHiding) {\r
404       area.w=1;\r
405       area.h=1;\r
406       draw();\r
407       parent->updateAll();\r
408     }\r
409     else {\r
410       //picture now on top\r
411       if (havePictureBanner && ! pictureBanner) showPictureBanner();\r
412     }\r
413   }\r
414 }\r
415 \r
416 \r
417 \r
418 void VMediaView::draw()\r
419 {\r
420   Log::getInstance()->log("VMediaView::draw", Log::DEBUG, "pictureError=%s,p=%p", pictureError,this);\r
421   \r
422   if (pictureShowing ) fillColour(pictureBack);\r
423   else fillColour(DrawStyle::BLACK);\r
424   if (pictureError) {\r
425     drawText(pictureError,100,area.h/2,DrawStyle::LIGHTTEXT);\r
426     return;\r
427     }\r
428 }\r
429 \r
430 \r
431 int VMediaView::handleCommand(int command)\r
432 {\r
433   Log::getInstance()->log("VMediaView::handleCommand", Log::DEBUG, "cmd=%d,p=%p", command,this);\r
434   if ( !audioEnabled && ! pictureEnabled ) {\r
435     //only handle YELLOW\r
436     if (command == Remote::YELLOW) {\r
437       setAudioMode(true);\r
438       return 1;\r
439     }\r
440     return 0;\r
441   }\r
442   if ( ! audioEnabled) {\r
443     //------------------------- command in mode PICTURE (i.e. picture is on top) ----------------\r
444     //picture on top\r
445     int rt=1;\r
446     switch(command)\r
447     {\r
448       case Remote::DF_UP:\r
449       case Remote::UP:\r
450       case Remote::SKIPBACK:\r
451         rotate=WJpegComplex::ROT_0;\r
452         showPicture(VMediaList::MV_PREV,slideshow,true);\r
453         rt= 2;\r
454         break;\r
455       case Remote::FORWARD:\r
456         if (showtime > 1) showtime--;\r
457         updatePictureBanner(true);\r
458         break;\r
459       case Remote::DF_DOWN:\r
460       case Remote::DOWN:\r
461       case Remote::SKIPFORWARD:\r
462         rotate=WJpegComplex::ROT_0;\r
463         showPicture(VMediaList::MV_NEXT,slideshow,true);\r
464         rt= 2;\r
465         break;\r
466       case Remote::REVERSE:\r
467         if (showtime < 50 ) showtime++;\r
468         updatePictureBanner(true);\r
469         break;\r
470       case Remote::OK:\r
471       {\r
472         if (pictureBanner) {\r
473           destroyPictureBanner();\r
474           destroyInfo();\r
475           havePictureBanner=false;\r
476           }\r
477         else {\r
478           havePictureBanner=true;\r
479           showPictureBanner(pictureLoading);\r
480         }\r
481         rt= 2;\r
482       }\r
483       break;\r
484       case Remote::PLAY:\r
485       {\r
486         slideshow=true;\r
487         rotate=WJpegComplex::ROT_0;\r
488         showPicture(VMediaList::MV_NEXT,slideshow,true);\r
489         rt= 2;\r
490       }\r
491       break;\r
492       case Remote::PAUSE:\r
493         if (slideshow) {\r
494           stopSlideshow(true);\r
495           updatePictureBanner();\r
496         }\r
497         else {\r
498           slideshow=true;\r
499           rotate=WJpegComplex::ROT_0;\r
500           showPicture(VMediaList::MV_NEXT,slideshow,true);\r
501         }\r
502         rt= 2;\r
503         break;\r
504       case Remote::STOP:\r
505         stopSlideshow(true);\r
506         showtime=INITIAL_SHOWTIME;\r
507         updatePictureBanner();\r
508         rt= 2;\r
509         break;\r
510       case Remote::RED:\r
511         switch(rotate) {\r
512           case WJpegComplex::ROT_0:\r
513             rotate=WJpegComplex::ROT_90;\r
514             break;\r
515           case WJpegComplex::ROT_90:\r
516             rotate=WJpegComplex::ROT_180;\r
517             break;\r
518           case WJpegComplex::ROT_180:\r
519             rotate=WJpegComplex::ROT_270;\r
520             break;\r
521           case WJpegComplex::ROT_270:\r
522             rotate=WJpegComplex::ROT_0;\r
523             break;\r
524           }\r
525         showPicture(VMediaList::MV_NONE,slideshow,true);\r
526         rt=2;\r
527         break;\r
528       case Remote::GREEN:\r
529         if (info) destroyInfo();\r
530         else showPictureInfo();\r
531         rt=2;\r
532         break;\r
533       case Remote::BLUE:\r
534         switch (cropmode) {\r
535           case WJpegComplex::CROP:\r
536             cropmode=WJpegComplex::LETTER;\r
537             break;\r
538           case WJpegComplex::LETTER:\r
539             cropmode=WJpegComplex::CROPPERCENT;\r
540             break;\r
541           default:\r
542             cropmode=WJpegComplex::CROP;\r
543             break;\r
544         }\r
545         showPicture(VMediaList::MV_NONE,slideshow,true);\r
546         rt=2;\r
547         break;\r
548       case Remote::MENU: {\r
549         stopSlideshow(true);\r
550         destroyPictureBanner();\r
551         destroyInfo();\r
552         VColourTuner *ct=new VColourTuner();\r
553         BoxStack::getInstance()->add(ct);\r
554         ct->draw();\r
555         BoxStack::getInstance()->update(ct);\r
556         rt=2;\r
557        \r
558                          } break;\r
559       case Remote::BACK:\r
560       {\r
561         setPictureMode(false);\r
562         rt= 2;\r
563       }\r
564       break;\r
565       case Remote::YELLOW:\r
566       {\r
567         setAudioMode(true);\r
568       }\r
569     }\r
570     return rt;\r
571   } \r
572   else \r
573   {\r
574     int rt=1;\r
575     bool updateInfo=false;\r
576     //------------------------- command in mode AUDIO (i.e. audio is on top) ----------------\r
577     switch(command)\r
578     {\r
579       case Remote::YELLOW:\r
580         setAudioMode(false);\r
581         rt=2;\r
582         break;\r
583       case Remote::DF_UP:\r
584       case Remote::UP:\r
585         play(playall,false,VMediaList::MV_PREV);\r
586         rt= 2;\r
587         break;\r
588       case Remote::FORWARD:\r
589         if (! audioError) getPlayer()->fastForward();\r
590         updateInfo=true;\r
591         rt=2;\r
592         break;\r
593       case Remote::DF_DOWN:\r
594       case Remote::DOWN:\r
595         play(playall,false,VMediaList::MV_NEXT);\r
596         rt= 2;\r
597         break;\r
598       case Remote::SKIPFORWARD:\r
599         if (! audioError) getPlayer()->skipForward(10);\r
600         rt=2;\r
601         break;\r
602       case Remote::SKIPBACK:\r
603         if (! audioError) getPlayer()->skipBackward(10);\r
604         rt=2;\r
605         break;\r
606       case Remote::REVERSE:\r
607         rt=2;\r
608         break;\r
609       case Remote::ZERO:\r
610         if (! audioError) getPlayer()->jumpToPercent(0);\r
611         rt=2;\r
612         break;\r
613       case Remote::ONE:\r
614         if (! audioError) getPlayer()->jumpToPercent(10);\r
615         rt=2;\r
616         break;\r
617       case Remote::TWO:\r
618         if (! audioError) getPlayer()->jumpToPercent(20);\r
619         rt=2;\r
620         break;\r
621       case Remote::THREE:\r
622         if (! audioError) getPlayer()->jumpToPercent(30);\r
623         rt=2;\r
624         break;\r
625       case Remote::FOUR:\r
626         if (! audioError) getPlayer()->jumpToPercent(40);\r
627         rt=2;\r
628         break;\r
629       case Remote::FIVE:\r
630         if (! audioError) getPlayer()->jumpToPercent(50);\r
631         rt=2;\r
632         break;\r
633       case Remote::SIX:\r
634         if (! audioError) getPlayer()->jumpToPercent(60);\r
635         rt=2;\r
636         break;\r
637       case Remote::SEVEN:\r
638         if (! audioError) getPlayer()->jumpToPercent(70);\r
639         rt=2;\r
640         break;\r
641       case Remote::EIGHT:\r
642         if (! audioError) getPlayer()->jumpToPercent(80);\r
643         rt=2;\r
644         break;\r
645       case Remote::NINE:\r
646         if (! audioError) getPlayer()->jumpToPercent(90);\r
647         rt=2;\r
648         break;\r
649       case Remote::OK:\r
650       case Remote::GREEN:\r
651       {\r
652         if (info) {\r
653           destroyInfo();\r
654           retriggerAudioInfo=false;\r
655           }\r
656         else {\r
657           retriggerAudioInfo=true;\r
658           showAudioInfo();\r
659         }\r
660         if (getPlayer()->getState() == AudioPlayer::S_ERROR) {\r
661           if (playall) play(playall,false,VMediaList::MV_NEXT);\r
662         }\r
663         rt= 2;\r
664       }\r
665       break;\r
666       case Remote::PLAY:\r
667       {\r
668         if (! audioError) getPlayer()->unpause();\r
669         updateInfo=true;\r
670         if (getPlayer()->getState() != AudioPlayer::S_ERROR) ;\r
671         else if (playall) play(playall,false,VMediaList::MV_NEXT);\r
672         rt= 2;\r
673       }\r
674       break;\r
675       case Remote::PAUSE:\r
676         if (! audioError) getPlayer()->pause();\r
677         updateInfo=true;\r
678         rt= 2;\r
679         break;\r
680       case Remote::STOP:\r
681         getPlayer()->stop();\r
682         justPlaying=false;\r
683         updateInfo=true;\r
684         rt= 2;\r
685         break;\r
686       case Remote::BACK:\r
687       {\r
688         getPlayer()->stop();\r
689         playall=false;\r
690         retriggerAudioInfo=false;\r
691         justPlaying=false;\r
692         setAudioMode(false);\r
693         if (! pictureShowing) setPictureMode(false); //could have been delayed\r
694         rt= 2;\r
695       }\r
696       break;\r
697     }\r
698     if (audioEnabled && updateInfo) updateAudioInfo();\r
699     return rt;\r
700   }\r
701 }\r
702 \r
703 void VMediaView::processMessage(Message* m)\r
704 {\r
705   Log::getInstance()->log("VMediaView::processMessage", Log::DEBUG, "cmd=%lu,p=%lu", m->message,m->parameter);\r
706   if (m->message == Message::MOUSE_MOVE)\r
707   {\r
708     ;\r
709   }\r
710   else if (m->message == Message::MOUSE_LBDOWN)\r
711   {\r
712     \r
713     //check if press is outside this view! then simulate cancel\r
714     int x=(m->parameter>>16)-getScreenX();\r
715     int y=(m->parameter&0xFFFF)-getScreenY();\r
716     if (x<0 || y <0 || x>(int)getWidth() || y>(int)getHeight())\r
717     {\r
718       BoxStack::getInstance()->handleCommand(Remote::BACK); //simulate cancel press\r
719     }\r
720   }\r
721   else if (m->message = Message::PLAYER_EVENT) {\r
722     switch (m->parameter) {\r
723       case EVENT_SLIDESHOW:\r
724         if (! pictureEnabled) break; //old timer msg...\r
725         //if (! audioEnabled) {\r
726         if (true) {\r
727           if (slideshow) {\r
728             rotate=WJpegComplex::ROT_0;\r
729             showPicture(VMediaList::MV_NEXT,true,false);\r
730             startSlideshow();\r
731           }\r
732         }\r
733         break;\r
734       case EVENT_DRAWINGERROR:\r
735         drawingDone(true);\r
736         break;\r
737       case EVENT_DRAWINGDONE:\r
738         drawingDone(false);\r
739         break;\r
740       case EVENT_DIRECTORYDONE:\r
741         //just disable audio without (poetntially) hiding us\r
742         //this gives the list a chance to decide whether audio\r
743         //should be on top afterwards without showing the list\r
744         //immediately\r
745         setAudioMode(false,false);\r
746         parent->directoryDone();\r
747         if (! pictureShowing) setPictureMode(false);\r
748         if (! justPlaying) setAudioMode(false);\r
749         break;\r
750       case AudioPlayer::STREAM_ERR:\r
751       case AudioPlayer::STREAM_END:\r
752         if (playall) play(playall,false,VMediaList::MV_NEXT);\r
753         else {\r
754           setAudioMode(false);\r
755           justPlaying=false;\r
756         }\r
757         break;\r
758       case AudioPlayer::SHORT_UPDATE:\r
759                                 if (info && audioEnabled ) {\r
760                                         drawAudioClocks();\r
761                                         BoxStack::getInstance()->update(info,&clocksRegion);\r
762                                   BoxStack::getInstance()->update(info,&barRegion);\r
763                                         Timers::getInstance()->setTimerD(this, 4, 1);\r
764                                 }\r
765         break;\r
766       case AudioPlayer::NEW_SONG:\r
767         if (audioEnabled) updateAudioInfo();\r
768         break;\r
769       case AudioPlayer::CONNECTION_LOST:\r
770         if (audioEnabled) destroyInfo();\r
771         if (AudioPlayer *player=getPlayer(false)) {\r
772           player->shutdown();\r
773           player=NULL;\r
774         }\r
775         Command::getInstance()->connectionLost();\r
776         break;\r
777     }\r
778   }\r
779 }\r
780 \r
781 \r
782 VMediaView * VMediaView::createViewer(VMediaList * mparent) {\r
783    Log::getInstance()->log("VMediaView::createViewer", Log::DEBUG, "p=%p",\r
784         mparent);\r
785    VMediaView *vmn=new VMediaView(mparent);\r
786    BoxStack::getInstance()->add(vmn);\r
787    vmn->draw();\r
788    BoxStack::getInstance()->update(vmn);\r
789    return vmn;\r
790 }\r
791 \r
792 void VMediaView::startSlideshow() {\r
793    slideshow=true;\r
794    if (! pictureLoading) Timers::getInstance()->setTimerD(this,1,showtime);\r
795 }\r
796 \r
797 void VMediaView::stopSlideshow(bool hard) {\r
798    if (hard) slideshow=false;\r
799    Timers::getInstance()->cancelTimer(this,1);\r
800 }\r
801 \r
802 \r
803 void VMediaView::showPicture(ULONG move,bool bslideshow,bool activateBanner) {\r
804   pictureShowing=true;\r
805   setPictureMode(true);\r
806   stopSlideshow(true);\r
807 #ifdef DRAWING_THREAD\r
808   drawingThread->stop();\r
809 #endif\r
810   slideshow=bslideshow;\r
811   Media *newPicture=parent->getMedia(MEDIA_TYPE_PICTURE,move);\r
812   if ( ! newPicture) {\r
813     pictureShowing=false;\r
814     if (!audioEnabled) {\r
815       //within the event handler first directoryDone is called\r
816       //and afterwards everything is stopped if nothing new\r
817       sendCommandMsg(EVENT_DIRECTORYDONE);\r
818     }\r
819     slideshow=false;\r
820   }\r
821   else \r
822   {\r
823     pictureShowing=true;\r
824     if (currentPicture) {\r
825       delete currentPicture;\r
826       currentPicture=NULL;\r
827     }\r
828     currentPicture=newPicture;\r
829     loadPicture(currentPicture,activateBanner);\r
830   }\r
831 }\r
832 \r
833 //the real picture drawing method\r
834 //will start drawing on a new surface and will switch it wehn done\r
835 \r
836 int VMediaView::loadPicture(Media *md,bool activateBanner) {\r
837   pictureError=NULL;\r
838   if (! md) return 1;\r
839   if (! md->getURI()) {\r
840     pictureError=tr("No media found");\r
841     Log::getInstance()->log("VMediaView::load",Log::ERR,"no URI in media");\r
842     return 1;\r
843   }\r
844   Log::getInstance()->log("VMediaView::load", Log::DEBUG, "filename=%s,p=%p",\r
845         md->getURI()->getName(),this);\r
846   //do we have a pictureBanner?\r
847   havePictureBanner=pictureBanner!=NULL || activateBanner;\r
848   pictureLoading=true;\r
849 #ifdef DRAWING_THREAD\r
850   if (!audioEnabled && havePictureBanner ) showPictureBanner(true);\r
851   drawingThread->stop();\r
852 #else\r
853   showPictureBanner(true);\r
854 #endif\r
855   ireader->stop();\r
856   ULLONG size=0;\r
857   int rtok=reader->initRead(md->getURI(),&size,ctl.scaleAmount); //scaleAmount is the same for both...\r
858   if (rtok == 0) {\r
859      //now we can really draw\r
860      //get the surface for drawing\r
861      Surface * drawSurface=NULL;\r
862      WJpegComplex::JpegControl *drawCtl=NULL;\r
863      getDrawingParam(drawSurface,drawCtl);\r
864      drawCtl->error[0]=0;\r
865      drawCtl->rotation=rotate;\r
866      drawCtl->mode=cropmode;\r
867      drawCtl->compressedSize=size;\r
868 #ifdef DRAWING_THREAD\r
869      bool ok=drawingThread->start(drawCtl,drawSurface,reader,pictureBack);\r
870      if (! ok) {\r
871        Log::getInstance()->log("VMediaView::load", Log::ERR, "unable to start drawing thread");\r
872        pictureError=tr("JpegError");\r
873        pictureLoading=false;\r
874        destroyPictureBanner();\r
875        return 1;\r
876      }\r
877      return 0;\r
878 #else\r
879      //here we could hand this over to the drawing thread\r
880      bool ok=WJpegComplex::drawJpeg(drawCtl,drawSurface,reader,pictureBack);\r
881      drawingDone(!ok);\r
882      return ok?0:1;\r
883 #endif\r
884   }\r
885   pictureLoading=false;\r
886   return 1;\r
887 }\r
888 \r
889 void VMediaView::drawingDone(bool hasError) {\r
890   pictureLoading=false;\r
891   destroyPictureBanner(); //disable loading indication (or real banner)\r
892   if (! hasError) {\r
893     switchSurface();\r
894     Log::getInstance()->log("VMediaView::drawingDone", Log::DEBUG, "success: sfc now=%p",surface);\r
895     pictureError=NULL;\r
896     //only show the pictureBanner if it was there before\r
897     if (havePictureBanner && ! audioEnabled) showPictureBanner();\r
898     Log::getInstance()->log("VMediaView::load", Log::DEBUG, "success" );\r
899     updatePictureInfo(); //will only do somethng if pictureEnabled\r
900   }\r
901   else \r
902   {\r
903     pictureError=tr("JpegError");\r
904     if (pictureEnabled) {\r
905       draw();\r
906       destroyInfo();\r
907     }\r
908   }\r
909   MediaPlayer::getInstance()->closeMediaChannel(1);\r
910 #ifndef DRAWING_THREAD\r
911   if (audioEnabled) showAudioBanner();\r
912 #endif\r
913   if (slideshow) startSlideshow();\r
914   BoxStack::getInstance()->update(this);\r
915 }\r
916 \r
917 void VMediaView::showPictureBanner(bool loading) {\r
918   //we are in the main thread - so we can (and must) safely hard destroy/create the banner\r
919   Timers::getInstance()->cancelTimer(this,2);\r
920   if (! currentPicture) {\r
921     //hmm...\r
922     destroyPictureBanner(false);\r
923     return;\r
924     }\r
925   if (pictureBanner) destroyPictureBanner(false);\r
926   if (! pictureEnabled || ! bannerEnabled) return;\r
927   pictureBanner= new VPictureBanner(loading, slideshow);\r
928   pictureBanner->fillColour(infoBack);\r
929   if (! loading) {\r
930     int len=strlen(currentPicture->getFileName())+Media::TIMEBUFLEN+20;\r
931     char *buf=new char[len];\r
932     char tbuf[Media::TIMEBUFLEN];\r
933     SNPRINTF(buf,len,"%c%02ds%c %s %s " ,\r
934       slideshow?' ':'[',\r
935       showtime,\r
936       slideshow?' ':']',\r
937       currentPicture->getTimeString(tbuf),\r
938       currentPicture->getFileName()\r
939       );\r
940     pictureBanner->setText(buf);\r
941     delete [] buf;\r
942   }\r
943   else {\r
944     char *buf=new char[strlen(currentPicture->getDisplayName())+50];\r
945     SNPRINTF(buf,50,"%s %s",tr("Loading"), currentPicture->getDisplayName());\r
946     pictureBanner->setText(buf);\r
947     delete buf;\r
948   }\r
949   pictureBanner->draw();\r
950   if (! loading )   Timers::getInstance()->setTimerD(this,2,8);\r
951   BoxStack::getInstance()->add(pictureBanner);\r
952   BoxStack::getInstance()->update(pictureBanner);\r
953   }\r
954 \r
955 void VMediaView::destroyPictureBanner(bool fromTimer) {\r
956   if (pictureBanner) {\r
957     if (fromTimer) sendViewMsg(pictureBanner); \r
958     else BoxStack::getInstance()->remove(pictureBanner);\r
959     pictureBanner=NULL;\r
960     if (! fromTimer) Timers::getInstance()->cancelTimer(this,2);\r
961     }\r
962 }\r
963 void VMediaView::updatePictureBanner(bool loading) {\r
964   if (pictureBanner ) {\r
965     showPictureBanner(loading);\r
966     }\r
967 }\r
968 void VMediaView::timercall(int clientref) {\r
969    Log::getInstance()->log("VMediaView::timercall", Log::DEBUG, "id=%d",clientref);\r
970    switch(clientref)\r
971    {\r
972       case 4:\r
973         {\r
974           sendCommandMsg(AudioPlayer::SHORT_UPDATE);\r
975           break;\r
976         }\r
977       case 3:\r
978         {\r
979           Log::getInstance()->log("VMediaView::timercall", Log::DEBUG, "infoEnd");\r
980           destroyInfo(true);\r
981           if (audioEnabled) {\r
982             //we only did show the audio error info if audio is enabled\r
983             bool stillError=false;\r
984             if (AudioPlayer * player=getPlayer(false)) {\r
985               stillError=player->getState()==AudioPlayer::S_ERROR;\r
986             }\r
987             if (stillError) {\r
988               sendCommandMsg(AudioPlayer::STREAM_END);\r
989             }\r
990           }\r
991           break;\r
992         }\r
993       case 1:\r
994         if (! slideshow) return;\r
995         Log::getInstance()->log("VMediaView::timercall", Log::DEBUG, "slideshow");\r
996         sendCommandMsg(EVENT_SLIDESHOW);\r
997         break;\r
998       case 2:\r
999         Log::getInstance()->log("VMediaView::timercall", Log::DEBUG, "pictureBannerEnd");\r
1000         destroyPictureBanner(true);\r
1001         break;\r
1002     }\r
1003    \r
1004   }\r
1005 \r
1006 #define INFOBUF 2000\r
1007 void VMediaView::showPictureInfo(){\r
1008   if (! pictureEnabled || audioEnabled) return;\r
1009   if (info) destroyInfo();\r
1010   if (! currentPicture) return;\r
1011 \r
1012   info=new VInfo();\r
1013   info->setTitleText(currentPicture->getFileName());\r
1014   info->setDropThrough();\r
1015   info->setSize(500, 300);\r
1016   info->createBuffer();\r
1017   info->setBorderOn(1);\r
1018   info->setTitleBarOn(1);\r
1019 \r
1020   if (Video::getInstance()->getFormat() == Video::PAL)\r
1021         info->setPosition(100, 180);\r
1022   else\r
1023         info->setPosition(100, 150);\r
1024   char buf[INFOBUF];\r
1025   char tbuf[Media::TIMEBUFLEN];\r
1026   //modes should come from mediaoptions...\r
1027   const char *mode=NULL;\r
1028   switch (currentControl->mode) {\r
1029     case WJpegComplex::CROPPERCENT:\r
1030       mode="clipfactor";\r
1031       break;\r
1032     case WJpegComplex::LETTER:\r
1033       mode="letter";\r
1034       break;\r
1035     default:\r
1036       mode="clip";\r
1037       break;\r
1038   }\r
1039   const char *dirname=parent->getDirname(MEDIA_TYPE_PICTURE);\r
1040   int ldir=0;\r
1041   const char *prfx="";\r
1042   if (dirname) ldir=strlen(dirname);\r
1043   if (ldir > 35){\r
1044     dirname=dirname+ldir-35;\r
1045     prfx="...";\r
1046   }\r
1047   SNPRINTF(buf,INFOBUF,"%s= %s%s\n%s= %u x %u\n%s= %lu kBytes\n%s= %s\n%s= %u\n%s= %u%%\n%s= %s",\r
1048      tr("Directory"), prfx,dirname,\r
1049      tr("Format(px)"),currentControl->picw,currentControl->pich,\r
1050      tr("Filesize"),currentControl->compressedSize/1000,\r
1051      tr("Time"),currentPicture->getTimeString(tbuf),\r
1052      tr("Rotation"),90*currentControl->finalRotation,\r
1053      tr("Scale"),currentControl->scale,\r
1054      tr("Picture Mode"),mode );\r
1055   info->setMainText(buf);\r
1056   info->draw();\r
1057   BoxStack::getInstance()->add(info);\r
1058   BoxStack::getInstance()->update(info);\r
1059   Timers::getInstance()->setTimerD(this,3,8);\r
1060 }\r
1061 void VMediaView::updatePictureInfo(){\r
1062   if (info) {\r
1063     showPictureInfo();\r
1064     }\r
1065 }\r
1066 void VMediaView::destroyInfo(bool fromTimer){\r
1067   if (info) {\r
1068     if (! fromTimer) {\r
1069       Log::getInstance()->log("VMediaView",Log::DEBUG,"remove info %p",info);\r
1070       BoxStack::getInstance()->remove(info);\r
1071     }\r
1072     else {\r
1073       Log::getInstance()->log("VMediaView",Log::DEBUG,"trigger remove info %p",info);\r
1074       sendViewMsg(info);\r
1075     }\r
1076     info=NULL;\r
1077     }\r
1078   if (! fromTimer) Timers::getInstance()->cancelTimer(this,3);\r
1079   if (! fromTimer) Timers::getInstance()->cancelTimer(this,4);\r
1080 }\r
1081 \r
1082 void VMediaView::sendViewMsg(Boxx *v) {\r
1083   Message* m = new Message(); \r
1084   m->message = Message::CLOSE_ME;\r
1085   m->to = BoxStack::getInstance();\r
1086   m->from = v;\r
1087   m->parameter=(ULONG)v;\r
1088   Command::getInstance()->postMessageFromOuterSpace(m);\r
1089 }\r
1090 void VMediaView::sendCommandMsg(int command) {\r
1091   Message* m = new Message(); \r
1092   //we misuse PLAYER_EVENT here\r
1093   m->message = Message::PLAYER_EVENT;\r
1094   m->to = this;\r
1095   m->from = this;\r
1096   m->parameter= command;\r
1097   Command::getInstance()->postMessageFromOuterSpace(m);\r
1098 }\r
1099 \r
1100 void VMediaView::enableBanner(bool enable) {\r
1101   bannerEnabled=false;\r
1102   updatePictureBanner();\r
1103 }\r
1104 \r
1105 void VMediaView::getDrawingParam(Surface *&sfc,WJpegComplex::JpegControl *&c){\r
1106   if (secondSurface()) {\r
1107     //we currently display on sfc2\r
1108     sfc=sfc1;\r
1109     c=&ctl;\r
1110   }\r
1111   else {\r
1112     sfc=sfc2;\r
1113     c=&ctl2;\r
1114   }\r
1115 }\r
1116 void VMediaView::switchSurface(){\r
1117   if (secondSurface()) {\r
1118     //now we switch to sfc1\r
1119     surface=sfc1;\r
1120     currentControl=&ctl;\r
1121   }\r
1122   else {\r
1123     surface=sfc2;\r
1124     currentControl=&ctl2;\r
1125   }\r
1126 }\r
1127 \r
1128 AudioPlayer * VMediaView::getPlayer(bool createIfNeeded)\r
1129 {\r
1130   AudioPlayer* rt=AudioPlayer::getInstance(this,false);\r
1131   if (! createIfNeeded && rt == NULL) return NULL;\r
1132   if (rt == NULL) {\r
1133     rt=AudioPlayer::getInstance(this);\r
1134     rt->run();\r
1135   }\r
1136   return rt;\r
1137 }\r
1138 \r
1139 bool VMediaView::isAudioPlaying() {\r
1140   Log::getInstance()->log("VMediaView::isPlaying", Log::DEBUG, "rt=%s", justPlaying?"true":"false");\r
1141   return justPlaying;\r
1142 }\r
1143 \r
1144 \r
1145 \r
1146 \r
1147 \r
1148 \r
1149 int VMediaView::play(bool all,bool activate,ULONG move,bool showInfo) {\r
1150   int rt=0;\r
1151   if (getPlayer(false)) getPlayer(false)->stop();\r
1152   justPlaying=false;\r
1153   if (currentAudio) delete currentAudio;\r
1154   currentAudio=NULL;\r
1155   playall=all;\r
1156   currentAudio=parent->getMedia(MEDIA_TYPE_AUDIO,move);\r
1157   audioError=NULL;\r
1158   if ( ! currentAudio || ! currentAudio->getURI()) {\r
1159     Log::getInstance()->log("VMediaView::load", Log::ERR, "no URI in media");\r
1160     audioError=tr("no audio file");\r
1161     if (audioEnabled) sendCommandMsg(EVENT_DIRECTORYDONE);\r
1162     rt= -1;\r
1163   }\r
1164   else {\r
1165     Log::getInstance()->log("VMediaView::load", Log::DEBUG, "filename=%s,p=%p",\r
1166       currentAudio->getURI()->getName(),this);\r
1167     int wseq=getPlayer()->play(currentAudio->getURI());\r
1168     if (getPlayer()->waitForSequence(5,wseq)<0) {\r
1169        audioError=tr("unable to open audio file");\r
1170        rt= -1;\r
1171     }\r
1172     else {\r
1173       justPlaying=true;\r
1174       rt=0;\r
1175     }\r
1176     Log::getInstance()->log("VMediaView", Log::DEBUG, "player started for %s",currentAudio->getURI()->getName());\r
1177   }\r
1178   if (activate && ! audioEnabled){\r
1179     if (showInfo) retriggerAudioInfo=true;\r
1180     setAudioMode(true);\r
1181   }\r
1182   else {\r
1183     //avoid duplicate creation of banner and info\r
1184     showAudioBanner();\r
1185     showAudioInfo();\r
1186   }\r
1187   if (activate && (! currentPicture || ! pictureShowing)) draw();\r
1188   BoxStack::getInstance()->update(this);\r
1189   return rt;\r
1190 }\r
1191 \r
1192 void VMediaView::showAudioInfo() {\r
1193   if (! audioEnabled) return;\r
1194   Timers::getInstance()->cancelTimer(this,4);\r
1195   Timers::getInstance()->cancelTimer(this,3);\r
1196   if (info) destroyInfo();\r
1197   if (! retriggerAudioInfo) return;\r
1198   drawAudioInfo();\r
1199   bool playerError=getPlayer()->getState()==AudioPlayer::S_ERROR || audioError;\r
1200   if (! playerError) Timers::getInstance()->setTimerD(this,3,AUDIOBANNER_TIME);\r
1201   else Timers::getInstance()->setTimerD(this,3,AUDIOERROR_TIME);\r
1202         if (! playerError) Timers::getInstance()->setTimerD(this,4, 1);\r
1203   BoxStack::getInstance()->update(info);\r
1204   }\r
1205 \r
1206 void VMediaView::updateAudioInfo() {\r
1207   if (info) {\r
1208     showAudioInfo();\r
1209     }\r
1210 }\r
1211 \r
1212 void VMediaView::drawAudioInfo(){\r
1213   Log::getInstance()->log("VMediaView",Log::DEBUG, "draw banner for %p",info);\r
1214   const char *title=NULL;\r
1215   char *playerTitle=NULL;\r
1216   bool playerError=false;\r
1217   int numlines=0;\r
1218   int len=0;\r
1219   int num=0;\r
1220   const char *pl=tr("Playlist");\r
1221   const char *first=NULL;\r
1222   char *playerInfo=NULL;\r
1223   if (audioError) {\r
1224     if (getPlayer()->getState() == AudioPlayer::S_PLAY) audioError=NULL;\r
1225   }\r
1226   if (! currentAudio && ! audioError) audioError=tr("no audio file");\r
1227   if (audioError ) {\r
1228     title=tr("MediaError");\r
1229   }\r
1230   else {\r
1231     playerTitle=getPlayer()->getTitle();\r
1232     if (playerTitle) title=playerTitle;\r
1233     else title=currentAudio->getDisplayName();\r
1234     num=parent->getNumEntries(MEDIA_TYPE_AUDIO,currentAudio->index);\r
1235     playerError=getPlayer()->getState() == AudioPlayer::S_ERROR;\r
1236     //1more line for long dirs\r
1237     numlines=playall?5:4;\r
1238   }\r
1239   if (playerError) {\r
1240     numlines=3;\r
1241     first=tr("Unable to play audio file");\r
1242     len=strlen(first)+3;\r
1243   }\r
1244   else if (audioError) {\r
1245     numlines=3;\r
1246     first=audioError;\r
1247     len=strlen(first)+3;\r
1248   }\r
1249   else {\r
1250     playerInfo=getPlayer()->getID3Info();drawText(tr("Loading"),5,3,DrawStyle::LIGHTTEXT);\r
1251     len=strlen(currentAudio->getDisplayName())+strlen(pl)+30+strlen(parent->getDirname(MEDIA_TYPE_AUDIO))+Media::TIMEBUFLEN+110;\r
1252     if (playerInfo) {\r
1253       for (UINT i=0;i<strlen(playerInfo);i++) \r
1254         if (playerInfo[i] == '\n') numlines++;\r
1255       len+=strlen(playerInfo);\r
1256       first=playerInfo;\r
1257     }\r
1258     else {\r
1259       first="";\r
1260     }\r
1261   }\r
1262   destroyInfo();\r
1263   info=new VInfo();\r
1264   UINT height=numlines*30+60;\r
1265   UINT vheight=Video::getInstance()->getScreenHeight();\r
1266   UINT vwidth=Video::getInstance()->getScreenWidth();\r
1267   if (height > vheight-2*AUDIOBANNER_BOTTOM_MARGIN)\r
1268     height=vheight-2*AUDIOBANNER_BOTTOM_MARGIN;\r
1269   info->setSize(vwidth -2*AUDIOBANNER_X_MARGIN, height);\r
1270   info->createBuffer();\r
1271   if (Video::getInstance()->getFormat() == Video::PAL)\r
1272   {\r
1273     info->setPosition(AUDIOBANNER_X_MARGIN, vheight-height-AUDIOBANNER_BOTTOM_MARGIN);\r
1274   }\r
1275   else\r
1276   {\r
1277     info->setPosition(AUDIOBANNER_X_MARGIN, vheight-height-AUDIOBANNER_BOTTOM_MARGIN);\r
1278   }\r
1279 \r
1280   info->setTitleBarOn(0);\r
1281   info->setDropThrough();\r
1282   //from vvideorec \r
1283         //set the regions for the closcks and bars on banner\r
1284   barRegion.x = info->getWidth()-AUDIOBARLEN-20;\r
1285   barRegion.y = info->getHeight() - 30;   // FIXME, need to be - 1? and below?\r
1286   barRegion.w = info->getWidth()-AUDIOBARLEN+10;\r
1287   barRegion.h = 30;\r
1288 \r
1289   clocksRegion.x = 130;\r
1290   clocksRegion.y = barRegion.y + 3;\r
1291   clocksRegion.w = 190;\r
1292   clocksRegion.h = getFontHeight();\r
1293   Log::getInstance()->log("VMediaView",Log::DEBUG,"created AudioInfo %p",info);\r
1294   BoxStack::getInstance()->add(info);\r
1295   char *buf=new char [len];\r
1296   if (playerError || audioError) {\r
1297     SNPRINTF(buf,len,"%s",first);\r
1298   }\r
1299   else {\r
1300     char tbuf[Media::TIMEBUFLEN];\r
1301     if (playall) {\r
1302     SNPRINTF(buf,len,"%s\n"\r
1303         "%s:%s\n"\r
1304         "%s: %d/%d\n"\r
1305         "%s:%s\n"\r
1306         "%s:%s\n",\r
1307         first,\r
1308         tr("FileName"),currentAudio->getDisplayName(),\r
1309         pl,num,parent->getNumEntries(MEDIA_TYPE_AUDIO),\r
1310         tr("Directory"),parent->getDirname(MEDIA_TYPE_AUDIO),\r
1311         tr("Time"),currentAudio->getTimeString(tbuf));\r
1312     }\r
1313     else {\r
1314     SNPRINTF(buf,len,"%s\n"\r
1315         "%s:%s\n"\r
1316         "%s:%s\n"\r
1317         "%s:%s\n",\r
1318         first,\r
1319         tr("FileName"),currentAudio->getDisplayName(),\r
1320         tr("Directory"),parent->getDirname(MEDIA_TYPE_AUDIO),\r
1321         tr("Time"),currentAudio->getTimeString(tbuf));\r
1322     }\r
1323   }\r
1324   Log::getInstance()->log("VMediaView",Log::DEBUG,"info: (%d)%s",strlen(buf),buf);\r
1325   //now the real drawing functions\r
1326   info->draw();\r
1327   //title\r
1328   info->rectangle(0, 0, info->getWidth(), 30, DrawStyle::TITLEBARBACKGROUND);\r
1329   info->drawText(title, 5, 5, DrawStyle::LIGHTTEXT);\r
1330   info->drawPara(buf,5,32,DrawStyle::LIGHTTEXT);\r
1331   delete [] buf;\r
1332   if (! audioError) {\r
1333     WSymbol w;\r
1334     info->TEMPADD(&w);\r
1335     int x=10;\r
1336     int ybottom=info->getHeight();\r
1337     info->rectangle(0, ybottom - barRegion.h, info->getWidth(), barRegion.h, DrawStyle::TITLEBARBACKGROUND);\r
1338     bool drawSymbol=true;\r
1339     switch(getPlayer()->getState()) {\r
1340       case AudioPlayer::S_PAUSE:\r
1341         w.nextSymbol = WSymbol::PAUSE;\r
1342         break;\r
1343       case AudioPlayer::S_PLAY:\r
1344         w.nextSymbol = WSymbol::PLAY;\r
1345         break;\r
1346       case AudioPlayer::S_DONE:\r
1347         if (playall) \r
1348           w.nextSymbol = WSymbol::PLAY;\r
1349         else\r
1350           drawSymbol=false;\r
1351         break;\r
1352       case AudioPlayer::S_BACK:\r
1353         w.nextSymbol = WSymbol::FBWD ;\r
1354         break;\r
1355       case AudioPlayer::S_FF:\r
1356         w.nextSymbol = WSymbol::FFWD ;\r
1357         break;\r
1358       default:\r
1359         drawSymbol=false;\r
1360         break;\r
1361     }\r
1362     if (drawSymbol) {\r
1363       w.setPosition(x, ybottom-24);\r
1364       w.draw();\r
1365     }\r
1366     else {\r
1367       //stop symbol\r
1368       info->rectangle(x, ybottom - 23, 18, 16, DrawStyle::LIGHTTEXT);\r
1369     }\r
1370     x+=30;\r
1371     drawAudioClocks();\r
1372   }\r
1373   if (playerInfo) delete playerInfo;\r
1374   if (playerTitle) delete playerTitle;\r
1375 }\r
1376 \r
1377 void VMediaView::drawAudioClocks() {\r
1378         if (! info || ! audioEnabled) return;\r
1379         Log::getInstance()->log("VMediaView::drawAudioClocks", Log::DEBUG, "");\r
1380   //draw clocks and bar\r
1381   info->rectangle(clocksRegion, DrawStyle::TITLEBARBACKGROUND);\r
1382 \r
1383   time_t currentSec = (time_t)(getPlayer()->getCurrentTimes());\r
1384   time_t lengthSec=(time_t)(getPlayer()->getSonglen());\r
1385         struct tm cpos;\r
1386         struct tm slen;\r
1387 /*      gmtime_r(&currentSec,&cpos);\r
1388         gmtime_r(&lengthSec,&slen);*/\r
1389     cpos.tm_hour=currentSec/3600;\r
1390     cpos.tm_min=(currentSec-cpos.tm_hour*3600)/60;\r
1391     cpos.tm_sec=(currentSec-cpos.tm_hour*3600-cpos.tm_min*60);\r
1392     slen.tm_hour=lengthSec/3600;;\r
1393     slen.tm_min=(lengthSec-slen.tm_hour*3600)/60;\r
1394     slen.tm_sec=(lengthSec-slen.tm_hour*3600-slen.tm_min*60);\r
1395 \r
1396   char buffer[100];\r
1397   if (currentSec >= lengthSec)\r
1398   {\r
1399     SNPRINTF(buffer,99, "-:--:-- / -:--:--  %03dk",getPlayer()->getCurrentBitrate()/1000);\r
1400   }\r
1401   else\r
1402   {\r
1403     SNPRINTF(buffer, 99, "%01i:%02i:%02i / %01i:%02i:%02i  %03dk", cpos.tm_hour, cpos.tm_min, cpos.tm_sec, slen.tm_hour, slen.tm_min, slen.tm_sec,\r
1404                                 getPlayer()->getCurrentBitrate()/1000);\r
1405                 //Log::getInstance()->log("VMediaView", Log::DEBUG, buffer);\r
1406   }\r
1407 \r
1408   info->drawText(buffer, clocksRegion.x, clocksRegion.y, DrawStyle::LIGHTTEXT);\r
1409   \r
1410         // Draw progress bar\r
1411   int progBarXbase = 0;\r
1412         int barlen=250;\r
1413 \r
1414   info->rectangle(barRegion.x + progBarXbase, barRegion.y + 3, barlen+10, 24, DrawStyle::LIGHTTEXT);\r
1415   info->rectangle(barRegion.x + progBarXbase + 2, barRegion.y + 5, barlen+6, 20, barBlue);\r
1416 \r
1417   if (currentSec > lengthSec) currentSec=lengthSec;\r
1418   if (lengthSec == 0) return;\r
1419 \r
1420   // Draw yellow portion\r
1421   int progressWidth = (barlen+2) * currentSec / lengthSec;\r
1422   info->rectangle(barRegion.x + progBarXbase + 4, barRegion.y + 7, progressWidth, 16, DrawStyle::SELECTHIGHLIGHT);\r
1423 \r
1424 }\r
1425 \r
1426 void VMediaView::showAudioBanner() {\r
1427   destroyAudioBanner();\r
1428   if (! audioEnabled) return;\r
1429   audioBanner=new VInfo();\r
1430   Log::getInstance()->log("VMediaView",Log::DEBUG,"creating AudioBanner %p", audioBanner);\r
1431   Video *v=Video::getInstance();\r
1432   audioBanner->setSize(v->getScreenWidth()-100, 36);\r
1433   audioBanner->createBuffer();\r
1434   audioBanner->setPosition(50, v->getScreenHeight()-50);\r
1435   audioBanner->fillColour(audioBannerBack);\r
1436   audioBanner->setTitleBarOn(0);\r
1437   audioBanner->setDropThrough();\r
1438   if ( ! currentAudio || ! currentAudio->getDisplayName() || audioError) {\r
1439     audioBanner->drawText(tr("AudioPlayer - not playing"),5,3,DrawStyle::LIGHTTEXT);\r
1440   }\r
1441   else {\r
1442     char * buf=new char[strlen(currentAudio->getDisplayName())+50];\r
1443     SNPRINTF(buf,50,"%s %s",tr("AudioPlayer"),currentAudio->getDisplayName());\r
1444     audioBanner->drawText(buf,5,3,DrawStyle::LIGHTTEXT);\r
1445     delete buf;\r
1446   }\r
1447   BoxStack::getInstance()->add(audioBanner);\r
1448   BoxStack::getInstance()->update(audioBanner);\r
1449 }\r
1450 \r
1451 void VMediaView::destroyAudioBanner() {\r
1452   if (audioBanner) {\r
1453     Log::getInstance()->log("VMediaView",Log::DEBUG,"deleting AudioBanner %p",audioBanner);\r
1454     BoxStack::getInstance()->remove(audioBanner);\r
1455     audioBanner=NULL;\r
1456   }\r
1457 }\r