From: Marten Richter Date: Sun, 13 Jul 2014 12:21:29 +0000 (+0200) Subject: Add tvscraper support and other image handling stuff to vomp X-Git-Tag: 0-5-0~78 X-Git-Url: https://git.vomp.tv/gitweb/?a=commitdiff_plain;h=8c98eb914c52f958e7c0e382193f298d0206fa4d;p=vompclient.git Add tvscraper support and other image handling stuff to vomp --- diff --git a/boxx.cc b/boxx.cc index dd12024..2222086 100644 --- a/boxx.cc +++ b/boxx.cc @@ -26,6 +26,7 @@ #include "osd.h" #include "boxx.h" +#include "surfacevector.h" char Boxx::numBoxxes = 0; Boxx::Boxx() @@ -241,7 +242,7 @@ void Boxx::fillColour(const DrawStyle& colour) rectangle(0, 0, area.w, area.h, colour); } -void Boxx::drawPara(const char* text, int x, int y, const DrawStyle& colour) +int Boxx::drawPara(const char* text, int x, int y, const DrawStyle& colour,unsigned int skiplines) { char line[256]; int lineHeight = getFontHeight() + paraVSpace; @@ -252,6 +253,9 @@ void Boxx::drawPara(const char* text, int x, int y, const DrawStyle& colour) int linePos; int ypos; int printLine; + int leftlines=0; + + int drawLinePos=-skiplines; textPos = 0; ypos = y; @@ -308,15 +312,22 @@ void Boxx::drawPara(const char* text, int x, int y, const DrawStyle& colour) if (printLine || (linePos > 1)) // if some text was put in line { - drawText(line, x, ypos, colour); - ypos += lineHeight; - if (ypos > (int)(area.h - lineHeight)) break; + if (ypos <= (int)(area.h - lineHeight + paraVSpace)) { + if (drawLinePos >= 0) { + drawText(line, x, ypos, colour); + ypos += lineHeight; + } + } else { + leftlines++; + } + drawLinePos++; } else { break; } } + return leftlines; } void Boxx::rectangle(Region& region, const DrawStyle& colour) @@ -411,6 +422,27 @@ void Boxx::drawMonoBitmap(UCHAR*base, int dx, int dy, unsigned int height,unsign else if (surface) surface->drawMonoBitmap(base, dx,dy, height, width, nextColour); } +void Boxx::drawTVMedia(TVMediaInfo & tvmedia,float x, float y, float width, float height, Corner corner) +{ + if (parent) parent->drawTVMedia(tvmedia,area.x + x,area.y + y,width, height, corner); + else if (surface) { + SurfaceVector * surfacevector=dynamic_cast(surface); + if (surfacevector) surfacevector->drawTVMedia(tvmedia,x, y,width, height, corner); + else surface->fillblt(x, y, width, height, DrawStyle::RED); // Signal that something went wrong + } + +} + +void Boxx::drawClippingRectangle(float x, float y, float w, float h) +{ + if (parent) parent->drawClippingRectangle(area.x + x, area.y + y, w, h); + else if (surface) { + SurfaceVector * surfacevector=dynamic_cast(surface); + if (surfacevector) surfacevector->drawClippingRectangle(x, y, w, h); + + } +} + int Boxx::getFontHeight() { if (parent) return parent->getFontHeight(); diff --git a/boxx.h b/boxx.h index a90a070..1b76866 100644 --- a/boxx.h +++ b/boxx.h @@ -32,6 +32,8 @@ using namespace std; #include "surface.h" +#include "tvmedia.h" +#include "osdvector.h" class Bitmap; @@ -91,7 +93,7 @@ class Boxx // Drawing functions level 1 void fillColour(const DrawStyle & colour); - void drawPara(const char* text, int x, int y, const DrawStyle& colour); + int drawPara(const char* text, int x, int y, const DrawStyle& colour, unsigned int skiplines=0); // Drawing functions level 0 void rectangle(UINT x, UINT y, UINT w, UINT h, const DrawStyle& colour); @@ -106,6 +108,8 @@ class Boxx void drawBitmap(UINT x, UINT y, const Bitmap& bm, const DisplayRegion & region); //Now deprecated // void drawPixelAlpha(UINT x, UINT y, const Colour& colour,bool fastdraw=false); + void drawTVMedia(TVMediaInfo & tvmedia,float x, float y, float width, float height, Corner corner=TopLeft); + void drawClippingRectangle(float x, float y, float w, float h); int getFontHeight(); void drawJpeg(const char *fileName,int x, int y,int *width, int *height); diff --git a/command.cc b/command.cc index 8288d2f..b942f2c 100644 --- a/command.cc +++ b/command.cc @@ -445,6 +445,18 @@ void Command::processMessage(Message* m) break; } + case Message::PICTURES_ARRIVED: + { + Log::getInstance()->log("Command", Log::DEBUG, "TVMedia Pictures arrived"); + OsdVector *osdv=dynamic_cast(Osd::getInstance()); + if (osdv) { + osdv->processReceivedPictures(); + /* if (osdv->processReceivedPictures()) { + Log::getInstance()->log("Command", Log::DEBUG, "TVMedia Boxstack update triggered"); + boxstack->update(NULL,NULL); + }*/ + } + } break; } } else @@ -595,6 +607,7 @@ void Command::doPowerOff() void Command::doFromTheTop(bool which) { + if (isStandby) return; if (which) { if (connLost) diff --git a/eventdispatcher.cc b/eventdispatcher.cc index eba132a..dd1692b 100644 --- a/eventdispatcher.cc +++ b/eventdispatcher.cc @@ -60,8 +60,9 @@ bool EventDispatcher::edFindAndCall(void* userTag) } edr->callinprogress = true; - edUnlock(); - bool edrType = edr->call(userTag); + edUnlock(); + bool edr_delete=false; + bool edrType = edr->call(userTag,edr_delete); edLock(); edr->callinprogress = false; @@ -97,6 +98,7 @@ bool EventDispatcher::edFindAndCall(void* userTag) #else SetEvent(edr->cond); #endif + if (edr_delete) delete edr; } edUnlock(); diff --git a/eventdispatcher.h b/eventdispatcher.h index 3b0a5ee..500ec59 100644 --- a/eventdispatcher.h +++ b/eventdispatcher.h @@ -44,7 +44,7 @@ class EDReceiver //(implementation in eventdispatcher.cc) virtual ~EDReceiver(); protected: - virtual bool call(void* userTag)=0; // Implementor must override this and do the actual call + virtual bool call(void* userTag, bool & deleteme)=0; // Implementor must override this and do the actual call // return true to have EventDispatcher remove receiver from list after call bool nomorecalls; bool callinprogress; diff --git a/message.h b/message.h index b53018a..1494129 100644 --- a/message.h +++ b/message.h @@ -77,6 +77,7 @@ class Message const static ULONG TELETEXTUPDATEFIRSTLINE = 33; const static ULONG SUBTITLE_CHANGE_CHANNEL = 34; const static ULONG MOUSE_ANDROID_SCROLL = 35; + const static ULONG PICTURES_ARRIVED = 36; }; #endif diff --git a/movieinfo.cc b/movieinfo.cc new file mode 100644 index 0000000..2513c18 --- /dev/null +++ b/movieinfo.cc @@ -0,0 +1,46 @@ +/* + Copyright 2014 Marten Richter + + This file is part of VOMP. + + VOMP is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + VOMP is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with VOMP; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include "movieinfo.h" + +MovieInfo::MovieInfo() +{ + id=0; + title=""; + originalTitle=""; + tagline=""; + overview=""; + adult=0; + collectionName=""; + + budget=0; + revenue=0; + genres=""; + homepage=""; + releaseDate=""; + runtime=0; + popularity=0.f; + voteAverage=0.f; + + + +} + + diff --git a/movieinfo.h b/movieinfo.h new file mode 100644 index 0000000..31c3358 --- /dev/null +++ b/movieinfo.h @@ -0,0 +1,56 @@ +/* + Copyright 2014 Marten Richter + + This file is part of VOMP. + + VOMP is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + VOMP is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with VOMP; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef MOVIEINFO_H +#define MOVIEINFO_H + +#include "tvmedia.h" + +class MovieInfo { +public: + MovieInfo(); + + int id; + + std::string title; + std::string originalTitle; + std::string tagline; + std::string overview; + UCHAR adult; + std::string collectionName; + + int budget; + int revenue; + std::string genres; + std::string homepage; + std::string releaseDate; + int runtime; + float popularity; + float voteAverage; + + TVMedia poster; + TVMedia fanart; + TVMedia collectionPoster; + TVMedia collectionFanart; + Actors actors; +}; + + +#endif diff --git a/objects.mk b/objects.mk index 5ecff89..e27f749 100644 --- a/objects.mk +++ b/objects.mk @@ -24,5 +24,7 @@ OBJECTS1 = command.o tcp.o dsock.o thread.o timers.o i18n.o \ imagereader.o mediaoptions.o mediaplayer.o \ serialize.o localmediafile.o playermedia.o \ demuxermedia.o tfeed.o vteletextview.o teletextdecodervbiebu.o \ - teletxt/txtfont.o mediafile.o + teletxt/txtfont.o mediafile.o movieinfo.o seriesinfo.o wmovieview.o wseriesview.o tvmedia.o \ + wpictureview.o + diff --git a/osd.h b/osd.h index 5b96e68..0f87900 100644 --- a/osd.h +++ b/osd.h @@ -49,6 +49,8 @@ class Osd virtual int getFontNames(const char *** names,const char *** names_keys){ return 0;}; virtual void setFont(const char * fontname){}; + virtual float getPixelAspect() {return 1.f;}; + protected: static Osd* instance; int initted; diff --git a/osdopenvg.cc b/osdopenvg.cc index d11c0d9..207063a 100644 --- a/osdopenvg.cc +++ b/osdopenvg.cc @@ -304,6 +304,12 @@ int OsdOpenVG::init(void* device) return 1; } +void OsdOpenVG::getScreenSize(int &width, int &height) +{ + width=BACKBUFFER_WIDTH; + height=BACKBUFFER_HEIGHT; +} + void OsdOpenVG::initPaths() { @@ -798,6 +804,8 @@ void OsdOpenVG::drawSetTrans(SurfaceCommands & sc) vgLoadIdentity(); vgScale(((float)BACKBUFFER_WIDTH)/720.f, -((float)BACKBUFFER_HEIGHT)/576.f); vgTranslate(0.f+sc.x,-576.f+sc.y); + clip_shift_x=sc.x; + clip_shift_y=sc.y; @@ -829,15 +837,14 @@ void OsdOpenVG::executeDrawCommand(SVGCommand & command) case DrawImage: { vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE); vgGetMatrix(save_matrix); - vgTranslate(command.x,command.y); - - + VGfloat imagewidth=vgGetParameteri((VGImage) command.target.image, VG_IMAGE_WIDTH); + VGfloat imageheight=vgGetParameteri((VGImage) command.target.image, VG_IMAGE_HEIGHT); //vgScale(command.w,command.h); - VGfloat imagewidth=vgGetParameteri((VGImage) command.target.image, VG_IMAGE_WIDTH); - VGfloat imageheight=vgGetParameteri((VGImage) command.target.image, VG_IMAGE_HEIGHT); + if (command.reference) { //special behaviout for bw images they act as a mask on the current paint + vgTranslate(command.x,command.y); vgSetPaint((VGPaint) command.reference,VG_FILL_PATH); vgSetPaint((VGPaint) command.reference,VG_STROKE_PATH); vgSeti(VG_IMAGE_MODE,VG_DRAW_IMAGE_STENCIL); @@ -851,6 +858,33 @@ void OsdOpenVG::executeDrawCommand(SVGCommand & command) //vgScale(720.f/((float)BACKBUFFER_WIDTH), 576.f/((float)BACKBUFFER_HEIGHT)); float scalex=command.w/imagewidth; float scaley=command.h/imageheight; + if (scalex==0.f && scaley==0.f) { + scalex=aspect_correction; + scaley=1.f; + } else if (scalex==0.f) { + scalex=scaley*aspect_correction; + } else if (scaley==0.f) { + scaley=scalex/aspect_correction; + } + float tx=command.x; + float ty=command.y; + + if (command.corner == BottomRight || command.corner == BottomLeft || command.corner == BottomMiddle) + { + ty-=imageheight * scaley; + } + + if (command.corner == BottomRight || command.corner == TopRight) + { + tx-=imagewidth * scalex; + } + + if (command.corner == BottomMiddle || command.corner == TopMiddle) + { + tx-=imagewidth * scalex *0.5f; + } + + vgTranslate(tx,ty); //vgScale(command.w/imagewidth,command.h/imageheight); vgScale(scalex,scaley); vgSeti(VG_IMAGE_MODE,VG_DRAW_IMAGE_NORMAL); @@ -950,6 +984,17 @@ void OsdOpenVG::executeDrawCommand(SVGCommand & command) vgSeti(VG_BLEND_MODE, VG_BLEND_SRC); }break; + case DrawClipping: { + VGint coords[4]={0,0,0,0}; + coords[0]= ((command.x+clip_shift_x)*((float)BACKBUFFER_WIDTH)/720.f); + coords[1]= ((576.f-command.y-clip_shift_y-command.h)*((float)BACKBUFFER_HEIGHT)/576.f); + coords[2]= ((command.w-1.f)*((float)BACKBUFFER_WIDTH)/720.f); + coords[3]= ((command.h-1.f)*((float)BACKBUFFER_HEIGHT)/576.f); + vgSetiv(VG_SCISSOR_RECTS, 4,coords); + if (command.w==0.f && command.h==0.f) + vgSeti(VG_SCISSORING,VG_FALSE); + else vgSeti(VG_SCISSORING,VG_TRUE); + } break; } } @@ -995,8 +1040,7 @@ unsigned int OsdOpenVG::handleTask(OpenVGCommand& command) } break; case OVGcreateMonoBitmap: { VGImage handle=vgCreateImage(VG_A_1,command.param1, command.param2, - VG_IMAGE_QUALITY_NONANTIALIASED| - VG_IMAGE_QUALITY_FASTER|VG_IMAGE_QUALITY_BETTER); + VG_IMAGE_QUALITY_FASTER); //Log::getInstance()->log("OSD", Log::DEBUG, "Draw create mono %d %d %x %d",command.param1,command.param2,vgGetError(),handle); unsigned int buffer_len=(command.param1*command.param2)>>3; unsigned char * buffer=(unsigned char*)malloc(buffer_len); @@ -1025,12 +1069,11 @@ unsigned int OsdOpenVG::handleTask(OpenVGCommand& command) handle=vgCreateImage(VG_sXBGR_8888,imagefile->columns(),imagefile->rows(), - VG_IMAGE_QUALITY_NONANTIALIASED| - VG_IMAGE_QUALITY_FASTER|VG_IMAGE_QUALITY_BETTER); - // Log::getInstance()->log("OSD", Log::DEBUG, "Draw create image details %d %d %x mark1",imagefile->columns(),imagefile->rows(),*(unsigned int*)imageblob.data()); + VG_IMAGE_QUALITY_BETTER); + //Log::getInstance()->log("OSD", Log::DEBUG, "Draw create image details %d %d %x mark1",imagefile->columns(),imagefile->rows(),(unsigned int*)imageblob.data()); vgImageSubData(handle,imageblob.data(),imagefile->columns()*4, VG_sXBGR_8888,0,0,imagefile->columns(),imagefile->rows()); - // Log::getInstance()->log("OSD", Log::DEBUG, "Draw create image details %d %d %x mark2",imagefile->columns(),imagefile->rows(),*(unsigned int*)imageblob.data()); + //Log::getInstance()->log("OSD", Log::DEBUG, "Draw create image details %d %d %x mark2",imagefile->columns(),imagefile->rows(),(unsigned int*)imageblob.data()); delete imagefile; }catch( Exception &error_ ) { @@ -1248,6 +1291,30 @@ ImageIndex OsdOpenVG::createJpeg(const char* fileName, int *width,int *height) return putOpenVGCommand(comm,true); } +ImageIndex OsdOpenVG::createPicture(unsigned char *data, unsigned int length) +{ + Image* magicimage=NULL; + bool mem=false; + struct OpenVGCommand comm; + comm.task=OVGcreateImageFile; + + try{ + // Now figure out, if it is a special case + //Log::getInstance()->log("OSD", Log::DEBUG, "createPicture"); + magicimage=new Image(Blob(data,length)); // fix me this is an unnecessary memcpy + free(data); + }catch( Exception &error_ ) + { + Log::getInstance()->log("OSD", Log::DEBUG, "Libmagick: %s",error_.what()); + + return 0; + } + comm.data=magicimage; + return putOpenVGCommand(comm,true); +} + + + ImageIndex OsdOpenVG::createMonoBitmap(void *base,int width,int height) { struct OpenVGCommand comm; diff --git a/osdopenvg.h b/osdopenvg.h index baf6c0c..051e173 100644 --- a/osdopenvg.h +++ b/osdopenvg.h @@ -90,6 +90,8 @@ class OsdOpenVG : public OsdVector, public Thread_TYPE virtual void setFont(const char * fontname); + virtual float getPixelAspect() {return aspect_correction;}; + protected: /*osd vector implementation*/ @@ -97,6 +99,7 @@ protected: ImageIndex createJpeg(const char* fileName, int *width,int *height); ImageIndex createMonoBitmap(void *base,int width,int height); ImageIndex createImagePalette(int width,int height,const unsigned char *image_data,const unsigned int*palette_data); + ImageIndex createPicture(unsigned char *data, unsigned int length); void destroyStyleRef(unsigned int index); unsigned int createStyleRef(const DrawStyle &c); unsigned int createColorRef(const Colour &c); @@ -109,6 +112,7 @@ protected: VGPath std_paths[Point+1]; long long lastrendertime; void InternalRendering(); + void getScreenSize(int &width, int &height); @@ -136,6 +140,9 @@ protected: vector fontnames_keys; char * cur_fontname; + int clip_shift_x; + int clip_shift_y; + unsigned int loadTTchar(cTeletextChar c); map tt_font_chars; diff --git a/osdvector.cc b/osdvector.cc index 457cd80..8012ff6 100644 --- a/osdvector.cc +++ b/osdvector.cc @@ -20,10 +20,15 @@ #include "osdvector.h" #include "surfacevector.h" +#include "vdr.h" +#include "vdrresponsepacket.h" +#include "command.h" +#include "message.h" OsdVector::OsdVector() { setlocale(LC_CTYPE,"C.UTF-8"); + picture_update=true; } OsdVector::~OsdVector() @@ -108,6 +113,8 @@ void OsdVector::drawSurfaces() } itty1++; } + int swidth,sheight; + getScreenSize(swidth,sheight); //Now go through all surfaces and draw them list::iterator curdraw=todraw.begin(); while (curdraw!=todraw.end()) { @@ -115,7 +122,21 @@ void OsdVector::drawSurfaces() list::iterator commands=(*(*curdraw)).commands.begin(); list::iterator end=(*(*curdraw)).commands.end(); while (commands!=end) { - executeDrawCommand(*commands); + // update any images loaded in the mean time + if ((*commands).instr==DrawImageLoading) { + LoadIndex loadindex=(*commands).target.loadindex; + if (tvmedias_loaded.find(loadindex)!=tvmedias_loaded.end()) { + (*commands).instr=DrawImage; + (*commands).target.image=tvmedias_loaded[loadindex];; + incImageRef((*commands).target.image); + removeLoadIndexRef(loadindex); + } + + } + // Now check if the command is on screen! + if (!(*commands).Outside(0,0,swidth,sheight)) { + executeDrawCommand(*commands); + } commands++; } curdraw++; @@ -124,7 +145,6 @@ void OsdVector::drawSurfaces() surfaces_mutex.Unlock(); } - void OsdVector::updateOrAddSurface(const SurfaceVector *surf,float x,float y,float height,float width, list& commands) { @@ -149,6 +169,25 @@ void OsdVector::updateOrAddSurface(const SurfaceVector *surf,float x,float y,flo new_sc.h=height; itty=scommands.insert(itty,new_sc); } + // update any images loaded in the mean time + list::iterator ilitty=commands.begin(); + + while (ilitty!=commands.end()) + { + if ((*ilitty).instr==DrawImageLoading) { + LoadIndex loadindex=(*ilitty).target.loadindex; + if (tvmedias_loaded.find(loadindex)!=tvmedias_loaded.end()) { + + (*ilitty).instr=DrawImage; + (*ilitty).target.image=tvmedias_loaded[loadindex]; + incImageRef((*ilitty).target.image); + removeLoadIndexRef(loadindex); + } + } + ilitty++; + } + + // then clear and copy (*itty).commands.clear(); (*itty).commands=commands; @@ -159,6 +198,8 @@ void OsdVector::updateOrAddSurface(const SurfaceVector *surf,float x,float y,flo incStyleRef((*sitty).getRef()); ImageIndex ii=(*sitty).getImageIndex(); if (ii) incImageRef(ii); + LoadIndex li=(*sitty).getLoadIndex(); + if (li) incLoadIndexRef(li); sitty++; } cleanupOrphanedRefs(); @@ -192,6 +233,8 @@ void OsdVector::dereferenceSVGCommand(list& commands ) removeStyleRef((*sitty).getRef()); ImageIndex ii = (*sitty).getImageIndex(); if (ii) removeImageRef(ii); + LoadIndex li=(*sitty).getLoadIndex(); + if (li) removeLoadIndexRef(li); sitty++; } } @@ -204,10 +247,13 @@ void OsdVector::referenceSVGCommand(list& commands ) incStyleRef((*sitty).getRef()); ImageIndex ii=(*sitty).getImageIndex(); if (ii) incImageRef(ii); + LoadIndex li=(*sitty).getLoadIndex(); + if (li) incLoadIndexRef(li); sitty++; } } + void OsdVector::incImageRef(ImageIndex index) { if (images_ref.find(index)==images_ref.end()) { @@ -222,6 +268,39 @@ void OsdVector::removeImageRef(const ImageIndex ref) images_ref[ref]--; } +unsigned int OsdVector::getLoadIndexRef(LoadIndex index) +{ + if (loadindex_ref.find(index)==loadindex_ref.end()) { + return -1; + } else { + return loadindex_ref[index]; + } +} + +void OsdVector::incLoadIndexRef(LoadIndex index) +{ + if (loadindex_ref.find(index)==loadindex_ref.end()) { + loadindex_ref[index]=1; + } else { + loadindex_ref[index]++; + } +} + +void OsdVector::removeLoadIndexRef(const LoadIndex ref) +{ + loadindex_ref[ref]--; + if (loadindex_ref[ref]==0) { + //now check, if it is already loaded + map::iterator itty=tvmedias_loaded.find(ref); + if ( itty != tvmedias_loaded.end()) { + removeImageRef((*itty).second); // remove lock + } + tvmedias_loaded.erase(ref); + tvmedias_load.erase(tvmedias_load_inv[ref]); + tvmedias_load_inv.erase(ref); + } +} + void OsdVector::cleanupOrphanedRefs() { // Do some garbage collection @@ -249,6 +328,20 @@ void OsdVector::cleanupOrphanedRefs() } else ++jitty; } + map::iterator titty=tvmedias.begin(); + while (titty!=tvmedias.end()) { + map::iterator curitty=images_ref.find((*titty).second); + int count=(*curitty).second; + if (count==0) { + + Log::getInstance()->log("OsdVector", Log::DEBUG, "TVMedia destroy Picture"); + ImageIndex ref=(*curitty).first; + tvmedias.erase(titty++); + images_ref.erase(curitty++); + destroyImageRef(ref); + } else ++titty; + } + map,unsigned int>::iterator sitty=styles.begin(); while (sitty!=styles.end()) { @@ -333,6 +426,68 @@ unsigned int OsdVector::getStyleRef(unsigned int index) } } +LoadIndex OsdVector::getTVMediaRef(TVMediaInfo& tvmedia, ImageIndex& image) +{ + ImageIndex image_handle=0; + LoadIndex loadindex=0; + if (tvmedias.find(tvmedia)==tvmedias.end()) + { + loadindex=loadTVMedia(tvmedia); + } else { + image_handle=tvmedias[tvmedia]; + if (images_ref.find(image_handle)==images_ref.end()) { + //invalid handle recreate + loadindex=loadTVMedia(tvmedia); + image_handle=0; + } else { + incImageRef(image_handle); + } + } + /*tvmedias[tvmedia]=createTVMedia(tvmedia,width,height); + incImageRef(image_handle);*/ + image=image_handle; + return loadindex; +} + +LoadIndex OsdVector::loadTVMedia(TVMediaInfo& tvmedia) +{ + LoadIndex index=0; + if (tvmedias_load.find(tvmedia)==tvmedias_load.end()) + { + index=VDR::getInstance()->loadTVMedia(tvmedia); + tvmedias_load[tvmedia]=index; + tvmedias_load_inv[index]=tvmedia; + } else { + index=tvmedias_load[tvmedia]; + } + + incLoadIndexRef(index); + + return index; +} + +void OsdVector::setTVMedia(LoadIndex index, unsigned char * buffer, unsigned int length) +{ + //Beware for thread safety + ImageIndex image_index=0; + + TVMediaInfo tvmedia=tvmedias_load_inv[index]; + Log::getInstance()->log("OsdVector", Log::DEBUG, "TVMedia Picture for request id %d arrived",index); + if (buffer) { + if (getLoadIndexRef(index)<1) { + // we do not want the picture anymore . Really... + } else { + image_index=tvmedias[tvmedia]=createPicture(buffer,length); + tvmedias_loaded[index]=image_index; + incImageRef(image_index); // hold one index until all loadings refs are gone; + } + } + + +} + + + ImageIndex OsdVector::getJpegRef(const char* fileName, int *width,int *height) { ImageIndex image_handle=0; @@ -376,3 +531,56 @@ ImageIndex OsdVector::getImagePalette(int width,int height,const unsigned char incImageRef(image_handle); return image_handle; } + +void OsdVector::receivePicture(VDR_ResponsePacket *vresp) +{ + pict_lock_incoming.Lock(); + pict_incoming.push(vresp); + pict_lock_incoming.Unlock(); + //Log::getInstance()->log("OsdVector", Log::DEBUG, "TVMedia Pictures arrived"); + if (picture_update) { + Message* m = new Message(); + // This is incoming from VDR, we do not want to block gui so send a message to ourself to switch to gui thread + m->message=Message::PICTURES_ARRIVED; + m->from=this; + m->to=Command::getInstance(); + picture_update=false; + Command::getInstance()->postMessageFromOuterSpace(m); // inform command about new picture + } +} + +bool OsdVector::processReceivedPictures() +{ + bool ret=false; + pict_lock_incoming.Lock(); + int i=0; + long long time1 = getTimeMS(); + long long cur_time =time1; + while (pict_incoming.size() && (time1-cur_time)<100) { + VDR_ResponsePacket *vresp=pict_incoming.front(); + pict_incoming.pop(); + pict_lock_incoming.Unlock(); + if (vresp->getFlag() != 2) { + setTVMedia(vresp->getStreamID(), vresp->getUserData(), vresp->getUserDataLength()); + ret=true; + } + else setTVMedia(vresp->getStreamID(), NULL, 0); + delete vresp; + cur_time = getTimeMS(); + pict_lock_incoming.Lock(); + } + if (pict_incoming.size()==0) picture_update=true; + pict_lock_incoming.Unlock(); + + + if (!picture_update) { + Message* m = new Message(); + // We have remaing pictures! send a message to ourself to switch to gui thread + m->message=Message::PICTURES_ARRIVED; + m->from=this; + m->to=Command::getInstance(); + picture_update=false; + Command::getInstance()->postMessageNoLock(m); // inform command about new picture + } + return ret; +} diff --git a/osdvector.h b/osdvector.h index b9474f1..6221ae5 100644 --- a/osdvector.h +++ b/osdvector.h @@ -25,15 +25,21 @@ #include "colour.h" #include #include +#include #include +#include "tvmedia.h" +#include "vdr.h" #include "teletextdecodervbiebu.h" enum SVGCommandInstr { + DrawNoop, DrawPath, DrawGlyph, DrawImage, - DrawTTchar + DrawTTchar, + DrawClipping, + DrawImageLoading }; enum PathIndex { HorzLine, @@ -42,50 +48,108 @@ enum PathIndex { Point }; +enum Corner{ + TopLeft, + TopRight, + BottomLeft, + BottomRight, + TopMiddle, + BottomMiddle +}; + typedef unsigned int ImageIndex; +typedef unsigned int LoadIndex; class SVGCommand { public: - SVGCommand(float ix, float iy,float iw,float ih,PathIndex path,unsigned int ref) + SVGCommand() + { + instr=DrawNoop; + x=y=w=h=reference=0; + }; + + static SVGCommand PaintPath(float ix, float iy,float iw,float ih,PathIndex path,unsigned int ref) + { + SVGCommand nc; + nc.instr=DrawPath; + nc.x=ix; + nc.y=iy; + nc.w=iw; + nc.h=ih; + nc.target.path_index=path; + nc.reference=ref; + return nc; + }; + + static SVGCommand PaintImageLoading(LoadIndex load_in,float ix, float iy,float iw,float ih,unsigned int ref, Corner corner=TopLeft) + { + SVGCommand nc; + nc.instr=DrawImageLoading; + nc.x=ix; + nc.y=iy; + nc.w=iw; + nc.h=ih; + nc.target.loadindex=load_in; + nc.reference=ref; + nc.corner=corner; + return nc; + }; + + static SVGCommand PaintImage(float ix, float iy,float iw,float ih,ImageIndex image_in,unsigned int ref, Corner corner=TopLeft) { - instr=DrawPath; - x=ix; - y=iy; - w=iw; - h=ih; - target.path_index=path; - reference=ref; + SVGCommand nc; + nc.instr=DrawImage; + nc.x=ix; + nc.y=iy; + nc.w=iw; + nc.h=ih; + nc.target.image=image_in; + nc.reference=ref; + nc.corner=corner; + return nc; }; - SVGCommand(float ix, float iy,float iw,float ih,ImageIndex image_in,unsigned int ref) + + + + static SVGCommand PaintTTchar(float ix, float iy,float iw,float ih,unsigned int ttchar_in) { - instr=DrawImage; - x=ix; - y=iy; - w=iw; - h=ih; - target.image=image_in; - reference=ref; + SVGCommand nc; + nc.instr=DrawTTchar; + nc.x=ix; + nc.y=iy; + nc.w=iw; + nc.h=ih; + nc.reference=0; + nc.target.ttchar=ttchar_in; + nc.corner=TopLeft; + return nc; }; - SVGCommand(float ix, float iy,float iw,float ih,unsigned int ttchar_in) + static SVGCommand PaintClipping(float ix, float iy,float iw,float ih) { - instr=DrawTTchar; - x=ix; - y=iy; - w=iw; - h=ih; - reference=0; - target.ttchar=ttchar_in; + SVGCommand nc; + nc.instr=DrawClipping; + nc.x=ix; + nc.y=iy; + nc.w=iw; + nc.h=ih; + nc.reference=0; + nc.target.ttchar=0; + return nc; }; - SVGCommand(float ix, float iy,wchar_t char_in,unsigned int ref) + + + static SVGCommand PaintGlyph(float ix, float iy,wchar_t char_in,unsigned int ref) { - instr=DrawGlyph; - x=ix; - y=iy; - w=0; - h=0; - reference=ref; - target.textchar=char_in; + SVGCommand nc; + nc.instr=DrawGlyph; + nc.x=ix; + nc.y=iy; + nc.w=0; + nc.h=0; + nc.reference=ref; + nc.target.textchar=char_in; + return nc; }; bool Test(float tx,float ty,float tw, float th) @@ -96,11 +160,21 @@ public: { return (x==tox) && (toy==y) && (w==tx) && (h==ty); } + bool Outside(float tx,float ty,float tw, float th) + { + return ((x+w) images_ref; map monobitmaps; map jpegs; + map tvmedias; + + + + void setTVMedia(LoadIndex index, unsigned char * buffer, unsigned int length); + Mutex pict_lock_incoming; //locks + std::queue pict_incoming; + bool picture_update; + + + map loadindex_ref; + map tvmedias_load; + map tvmedias_load_inv; + map tvmedias_loaded; void incStyleRef(unsigned int index); unsigned int getStyleRef(ImageIndex index); diff --git a/recinfo.cc b/recinfo.cc index 92cb205..66ff677 100644 --- a/recinfo.cc +++ b/recinfo.cc @@ -33,6 +33,8 @@ RecInfo::RecInfo() types = NULL; languages = NULL; descriptions = NULL; + + title = NULL; } RecInfo::~RecInfo() @@ -58,6 +60,8 @@ RecInfo::~RecInfo() delete[] types; } + if (title) delete [] title; + timerStart = 0; timerEnd = 0; resumePoint = 0; diff --git a/recinfo.h b/recinfo.h index 260bd5f..27844d4 100644 --- a/recinfo.h +++ b/recinfo.h @@ -44,6 +44,8 @@ class RecInfo char** languages; char** descriptions; + char *title; + void setNumComponents(ULONG); void addComponent(ULONG componentNum, UCHAR tstream, UCHAR ttype, char* tlanguage, char* tdescription); // addComponent accepts a pointer to a buffer that RecInfo will free, not the caller diff --git a/recording.cc b/recording.cc index d173cae..5bec001 100644 --- a/recording.cc +++ b/recording.cc @@ -26,9 +26,13 @@ #include "demuxer.h" #include "demuxerts.h" #include "command.h" +#include "seriesinfo.h" +#include "movieinfo.h" Recording* Recording::recInfoFor = NULL; RecInfo* Recording::recInfo = NULL; +MovieInfo* Recording::movieInfo = NULL; +SeriesInfo* Recording::seriesInfo = NULL; Recording::Recording() { @@ -41,6 +45,9 @@ Recording::Recording() fileName = NULL; index = -1; markList = NULL; + movieID = 0; + seriesID = 0; + episodeID = 0; } Recording::~Recording() @@ -112,7 +119,34 @@ void Recording::loadRecInfo() recInfo = vdr->getRecInfo(fileName); Log::getInstance()->log("Recording", Log::DEBUG, "Recording has loaded recInfo %p", recInfo); - if (!VDR::getInstance()->isConnected()) Command::getInstance()->connectionLost(); + if (!vdr->isConnected()) Command::getInstance()->connectionLost(); + + if (movieInfo) delete movieInfo; + if (seriesInfo) delete seriesInfo; + + movieInfo = NULL; + seriesInfo = NULL; + + vdr->getScraperEventType(fileName, movieID, seriesID, episodeID); + Log::getInstance()->log("Recording", Log::DEBUG, "Got Scraper EventType %d %d %d", + movieID, seriesID, episodeID); + + if (!vdr->isConnected()) Command::getInstance()->connectionLost(); + + if (movieID != 0) + { + movieInfo = vdr->getScraperMovieInfo(movieID); + Log::getInstance()->log("Recording", Log::DEBUG, "Got Scraper MovieInfo "); + } + else if (seriesID != 0) + { + seriesInfo = vdr->getScraperSeriesInfo(seriesID, episodeID); + Log::getInstance()->log("Recording", Log::DEBUG, "Got Scraper SeriesInfo "); + } + + + if (!vdr->isConnected()) Command::getInstance()->connectionLost(); + } void Recording::dropRecInfo() @@ -120,6 +154,11 @@ void Recording::dropRecInfo() if (recInfo) delete recInfo; recInfo = NULL; recInfoFor = NULL; + if (movieInfo) delete movieInfo; + if (seriesInfo) delete seriesInfo; + + movieInfo = NULL; + seriesInfo = NULL; } void Recording::loadMarks() diff --git a/recording.h b/recording.h index be72734..745d7a0 100644 --- a/recording.h +++ b/recording.h @@ -58,7 +58,13 @@ class Recording bool hasMarks(); MarkList* getMarkList(); + int movieID; + int seriesID; + int episodeID; + static RecInfo* recInfo; + static MovieInfo* movieInfo; + static SeriesInfo* seriesInfo; private: Log* logger; @@ -74,6 +80,7 @@ class Recording // else delete recInfo and reload for this recording static Recording* recInfoFor; + MarkList* markList; }; diff --git a/seriesinfo.cc b/seriesinfo.cc new file mode 100644 index 0000000..cd866d5 --- /dev/null +++ b/seriesinfo.cc @@ -0,0 +1,49 @@ +/* + Copyright 2014 Marten Richter + + This file is part of VOMP. + + VOMP is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + VOMP is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with VOMP; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include "seriesinfo.h" + + +EpisodeInfo::EpisodeInfo() { + name=""; + firstAired=""; + guestStars=""; + overview=""; + + rating=0.; + season=0; + episodeid=0; + number=0; +} + +EpisodeInfo::~EpisodeInfo() { + +} + +SeriesInfo::SeriesInfo() +{ + id=0; + + + +} + + + diff --git a/seriesinfo.h b/seriesinfo.h new file mode 100644 index 0000000..adea749 --- /dev/null +++ b/seriesinfo.h @@ -0,0 +1,70 @@ +/* + Copyright 2014 Marten Richter + + This file is part of VOMP. + + VOMP is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + VOMP is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with VOMP; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef SERIESINFO_H +#define SERIESINFO_H + +#include "tvmedia.h" +#include + +class EpisodeInfo { +public: + EpisodeInfo(); + ~EpisodeInfo(); + + int episodeid; + int number; + int season; + std::string name; + std::string firstAired; + std::string guestStars; + std::string overview; + float rating ; + TVMedia image; + + +}; + +class SeriesInfo { +public: + SeriesInfo(); + + int id; + + + std::string name; + std::string overview; + std::string firstAired; + std::string network; + std::string genre; + double rating; + std::string status; + EpisodeInfo episode; // Image 0 + + + + + Actors actors; // Image 1 + TVMedias posters; // Image 2 + TVMedias banners; // Image 3 + TVMedias fanart; // Image 4 + TVMedia seasonposter; // Image 5 +}; +#endif diff --git a/surfacevector.cc b/surfacevector.cc index fa9659f..dff3432 100644 --- a/surfacevector.cc +++ b/surfacevector.cc @@ -37,7 +37,11 @@ SurfaceVector::~SurfaceVector() { osd->removeStyleRef((*itty).getRef()); // We remove the Style reference, so that osd can free stuff ImageIndex ii=(*itty).getImageIndex(); - if (ii) osd->removeImageRef(ii); + if (ii) { + osd->removeImageRef(ii); + } + LoadIndex li=(*itty).getLoadIndex(); + if (li) osd->removeLoadIndexRef(li); itty++; } } @@ -98,7 +102,7 @@ int SurfaceVector::drawText(const char* text, int x, int y, int width, const Dra while (num_bytes!=((size_t) -1) && num_bytes!=((size_t) -2) && length>0) { unsigned int ref=osd->getStyleRef(c); - commands.push_back(SVGCommand(x+shift,y,*tempo,ref)); + commands.push_back(SVGCommand::PaintGlyph(x+shift,y,*tempo,ref)); shift+=osd->getCharWidth(*tempo); length -= num_bytes; run += num_bytes; @@ -158,7 +162,30 @@ void SurfaceVector::drawJpeg(const char *fileName,int x, int y,int *width, int * { command_mutex.Lock(); ImageIndex image=osd->getJpegRef(fileName,width,height); - commands.push_back(SVGCommand(x,y,*width,*height,image,0)); + commands.push_back(SVGCommand::PaintImage(x,y,*width,*height,image,0)); + command_mutex.Unlock(); +} + +void SurfaceVector::drawTVMedia(TVMediaInfo & tvmedia,float x, float y, float width, float height, Corner corner) +{ + command_mutex.Lock(); + ImageIndex image=0; + LoadIndex load_index=osd->getTVMediaRef(tvmedia,image); + if (image) { + //Log::getInstance()->log("SurfaceVector", Log::DEBUG, "TVMedia Add instru image %d %d", load_index,image); + commands.push_back(SVGCommand::PaintImage(x,y,width,height,image,0,corner)); + } else { + + commands.push_back(SVGCommand::PaintImageLoading(load_index,x,y,width,height,0,corner)); + //Log::getInstance()->log("SurfaceVector", Log::DEBUG, "TVMedia Add instru image loading %d %d", load_index,image); + } + command_mutex.Unlock(); +} + +void SurfaceVector::drawClippingRectangle(float x, float y, float w, float h) +{ + command_mutex.Lock(); + commands.push_back(SVGCommand::PaintClipping((float)x,(float)y,(float)w,(float)h)); command_mutex.Unlock(); } @@ -178,7 +205,7 @@ int SurfaceVector::fillblt(int x, int y, int width, int height, const DrawStyle& command_mutex.Lock(); removeCommands(x,y,width,height); // remove commands below the box unsigned int ref=osd->getStyleRef(c); - commands.push_back(SVGCommand(x,y,width,height,Rectangle,ref)); + commands.push_back(SVGCommand::PaintPath(x,y,width,height,Rectangle,ref)); command_mutex.Unlock(); return 1; @@ -187,14 +214,14 @@ void SurfaceVector::drawHorzLine(int x1, int x2, int y, const DrawStyle& c) { command_mutex.Lock(); unsigned int ref=osd->getStyleRef(c); - commands.push_back(SVGCommand(x1,y,x2-x1,1,HorzLine,ref)); + commands.push_back(SVGCommand::PaintPath(x1,y,x2-x1,1,HorzLine,ref)); command_mutex.Unlock(); } void SurfaceVector::drawVertLine(int x, int y1, int y2, const DrawStyle& c){ command_mutex.Lock(); unsigned int ref=osd->getStyleRef(c); - commands.push_back(SVGCommand(x,y1,1,y2-y1,VertLine,ref)); + commands.push_back(SVGCommand::PaintPath(x,y1,1,y2-y1,VertLine,ref)); command_mutex.Unlock(); } @@ -224,7 +251,7 @@ void SurfaceVector::drawBitmap(int x, int y, const Bitmap& bm,const DisplayRegio ty*=scaley; tw*=scalex; th*=scaley; - SVGCommand temp=SVGCommand(tx,ty,tw,th,image,0); + SVGCommand temp=SVGCommand::PaintImage(tx,ty,tw,th,image,0); commands.push_back(temp); command_mutex.Unlock(); } @@ -232,7 +259,7 @@ void SurfaceVector::drawBitmap(int x, int y, const Bitmap& bm,const DisplayRegio void SurfaceVector::drawPoint(int x, int y, DrawStyle& c, bool fastdraw){ if (!fastdraw) command_mutex.Lock(); unsigned int ref=osd->getStyleRef(c); - commands.push_back(SVGCommand(x,y,1,1,Point,ref)); + commands.push_back(SVGCommand::PaintPath(x,y,1,1,Point,ref)); if (!fastdraw) command_mutex.Unlock(); } void SurfaceVector::drawMonoBitmap(UCHAR* base, int dx, int dy, unsigned int height,unsigned int width, DrawStyle& nextColour) @@ -240,7 +267,7 @@ void SurfaceVector::drawMonoBitmap(UCHAR* base, int dx, int dy, unsigned int hei command_mutex.Lock(); ImageIndex image=osd->getMonoBitmapRef(base,width,height); unsigned int ref=osd->getStyleRef(nextColour); - commands.push_back(SVGCommand(dx,dy,height,width,image,ref)); + commands.push_back(SVGCommand::PaintImage(dx,dy,height,width,image,ref)); command_mutex.Unlock(); } @@ -251,10 +278,12 @@ int SurfaceVector::removeCommands(float x,float y,float width,float height) list::iterator itty=commands.begin(); while (itty!=commands.end()) { - if ((*itty).Test(x,y,width,height) ) { + if ((*itty).Test(x,y,width,height) && (*itty).instr != DrawClipping) { osd->removeStyleRef((*itty).getRef()); // We remove the Style reference, so that osd can free stuff ImageIndex ii=(*itty).getImageIndex(); if (ii) osd->removeImageRef(ii); + LoadIndex li=(*itty).getLoadIndex(); + if (li) osd->removeLoadIndexRef(li); itty=commands.erase(itty); } else { itty++; @@ -296,6 +325,6 @@ void SurfaceVector::drawTTChar(int ox, int oy,int x, int y, cTeletextChar c) itty++; } } - commands.push_back(SVGCommand(ox,oy,x,y,c.getInternal())); + commands.push_back(SVGCommand::PaintTTchar(ox,oy,x,y,c.getInternal())); command_mutex.Unlock(); } diff --git a/surfacevector.h b/surfacevector.h index 519abcd..fb31b17 100644 --- a/surfacevector.h +++ b/surfacevector.h @@ -43,6 +43,11 @@ class SurfaceVector : public Surface int drawTextCentre(const char* text, int x, int y, const DrawStyle& c); void drawJpeg(const char *fileName,int x, int y,int *width, int *height); + // set width and height to zero, if the original size is wanted, if one index is non zero, + // the images is scaled with correct aspect ratio, if both are non zero both are scaled + void drawTVMedia(TVMediaInfo & tvmedia,float x, float y, float width, float height, Corner corner=TopLeft); + // set w and h to 0, for unsetting clipping, use correct x and y parameter so that cleanup of commands works + void drawClippingRectangle(float x, float y, float w, float h); int create(UINT width, UINT height); void display(); diff --git a/tvmedia.cc b/tvmedia.cc new file mode 100644 index 0000000..8460b56 --- /dev/null +++ b/tvmedia.cc @@ -0,0 +1,91 @@ +/* + Copyright 2014 Marten Richter + + This file is part of VOMP. + + VOMP is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + VOMP is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with VOMP; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include "tvmedia.h" +#include "movieinfo.h" +#include "seriesinfo.h" + + +TVMediaInfo::TVMediaInfo() +{ + type=2; // movie or series + primary_id=0; //movie or series_id + secondary_id=0; //0 or episode id + type_pict=-1; // 0 full info, 1 poster, 2 poster banner, 3 poster thumb + container=-1; // indices the dataelements with picture in movieinfo or seriesinfo + container_member=-1; // index into the container +} + + + +TVMediaInfo::TVMediaInfo(const TVMediaInfo& info) +{ + type=info.type; // movie or series + primary_id=info.primary_id; //movie or series_id + secondary_id=info.secondary_id; //0 or episode id + type_pict=info.type_pict; // 0 full info, 1 poster, 2 poster banner, 3 poster thumb + container=info.container; // indices the dataelements with picture in movieinfo or seriesinfo + container_member=info.container_member; // index into the container + +} + +void TVMediaInfo::setMovieInfo(const MovieInfo * mi) +{ + type=1; // movie or series + primary_id=mi->id; //movie or series_id + secondary_id=0; //0 or episode id +} + +void TVMediaInfo::setSeriesInfo(const SeriesInfo * si) +{ + type=0; // movie or series + primary_id=si->id; //movie or series_id + secondary_id=si->episode.episodeid; //0 or episode id +} + +bool operator<(const TVMediaInfo& rhs, const TVMediaInfo& lhs) +{ + if (rhs.type==lhs.type) { + if (rhs.primary_id==lhs.primary_id) { + if (rhs.secondary_id==lhs.secondary_id) { + if (rhs.type_pict==lhs.type_pict) { + if (rhs.container==lhs.container) { + return rhs.container_member +#include + +class MovieInfo; +class SeriesInfo; + +class TVMediaInfo +{ +friend class VDR; +public: + TVMediaInfo(); + TVMediaInfo(const TVMediaInfo& info); + + friend bool operator<(const TVMediaInfo& rhs, const TVMediaInfo& lhs); + + void setSeasonThumb() { type_pict=2; container=0; container_member=0;}; + void setPosterThumb() { type_pict=1; container=0; container_member=0;}; + void setElement(int cont,int memb) { type_pict=0; container=cont; container_member=memb;}; + void setMovieInfo(const MovieInfo * mi); + void setSeriesInfo(const SeriesInfo * si); + +private: + int type; // movie or series + int primary_id; //movie or series_id + int secondary_id; //0 or episode id + int type_pict; // 0 full info, 1 poster thumb, 2 season thumb + int container; // indices the dataelements with picture in movieinfo or seriesinfo + int container_member; // index into the container +}; + +struct TVMedia +{ + unsigned int width; + unsigned int height; + + // no filename, file handling is only on the server + TVMediaInfo info; + +}; + +typedef std::vector TVMedias; + +struct Actor +{ + std::string name; + std::string role; + TVMedia thumb; +}; + +typedef std::vector Actors; + +#endif diff --git a/vconnect.cc b/vconnect.cc index e923665..7755073 100644 --- a/vconnect.cc +++ b/vconnect.cc @@ -162,15 +162,15 @@ void VConnect::threadMethod() if (success) { logger->log("VConnect", Log::DEBUG, "Connected ok, doing login"); - unsigned int version_server,version_client; - success = vdr->doLogin(&version_server,&version_client); + unsigned int version_server_min,version_server_max,version_client; + success = vdr->doLogin(&version_server_min,&version_server_max,&version_client); if (!success) { vdr->disconnect(); - if (version_server!=version_client) { + if (version_server_min >version_client || version_client > version_server_max) { char buffer[1024]; - sprintf(buffer,"Protocoll mismatch s: %x c: %x",version_server,version_client); + sprintf(buffer,"Protocol mismatch s min: %x s max: %x c: %x",version_server_min,version_server_max,version_client); setOneLiner(buffer); } else { setOneLiner(tr("Login failed")); diff --git a/vdr.cc b/vdr.cc index bb2d4d3..e8d7043 100644 --- a/vdr.cc +++ b/vdr.cc @@ -37,8 +37,11 @@ #include "vdrcommand.h" #include "video.h" #include "osd.h" +#include "movieinfo.h" +#include "seriesinfo.h" -#define VOMP_PROTOCOLL_VERSION 0x00000301 + +#define VOMP_PROTOCOLL_VERSION 0x00000302 VDR* VDR::instance = NULL; //prepare a request @@ -348,7 +351,7 @@ void VDR::threadMethod() // Data was read channelID = ntohl(channelID); - + if (channelID == CHANNEL_REQUEST_RESPONSE) { if (!tcp->readData((UCHAR*)&requestID, sizeof(ULONG))) break; @@ -375,7 +378,7 @@ void VDR::threadMethod() delete vresp; } } - else if (channelID == CHANNEL_STREAM) + else if (channelID == CHANNEL_STREAM || channelID == CHANNEL_TVMEDIA) { if (!tcp->readData((UCHAR*)&streamID, sizeof(ULONG))) break; streamID = ntohl(streamID); @@ -394,8 +397,8 @@ void VDR::threadMethod() } vresp = new VDR_ResponsePacket(); - vresp->setStream(streamID, flag, userData, userDataLength); -// logger->log("VDR", Log::DEBUG, "Rxd a stream packet, streamID=%lu, flag=%lu, len=%lu", streamID, flag, userDataLength); + vresp->setStream(streamID, flag, userData, userDataLength, channelID); + //logger->log("VDR", Log::DEBUG, "Rxd a stream packet, streamID=%lu, flag=%lu, len=%lu", streamID, flag, userDataLength); if (!edFindAndCall(vresp)) // makes ED lock, find receiver for vresp (using ed_cb_find() ) and then call (using ed_cb_call() ) { @@ -466,10 +469,10 @@ void VDR::connectionDied() } edLock(); } - else if (vdrpr->receiverChannel == CHANNEL_STREAM) + else if (vdrpr->receiverChannel == CHANNEL_STREAM || vdrpr->receiverChannel == CHANNEL_TVMEDIA) { vresp = new VDR_ResponsePacket(); - vresp->setStream(vdrpr->streamID, 2 /* connection-lost flag */ , NULL, 0); + vresp->setStream(vdrpr->streamID, 2 /* connection-lost flag */ , NULL, 0, vdrpr->receiverChannel); logger->log("VDR", Log::DEBUG, "Timeouts: created blank response packet for streamid %lu", vdrpr->streamID); edUnlock(); if (!edFindAndCall(vresp)) // makes ED lock, find receiver for vresp (using ed_cb_find() ) and then call (using ed_cb_call() ) @@ -503,6 +506,7 @@ bool VDR::ed_cb_find(EDReceiver* edr, void* userTag) // Is vresp for vdrpr ? ULONG packetChannel = vresp->getChannelID(); + //logger->log("VDR", Log::DEBUG, "TVMedia debug %d %d %x", vdrpr->receiverChannel,packetChannel,vdrpr); if (vdrpr->receiverChannel != packetChannel) return false; if (packetChannel == CHANNEL_REQUEST_RESPONSE) @@ -512,6 +516,9 @@ bool VDR::ed_cb_find(EDReceiver* edr, void* userTag) else if (packetChannel == CHANNEL_STREAM) { if (vdrpr->streamID == vresp->getStreamID()) return true; + } else if (packetChannel == CHANNEL_TVMEDIA) + { //We want them all + return true; } return false; @@ -584,7 +591,7 @@ bool VDR::sendKA(ULONG timeStamp) // Here VDR takes a break for the VDR_PacketReceiver helper class -bool VDR_PacketReceiver::call(void* userTag) +bool VDR_PacketReceiver::call(void* userTag, bool & deleteme) { if (receiverChannel == VDR::CHANNEL_REQUEST_RESPONSE) { @@ -592,6 +599,7 @@ bool VDR_PacketReceiver::call(void* userTag) // VDR::RequestResponse will be blocking waiting for this to happen. // That function has a pointer to this object and can read save_vresp. save_vresp = (VDR_ResponsePacket*)userTag; + deleteme=false; return true; // Signals ED to remove edr from receivers and wake up edr thread } @@ -601,15 +609,28 @@ bool VDR_PacketReceiver::call(void* userTag) VDR_ResponsePacket* vresp = (VDR_ResponsePacket*)userTag; streamReceiver->streamReceive(vresp->getFlag(), vresp->getUserData(), vresp->getUserDataLength()); delete vresp; + deleteme=false; return false; } + if (receiverChannel == VDR::CHANNEL_TVMEDIA) + { + // It's TVMedia + VDR_ResponsePacket* vresp = (VDR_ResponsePacket*)userTag; + Log::getInstance()->log("VDR", Log::DEBUG, "TVMedia Pictures arrived VDR"); + OsdVector *osd=dynamic_cast(Osd::getInstance()); + if (osd) osd->receivePicture(vresp); + else delete vresp; //nonsense + deleteme=false; + return true; + } + abort(); // unknown receiverChannel, should not happen } ///////////////////////////////////////////////////////////////////////////// -int VDR::doLogin(unsigned int* v_server,unsigned int* v_client) +int VDR::doLogin(unsigned int* v_server_min, unsigned int* v_server_max, unsigned int* v_client) { VDR_RequestPacket vrp; if (!vrp.init(VDR_LOGIN, true, 6)) return 0; @@ -626,14 +647,17 @@ int VDR::doLogin(unsigned int* v_server,unsigned int* v_client) long vdrTimeOffset = vresp->extractLONG(); logger->log("VDR", Log::DEBUG, "offset = %i", vdrTimeOffset); - unsigned int version=vresp->extractULONG(); + unsigned int version_min=vresp->extractULONG(); - *v_server=version; + *v_server_min=version_min; + unsigned int version_max=vresp->extractULONG(); + *v_server_max=version_max; *v_client=VOMP_PROTOCOLL_VERSION; delete vresp; - if (version!=VOMP_PROTOCOLL_VERSION) { + if ((version_min > VOMP_PROTOCOLL_VERSION) + || (version_max < VOMP_PROTOCOLL_VERSION) ) { return 0; @@ -1190,6 +1214,7 @@ RecInfo* VDR::getRecInfo(char* fileName) } } recInfo->fps=vresp->extractdouble(); + recInfo->title=vresp->extractString(); recInfo->print(); @@ -1566,3 +1591,209 @@ void VDR::shutdownVDR() logger->log("VDR", Log::DEBUG, "VDR shutdown"); } + +void VDR::getScraperEventType(char * fileName, int & movieID, + int & seriesID, int & episodeID ) +{ + movieID = 0; + seriesID = 0; + episodeID = 0; + VDR_RequestPacket vrp; + if (!vrp.init(VDR_GETRECSCRAPEREVENTTYPE, true, strlen(fileName) + 1)) return; + if (!vrp.addString(fileName)) return ; + Log::getInstance()->log("Recording", Log::DEBUG, "Before Response "); + VDR_ResponsePacket* vresp = RequestResponse(&vrp); + Log::getInstance()->log("Recording", Log::DEBUG, "After Response "); + if (vresp->noResponse()) { delete vresp; return ; } + int type = vresp->extractUCHAR(); + if (type == 0) //serie + { + seriesID = vresp->extractLONG(); + episodeID = vresp->extractLONG(); + } else if (type == 1) //movie + { + movieID = vresp->extractLONG(); + } + delete vresp; + +} + +MovieInfo *VDR::getScraperMovieInfo(int movieID) +{ + VDR_RequestPacket vrp; + if (!vrp.init(VDR_GETSCRAPERMOVIEINFO, false, 0)) return NULL; + if (!vrp.addULONG(movieID)) return NULL; + VDR_ResponsePacket* vresp = RequestResponse(&vrp); + if (vresp->noResponse()) { delete vresp; return NULL; } + MovieInfo * movieinf= new MovieInfo(); + + movieinf->id=movieID; + movieinf->title = vresp->extractStdString(); + movieinf->originalTitle = vresp->extractStdString(); + movieinf->tagline = vresp->extractStdString(); + movieinf->overview = vresp->extractStdString(); + movieinf->adult = vresp->extractUCHAR(); + movieinf->collectionName = vresp->extractStdString(); + + movieinf->budget = vresp->extractLONG(); + movieinf->revenue = vresp->extractLONG(); + movieinf->genres = vresp->extractStdString(); + movieinf->homepage = vresp->extractStdString(); + movieinf->releaseDate = vresp->extractStdString(); + movieinf->runtime = vresp->extractLONG(); + movieinf->popularity = vresp->extractdouble(); + movieinf->voteAverage = vresp->extractdouble(); + movieinf->poster.width = vresp->extractULONG(); + movieinf->poster.height = vresp->extractULONG(); + movieinf->poster.info.setMovieInfo(movieinf); + movieinf->poster.info.setElement(0,0); + movieinf->fanart.width = vresp->extractULONG(); + movieinf->fanart.height = vresp->extractULONG(); + movieinf->fanart.info.setMovieInfo(movieinf); + movieinf->fanart.info.setElement(1,0); + movieinf->collectionPoster.width = vresp->extractULONG(); + movieinf->collectionPoster.height = vresp->extractULONG(); + movieinf->collectionPoster.info.setMovieInfo(movieinf); + movieinf->collectionPoster.info.setElement(2,0); + movieinf->collectionFanart.width = vresp->extractULONG(); + movieinf->collectionFanart.height = vresp->extractULONG(); + movieinf->collectionFanart.info.setMovieInfo(movieinf); + movieinf->collectionFanart.info.setElement(3,0); + ULONG num_actors = vresp->extractULONG(); + movieinf->actors.clear(); + movieinf->actors.reserve(num_actors); + for (ULONG acty=0; acty < num_actors; acty++) { + Actor new_act; + new_act.name = vresp->extractStdString(); + new_act.role = vresp->extractStdString(); + new_act.thumb.width = vresp->extractULONG(); + new_act.thumb.height = vresp->extractULONG(); + new_act.thumb.info.setMovieInfo(movieinf); + new_act.thumb.info.setElement(4,acty); + movieinf->actors.push_back(new_act); + } + + + delete vresp; + return movieinf; + +} + +SeriesInfo *VDR::getScraperSeriesInfo(int seriesID, int episodeID) +{ + VDR_RequestPacket vrp; + if (!vrp.init(VDR_GETSCRAPERSERIESINFO, false, 0)) return NULL; + if (!vrp.addULONG(seriesID)) return NULL; + if (!vrp.addULONG(episodeID)) return NULL; + + VDR_ResponsePacket* vresp = RequestResponse(&vrp); + if (vresp->noResponse()) { delete vresp; return 0; } + SeriesInfo * seriesinf= new SeriesInfo(); + + seriesinf->id=seriesID; + + + seriesinf->name = vresp->extractStdString(); + seriesinf->overview = vresp->extractStdString(); + seriesinf->firstAired = vresp->extractStdString(); + seriesinf->network = vresp->extractStdString(); + seriesinf->genre = vresp->extractStdString(); + seriesinf->rating = vresp->extractdouble(); + seriesinf->status = vresp->extractStdString(); + + + seriesinf->episode.episodeid=episodeID; + seriesinf->episode.number = vresp->extractLONG(); + seriesinf->episode.season = vresp->extractLONG(); + seriesinf->episode.name = vresp->extractStdString(); + seriesinf->episode.firstAired = vresp->extractStdString(); + seriesinf->episode.guestStars = vresp->extractStdString(); + seriesinf->episode.overview = vresp->extractStdString(); + seriesinf->episode.rating = vresp->extractdouble(); + seriesinf->episode.image.width = vresp->extractULONG(); + seriesinf->episode.image.height = vresp->extractULONG(); + seriesinf->episode.image.info.setSeriesInfo(seriesinf); + seriesinf->episode.image.info.setElement(0,0); + + + ULONG num_actors = vresp->extractULONG(); + seriesinf->actors.clear(); + seriesinf->actors.reserve(num_actors); + for (ULONG acty=0; acty < num_actors; acty++) { + Actor new_act; + new_act.name = vresp->extractStdString(); + new_act.role = vresp->extractStdString(); + new_act.thumb.width = vresp->extractULONG(); + new_act.thumb.height = vresp->extractULONG(); + new_act.thumb.info.setSeriesInfo(seriesinf); + new_act.thumb.info.setElement(1,acty); + seriesinf->actors.push_back(new_act); + } + ULONG num_posters = vresp->extractULONG(); + for (ULONG medias = 0; medias < num_posters; medias++ ) { + TVMedia media; + media.info.setSeriesInfo(seriesinf); + media.info.setElement(2,medias); + media.width = vresp->extractULONG(); + media.height = vresp->extractULONG(); + seriesinf->posters.push_back(media); + } + + ULONG num_banners = vresp->extractULONG(); + for (ULONG medias = 0; medias < num_banners; medias++ ) { + TVMedia media; + media.info.setSeriesInfo(seriesinf); + media.info.setElement(3,medias); + media.width = vresp->extractULONG(); + media.height = vresp->extractULONG(); + seriesinf->banners.push_back(media); + } + ULONG num_fanarts = vresp->extractULONG(); + for (ULONG medias = 0; medias < num_fanarts; medias++ ) { + TVMedia media; + media.info.setSeriesInfo(seriesinf); + media.info.setElement(4,medias); + media.width = vresp->extractULONG(); + media.height = vresp->extractULONG(); + seriesinf->fanart.push_back(media); + } + seriesinf->seasonposter.width = vresp->extractULONG(); + seriesinf->seasonposter.height = vresp->extractULONG(); + seriesinf->seasonposter.info.setSeriesInfo(seriesinf); + seriesinf->seasonposter.info.setElement(5,0); + + delete vresp; + return seriesinf; + +} + +ULONG VDR::loadTVMedia(TVMediaInfo& tvmedia) +{ + + VDR_RequestPacket vrp; + + if (!vrp.init(VDR_LOADTVMEDIA, false, 0)) return -1; + if (!vrp.addULONG(tvmedia.type)) return -1; + if (!vrp.addULONG(tvmedia.primary_id)) return -1; + if (!vrp.addULONG(tvmedia.secondary_id)) return -1; + if (!vrp.addULONG(tvmedia.type_pict)) return -1; + if (!vrp.addULONG(tvmedia.container)) return -1; + if (!vrp.addULONG(tvmedia.container_member)) return -1; + Log::getInstance()->log("VDR", Log::DEBUG, "TVMedia with ID %d %d; %d %d %d %d;%d", + tvmedia.primary_id,tvmedia.secondary_id,tvmedia.type,tvmedia.type_pict, + tvmedia.container,tvmedia.container_member,vrp.getSerial()); + + + VDR_PacketReceiver* vdrpr = new VDR_PacketReceiver(); + vdrpr->receiverChannel = VDR::CHANNEL_TVMEDIA; + vdrpr->streamID = vrp.getSerial(); + vdrpr->streamReceiver = NULL; + edRegister(vdrpr); + + + VDR_ResponsePacket* vresp = RequestResponse(&vrp); + //if (vresp->noResponse()) { delete vresp; return -1; } + delete vresp; + + return vrp.getSerial(); +} diff --git a/vdr.h b/vdr.h index c406115..f322051 100644 --- a/vdr.h +++ b/vdr.h @@ -40,6 +40,7 @@ #include "eventdispatcher.h" #include "i18n.h" #include "log.h" +#include "osdvector.h" class TCP; class Log; @@ -49,6 +50,9 @@ class Channel; class VDR_RequestPacket; class VDR_ResponsePacket; class SerializeBuffer; +class MovieInfo; +class SeriesInfo; + using namespace std; @@ -92,7 +96,7 @@ class StreamReceiver class VDR_PacketReceiver : public EDReceiver // implementation in vdr.cc { public: - virtual bool call(void* userTag); + virtual bool call(void* userTag, bool & deleteme); friend class VDR; protected: @@ -119,6 +123,7 @@ class VDR : public Thread_TYPE, public EventDispatcher, public MediaProvider, pu const static ULONG CHANNEL_STREAM = 2; const static ULONG CHANNEL_KEEPALIVE = 3; const static ULONG CHANNEL_NETLOG = 4; + const static ULONG CHANNEL_TVMEDIA = 5; VDR(); ~VDR(); @@ -158,7 +163,7 @@ class VDR : public Thread_TYPE, public EventDispatcher, public MediaProvider, pu // configSave // setEventTimer - int doLogin(unsigned int* v_server,unsigned int* v_client); + int doLogin(unsigned int* v_server_min, unsigned int* v_server_max, unsigned int* v_client); bool getRecordingsList(RecMan* recman); RecInfo* getRecInfo(char* fileName); int deleteRecording(char* fileName); @@ -199,6 +204,12 @@ class VDR : public Thread_TYPE, public EventDispatcher, public MediaProvider, pu virtual int getMediaInfo(ULONG channel, struct MediaInfo * result); virtual int closeMediaChannel(ULONG channel); + //TV Scraper support + void getScraperEventType(char * fileName, int & movieID, int & seriesID, int & episodeID); + MovieInfo *getScraperMovieInfo(int movieID); + SeriesInfo *getScraperSeriesInfo(int seriesID, int episodeID); + ULONG loadTVMedia(TVMediaInfo& tvmedia); + I18n::lang_code_list getLanguageList(); int getLanguageContent(const string code, I18n::trans_table&); diff --git a/vdrcommand.h b/vdrcommand.h index 33b9352..d0a8af8 100644 --- a/vdrcommand.h +++ b/vdrcommand.h @@ -69,6 +69,10 @@ const static ULONG VDR_OPENMEDIA = 31; const static ULONG VDR_GETMEDIABLOCK = 32; const static ULONG VDR_GETMEDIAINFO = 35; const static ULONG VDR_CLOSECHANNEL = 36; +const static ULONG VDR_GETRECSCRAPEREVENTTYPE = 38; +const static ULONG VDR_GETSCRAPERMOVIEINFO = 39; +const static ULONG VDR_GETSCRAPERSERIESINFO = 40; +const static ULONG VDR_LOADTVMEDIA = 41; const static ULONG VDR_SHUTDOWN = 666; class VDR_Command : public SerializableList { diff --git a/vdrresponsepacket.cc b/vdrresponsepacket.cc index 37b2be5..41ff522 100644 --- a/vdrresponsepacket.cc +++ b/vdrresponsepacket.cc @@ -53,9 +53,9 @@ void VDR_ResponsePacket::setResponse(ULONG trequestID, UCHAR* tuserData, ULONG t userDataLength = tuserDataLength; } -void VDR_ResponsePacket::setStream(ULONG tstreamID, ULONG tflag, UCHAR* tuserData, ULONG tuserDataLength) +void VDR_ResponsePacket::setStream(ULONG tstreamID, ULONG tflag, UCHAR* tuserData, ULONG tuserDataLength, ULONG tchannelID) { - channelID = VDR::CHANNEL_STREAM; + channelID = tchannelID; streamID = tstreamID; flag = tflag; userData = tuserData; @@ -78,6 +78,17 @@ int VDR_ResponsePacket::serverError() else return 0; } +std::string VDR_ResponsePacket::extractStdString() +{ + if (serverError()) return NULL; + + int length = strlen((char*)&userData[packetPos]); + if ((packetPos + length) > userDataLength) return std::string(""); + const char * dest_str=(char*)&userData[packetPos]; + packetPos += length + 1; + return dest_str; +} + char* VDR_ResponsePacket::extractString() { if (serverError()) return NULL; diff --git a/vdrresponsepacket.h b/vdrresponsepacket.h index 0d60be0..25abedf 100644 --- a/vdrresponsepacket.h +++ b/vdrresponsepacket.h @@ -29,6 +29,7 @@ #include #include +#include #include "defines.h" @@ -39,7 +40,7 @@ class VDR_ResponsePacket ~VDR_ResponsePacket(); void setResponse(ULONG requestID, UCHAR* packet, ULONG packetLength); - void setStream(ULONG streamID, ULONG flag, UCHAR* packet, ULONG packetLength); + void setStream(ULONG streamID, ULONG flag, UCHAR* packet, ULONG packetLength, ULONG tchannelID); bool noResponse() { return (userData == NULL); }; int serverError(); @@ -51,6 +52,7 @@ class VDR_ResponsePacket ULONG getFlag() { return flag; } char* extractString(); + std::string extractStdString(); UCHAR extractUCHAR(); ULONG extractULONG(); ULLONG extractULLONG(); diff --git a/videoomx.cc b/videoomx.cc index fd8a133..33ce840 100644 --- a/videoomx.cc +++ b/videoomx.cc @@ -1208,7 +1208,7 @@ int VideoOMX::AllocateCodecsOMX() } - Log::getInstance()->log("Video", Log::DEBUG, "mark2 "); + if (!ChangeComponentState(omx_vid_sched,OMX_StateIdle)) { Log::getInstance()->log("Video", Log::DEBUG, "vid_sched idle ChangeComponentState"); clock_mutex.Unlock(); @@ -1218,7 +1218,7 @@ int VideoOMX::AllocateCodecsOMX() - Log::getInstance()->log("Video", Log::DEBUG, "mark1 "); + if ( !CommandFinished(omx_vid_sched,OMX_CommandPortEnable,omx_shed_clock_port)) { clock_mutex.Unlock(); DeAllocateCodecsOMX(); @@ -1228,7 +1228,7 @@ int VideoOMX::AllocateCodecsOMX() - Log::getInstance()->log("Video", Log::DEBUG, "mark1 special "); + if ( !CommandFinished(omx_clock,OMX_CommandPortEnable,omx_clock_output_port)) { clock_mutex.Unlock(); DeAllocateCodecsOMX(); @@ -1237,9 +1237,6 @@ int VideoOMX::AllocateCodecsOMX() - Log::getInstance()->log("Video", Log::DEBUG, "mark1b "); - - /* error=OMX_SendCommand(omx_vid_dec,OMX_CommandStateSet,OMX_StateIdle,0); if (error!=OMX_ErrorNone){ Log::getInstance()->log("Video", Log::DEBUG, "vid_dec Send Command to OMX State Idle %x", error); diff --git a/vrecording.cc b/vrecording.cc index 6ebb45c..f9e2eca 100644 --- a/vrecording.cc +++ b/vrecording.cc @@ -36,63 +36,111 @@ #include "recording.h" #include "message.h" #include "log.h" +#include "wmovieview.h" +#include "wseriesview.h" +#include "wpictureview.h" VRecording::VRecording(RecMan* trecman, Recording* trec) { rec = trec; recman = trecman; + buttons = true; Log::getInstance()->log("VRecording", Log::DEBUG, "%s", rec->getProgName()); rec->loadRecInfo(); Log::getInstance()->log("VRecording", Log::DEBUG, "%s", rec->getProgName()); - setSize(570, 420); - createBuffer(); + if (Video::getInstance()->getFormat() == Video::PAL) { - setPosition(80, 70); + setSize(640, 500); + createBuffer(); } else { - setPosition(70, 35); + setSize(560, 400); + createBuffer(); } + setPosition(40, 40); setTitleBarOn(1); setBorderOn(1); - setTitleText(rec->getProgName()); + if (rec->recInfo && strlen(rec->recInfo->title)) + setTitleText(rec->recInfo->title); + else + setTitleText(rec->getProgName()); setTitleBarColour(DrawStyle::TITLEBARBACKGROUND); - summary.setPosition(10, 30 + 5); - summary.setSize(area.w - 20, area.h - 30 - 15 - 50); - summary.setParaMode(true); + tabbar.setPosition(10+130+10, 30 + 5); + tabbar.setSize(area.w - 20-10-130, area.h - 30 - 10); + add(&tabbar); + + + - if (rec->recInfo &&strlen(rec->recInfo->summary)) - summary.setText(rec->recInfo->summary); + WTextbox * summary=new WTextbox(); + summary->setParaMode(true); + + if (rec->recInfo && strlen(rec->recInfo->summary)) + summary->setText(rec->recInfo->summary); else - summary.setText(tr("Summary unavailable")); + summary->setText(tr("Summary unavailable")); + + OsdVector *osdv=dynamic_cast(Osd::getInstance()); + + tabbar.addTab(tr("EPG"), summary); + if (rec->movieInfo) { + WMovieView *movieview = new WMovieView(rec->movieInfo); + movieview->setParaMode(true); + tabbar.addTab(tr("TheTVDB Info"), movieview); + if (osdv) { + if (rec->movieInfo->actors.size() > 0 && osdv) + { + WActorGallery *gallery= new WActorGallery(rec->movieInfo->actors); + tabbar.addTab(tr("Cast"),gallery); + } + WArtworkGallery *artgallery= new WArtworkGallery(*rec->movieInfo); + tabbar.addTab(tr("Gallery"),artgallery); + } + } else if (rec->seriesInfo) { + WSeriesView *seriesview = new WSeriesView(rec->seriesInfo); + seriesview->setParaMode(true); + tabbar.addTab(tr("TheTVDB Info"), seriesview); + if (osdv) { + if (rec->seriesInfo->actors.size() > 0 && osdv) + { + WActorGallery *gallery= new WActorGallery(rec->seriesInfo->actors); + tabbar.addTab(tr("Cast"),gallery); + } + WArtworkGallery *artgallery= new WArtworkGallery(*rec->seriesInfo); + tabbar.addTab(tr("Gallery"),artgallery); + } + + } + - add(&summary); int sfh = getFontHeight(); buttonRegion.x = 10; - buttonRegion.y = area.h - 40; - buttonRegion.w = 550; - buttonRegion.h = sfh; + buttonRegion.y = 10+30; + buttonRegion.w = 130; + buttonRegion.h = sfh*2*last; button[PLAY].setText(tr("Play")); button[RESUME].setText(tr("Resume")); button[MOVE].setText(tr("Move")); button[A_DELETE].setText(tr("Delete")); - for (int i=PLAY, hor=10; i(Osd::getInstance()); + if (osdv) { + TVMedia poster; + if (rec->movieInfo) { + poster=rec->movieInfo->poster; + } + if (rec->seriesInfo) { + if (rec->seriesInfo->seasonposter.height) { + poster=rec->seriesInfo->seasonposter; + } + else + if (rec->seriesInfo->posters.size()) { + poster=rec->seriesInfo->posters[0]; + } + } + if (poster.height) { + // float aspect=((float)poster.height)/((float)poster.width)/Osd::getInstance()->getPixelAspect(); + drawTVMedia(poster.info,buttonRegion.x, + buttonRegion.y+buttonRegion.h, + buttonRegion.w,/*buttonRegion.w*aspect*/0.f); + } + } + } int VRecording::handleCommand(int command) { - switch(command) - { - case Remote::LEFT: - case Remote::DF_LEFT: - case Remote::DF_UP: - case Remote::UP: - { - moveCursor(LEFT); - return 2; - } - case Remote::RIGHT: - case Remote::DF_RIGHT: - case Remote::DF_DOWN: - case Remote::DOWN: - { - moveCursor(RIGHT); - return 2; - } - case Remote::OK: - { + if (command==Remote::BACK) { + return 4; + } + if (buttons) { + switch(command) + { + case Remote::DF_UP: + case Remote::UP: + { + moveCursor(LEFT); + return 2; + } - if (selected == PLAY) - { - Message* m = new Message(); // Must be done after this view deleted - m->from = this; - m->to = vRecList; - m->message = Message::PLAY_SELECTED_RECORDING; - Command::getInstance()->postMessageNoLock(m); - return 4; - } + case Remote::DF_DOWN: + case Remote::DOWN: + { + moveCursor(RIGHT); + return 2; + } + case Remote::LEFT: + case Remote::DF_LEFT: + case Remote::RIGHT: + case Remote::DF_RIGHT: + { + buttons = false; + button[selected].setActive(0); + tabbar.activateFocus(true); + button[selected].draw(); + tabbar.draw(); + BoxStack::getInstance()->update(this); + return 2; + } + case Remote::OK: + { - if (selected == RESUME) - { - Message* m = new Message(); // Must be done after this view deleted - m->from = this; - m->to = vRecList; - m->message = Message::RESUME_SELECTED_RECORDING; - Command::getInstance()->postMessageNoLock(m); - return 4; - } + if (selected == PLAY) + { + Message* m = new Message(); // Must be done after this view deleted + m->from = this; + m->to = vRecList; + m->message = Message::PLAY_SELECTED_RECORDING; + Command::getInstance()->postMessageNoLock(m); + return 4; + } - if (selected == MOVE) - { - VRecMove* vrm = new VRecMove(recman); - vrm->setParent(this); - vrm->draw(); - BoxStack::getInstance()->add(vrm); - BoxStack::getInstance()->update(vrm); - return 2; - } + if (selected == RESUME) + { + Message* m = new Message(); // Must be done after this view deleted + m->from = this; + m->to = vRecList; + m->message = Message::RESUME_SELECTED_RECORDING; + Command::getInstance()->postMessageNoLock(m); + return 4; + } - if (selected == A_DELETE) - { - VQuestion* v = new VQuestion(this); - v->setSize(260, 180); - v->createBuffer(); - v->setTitleBarColour(DrawStyle::DANGER); - v->setTitleBarOn(1); - v->setBorderOn(1); - v->setTitleText(tr("Delete recording")); - v->setMainText(tr("Are you sure you want to delete this recording?")); - v->setDefault(VQuestion::NO); - if (Video::getInstance()->getFormat() == Video::PAL) - { - v->setPosition(230, 160); - } - else - { - v->setPosition(220, 140); - } - - v->draw(); - BoxStack::getInstance()->add(v); - BoxStack::getInstance()->update(v); - return 2; - } - } + if (selected == MOVE) + { + VRecMove* vrm = new VRecMove(recman); + vrm->setParent(this); + vrm->draw(); + BoxStack::getInstance()->add(vrm); + BoxStack::getInstance()->update(vrm); + return 2; + } - case Remote::BACK: - { - return 4; - } - } - // stop command getting to any more views - return 1; + if (selected == A_DELETE) + { + VQuestion* v = new VQuestion(this); + v->setSize(260, 180); + v->createBuffer(); + v->setTitleBarColour(DrawStyle::DANGER); + v->setTitleBarOn(1); + v->setBorderOn(1); + v->setTitleText(tr("Delete recording")); + v->setMainText(tr("Are you sure you want to delete this recording?")); + v->setDefault(VQuestion::NO); + if (Video::getInstance()->getFormat() == Video::PAL) + { + v->setPosition(230, 160); + } + else + { + v->setPosition(220, 140); + } + + v->draw(); + BoxStack::getInstance()->add(v); + BoxStack::getInstance()->update(v); + return 2; + } + } + } + } else { + // Pass to tabbar + int retval = tabbar.handleCommand(command); + if (retval == 1) + { + BoxStack::getInstance()->update(this); + return 2; + } + else if (retval == 2) + { + // command was taken and actively ignored + if (command==Remote::LEFT || command==Remote::DF_LEFT + || command==Remote::RIGHT || command==Remote::DF_RIGHT) + { + buttons=true; + button[selected].setActive(1); + tabbar.activateFocus(false); + button[selected].draw(); + tabbar.draw(); + BoxStack::getInstance()->update(this); + } + return 2; + } + } + + + // stop command getting to any more views + return 1; } void VRecording::moveCursor(Direction direction) diff --git a/vrecording.h b/vrecording.h index 10394c2..ca5eac1 100644 --- a/vrecording.h +++ b/vrecording.h @@ -27,6 +27,7 @@ #include "tbboxx.h" #include "wbutton.h" #include "wtextbox.h" +#include "wtabbar.h" class VRecordingList; class RecMan; @@ -49,8 +50,7 @@ class VRecording : public TBBoxx RecMan* recman; VRecordingList* vRecList; Recording* rec; - - WTextbox summary; + WTabBar tabbar; enum Action { PLAY=0, RESUME, MOVE, A_DELETE, last }; WButton button[last]; @@ -61,6 +61,7 @@ class VRecording : public TBBoxx int selected; Region buttonRegion; + bool buttons; enum Direction { LEFT, RIGHT }; void moveCursor(Direction direction); diff --git a/wmovieview.cc b/wmovieview.cc new file mode 100644 index 0000000..9e5ed6e --- /dev/null +++ b/wmovieview.cc @@ -0,0 +1,84 @@ +/* + Copyright 2014 Marten Richter + + This file is part of VOMP. + + VOMP is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + VOMP is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with VOMP; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include "wmovieview.h" +#include "i18n.h" +#include + + +WMovieView::WMovieView(MovieInfo* movie): +WTextbox(NULL) +{ + // portions from nopacity plugin by Louis Braun + if (movie) + { + std::stringstream info; + info << tr("TheMovieDB Information") << ":\n\n"; + if (!movie->originalTitle.empty()){ + info << tr("Original Title") << ": " << movie->originalTitle << "\n\n"; + } + if (!movie->tagline.empty()){ + info << tr("Tagline") << ": " << movie->tagline << "\n\n"; + } + if (!movie->overview.empty()){ + info << tr("Overview") << ": " << movie->overview << "\n\n"; + } + const char* strAdult = (movie->adult)?(tr("yes")):(tr("no")); + info << tr("Adult") << ": " << strAdult << "\n\n"; + if (!movie->collectionName.empty()){ + info << tr("Collection") << ": " << movie->collectionName << "\n\n"; + } + if (movie->budget > 0 ){ + info << tr("Budget") << ": " << movie->budget << "$\n\n"; + } + if (movie->revenue > 0 ){ + info << tr("Revenue") << ": " << movie->revenue << "$\n\n"; + } + if (!movie->genres.empty() ){ + info << tr("Genre") << ": " << movie->genres << "\n\n"; + } + if (!movie->homepage.empty()){ + info << tr("Homepage") << ": " << movie->homepage << "\n\n"; + } + if (!movie->releaseDate.empty()){ + info << tr("Release Date") << ": " << movie->releaseDate << "\n\n"; + } + if (movie->runtime > 0 ){ + info << tr("Runtime") << ": " << movie->runtime << " " << tr("minutes") << "\n\n"; + } + if (movie->popularity > 0 ){ + info << tr("TheMovieDB Popularity") << ": " << movie->popularity << "\n\n"; + } + if (movie->voteAverage > 0 ){ + info << tr("TheMovieDB Vote Average") << ": " << movie->voteAverage << "\n\n"; + } + setText(info.str().c_str()); + } else { + setText("This is a bug!"); + } + +} + +void WMovieView::draw() +{ + WTextbox::draw(); + + +} diff --git a/wmovieview.h b/wmovieview.h new file mode 100644 index 0000000..ef04c75 --- /dev/null +++ b/wmovieview.h @@ -0,0 +1,44 @@ +/* + Copyright 2014 Marten Richter + + This file is part of VOMP. + + VOMP is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + VOMP is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with VOMP; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef WMOVIEVIEW_H +#define WMOVIEVIEW_H + +#include +#include + +#include "defines.h" +#include "wtextbox.h" +#include "movieinfo.h" + +class Colour; + +class WMovieView : public WTextbox +{ + public: + WMovieView(MovieInfo* movinfo); + void draw(); + + + private: + +}; + +#endif diff --git a/woptionpane.cc b/woptionpane.cc index 690ab79..fb5b456 100644 --- a/woptionpane.cc +++ b/woptionpane.cc @@ -68,7 +68,7 @@ void WOptionPane::addOptionLine(Option* option) WTextbox* tb = new WTextbox(); tb->setPosition(4, 4 + (numOptions * 30)); - tb->setSize(300, fontHeight); + tb->setSize(300, fontHeight + 6); tb->setText(tr(option->displayText)); tb->setTextPos(0, 0); add(tb); diff --git a/wpictureview.cc b/wpictureview.cc new file mode 100644 index 0000000..5418a2d --- /dev/null +++ b/wpictureview.cc @@ -0,0 +1,247 @@ +/* + Copyright 2005 Brian Walton (WTextBox) + Copyright 2014 Marten Richter (WPictureView) + + This file is part of VOMP. + + VOMP is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + VOMP is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with VOMP; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include "wpictureview.h" + +#include "colour.h" +#include "remote.h" +#include "osd.h" +#include "movieinfo.h" +#include "seriesinfo.h" +#include + +WPictureView::WPictureView(): +foreColour(DrawStyle::LIGHTTEXT) +{ + cur_scroll_line=0; + rem_scroll_line=0; + const_height=0; +} + +WPictureView::~WPictureView() +{ +} + + + +void WPictureView::setForegroundColour(const DrawStyle& fcolour) +{ + foreColour = fcolour; +} + +void WPictureView::draw() +{ + Boxx::draw(); + int fontHeight = getFontHeight(); + float ypos = cur_scroll_line * (fontHeight*8.f); + ypos = -ypos; + float height = 0; + + drawClippingRectangle(1,1,area.w-1,area.h-1); + + list::iterator itty=pictures.begin(); + while (itty!=pictures.end()) + { + // We now calculate the pictures in one row + list cur_pict; + float cur_width=0; + float max_height=const_height; + + + while (itty != pictures.end()) + { + if ((((*itty).w + cur_width+ 10.f) > area.w || const_height) && cur_pict.size() > 0) break; + cur_width += 10 + (*itty).w; + if (!const_height) max_height = max(max_height,(*itty).h); + cur_pict.push_back(&(*itty)); + itty++; + } + // ok now we have a list of pictures, let's draw them + list::iterator citty=cur_pict.begin(); + float xpos= (area.w - cur_width)*0.5f; + if (xpos < 0) xpos=0; + while (citty!=cur_pict.end()) + { + if (!const_height) { + drawTVMedia((*citty)->media, + xpos, ypos + max_height /*- (*citty)->h*/, + (*citty)->w, + /*(*citty)->h*/0.f,BottomLeft); + } else { + if (!(*citty)->banner) { + drawTVMedia((*citty)->media, + xpos+area.w*0.5f, ypos, + 0.f, + const_height,TopMiddle); + } else { + drawTVMedia((*citty)->media, + xpos+area.w*0.5f, ypos, + area.w-2.f, + 0.f,TopMiddle); + } + } + xpos += (*citty)->w + 10.f; + citty++; + } + ypos += max_height; + height += max_height; + bool caption1=false; + bool caption2=false; + + citty=cur_pict.begin(); + xpos= (area.w - cur_width)*0.5f; + if (xpos < 0) xpos=0; + while (citty!=cur_pict.end()) + { + if (!(*citty)->caption.empty()) + { + drawTextCentre((*citty)->caption.c_str(), xpos + (*citty)->w*0.5f, ypos, foreColour); + caption1 = true; + } + if (!(*citty)->caption2.empty()) + { + drawTextCentre((*citty)->caption2.c_str(), xpos + (*citty)->w*0.5f, ypos + fontHeight*1.f, foreColour); + caption2 = true; + } + xpos += (*citty)->w + 10.f; + citty++; + } + if (caption1) { + ypos +=fontHeight*1.f; + height += fontHeight*1.f; + } + if (caption2) { + ypos +=fontHeight*1.f; + height += fontHeight*1.f; + } + ypos +=fontHeight*1.f; + height += fontHeight*1.f; + + } + rem_scroll_line = ceil((height - area.h -cur_scroll_line * fontHeight*8.f)/fontHeight/8.f); + // Log::getInstance()->log("WActorGallery", Log::DEBUG, "TVMedia rml %d",rem_scroll_line); + drawClippingRectangle(0,0,0,0); + +} + +void WPictureView::addPicture(TVMediaInfo& pict, float pwidth, float pheight , bool banner, std::string caption, std::string caption2) +{ + pictures.push_back(Picture(pict,pwidth,pheight, banner, caption,caption2)); +} + +int WPictureView::handleCommand(int command) +{ + switch(command) + { + case Remote::DF_UP: + case Remote::UP: + { + if (cur_scroll_line > 0) + { + cur_scroll_line--; + rem_scroll_line++; + return 1; + } + else + { + return 4; // Signal return control to parent + } + } + case Remote::DF_DOWN: + case Remote::DOWN: + { + if (rem_scroll_line > 0) + { + cur_scroll_line++; + rem_scroll_line--; + return 1; + } else { + return 4; + } + } + case Remote::LEFT: + case Remote::RIGHT: + case Remote::DF_LEFT: + case Remote::DF_RIGHT: + { + return 5; + } + + } + + return 0; +} + +WActorGallery::WActorGallery(Actors& actors) +{ + Actors::iterator itty=actors.begin(); + float pixelaspect=Osd::getInstance()->getPixelAspect(); + while (itty!= actors.end()) + { + float aspect=((float)(*itty).thumb.height)/((float)(*itty).thumb.width)/pixelaspect; + float width= 100; + float height= aspect*width; + + //Log::getInstance()->log("WActorGallery", Log::DEBUG, "TVMedia %d %d %g", (*itty).thumb.width,(*itty).thumb.height,aspect); + addPicture((*itty).thumb.info, width, height, false,(*itty).name,"\""+(*itty).role+"\""); + itty++; + } +} + +WArtworkGallery::WArtworkGallery(MovieInfo& movie) +{ + float pixelaspect=Osd::getInstance()->getPixelAspect(); + addTVMedia(movie.fanart); + addTVMedia(movie.collectionFanart); + addTVMedia(movie.collectionPoster); + addTVMedia(movie.poster); + const_height=400; +} + +WArtworkGallery::WArtworkGallery(SeriesInfo& series) +{ + addTVMedia(series.seasonposter); + addTVMedia(series.episode.image); + + addTVMedias(series.banners, true); + addTVMedias(series.fanart); + addTVMedias(series.posters); + const_height=400; +} + +void WArtworkGallery::addTVMedias(TVMedias& medias, bool banner) +{ + if (medias.size()) { + TVMedias::iterator titty=medias.begin(); + while (titty!=medias.end()) + { + addTVMedia(*titty, banner); + titty++; + } + + } +} + +void WArtworkGallery::addTVMedia(TVMedia& media, bool banner) +{ + if (media.width) + addPicture(media.info, media.width, media.height, banner); +} diff --git a/wpictureview.h b/wpictureview.h new file mode 100644 index 0000000..272299a --- /dev/null +++ b/wpictureview.h @@ -0,0 +1,87 @@ +/* + Copyright 2005 Brian Walton (WTextBox) + Copyright 2014 Marten Richter (WPictureView) + + This file is part of VOMP. + + VOMP is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + VOMP is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with VOMP; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef WPICTUREVIEW_H +#define WPICTUREVIEW_H + +#include +#include +#include + +#include "defines.h" +#include "boxx.h" + +class Colour; + +class WPictureView : public Boxx +{ + public: + WPictureView(); + virtual ~WPictureView(); + void addPicture(TVMediaInfo& pict, float width, float height,bool banner=false, std::string caption ="", std::string caption2 =""); + void draw(); + void setForegroundColour(const DrawStyle& fcolour); + + + // if added as a pane + int handleCommand(int command); + + protected: + class Picture { + public: + Picture(TVMediaInfo tmedia,float width, float height, bool tbanner, std::string tcaption, std::string tcaption2){ + media=tmedia; caption=tcaption;caption2=tcaption2;w=width; h=height; banner=tbanner; + } + + TVMediaInfo media; + std::string caption; + std::string caption2; + float w; + float h; + bool banner; + }; + list pictures; + + DrawStyle foreColour; + unsigned int cur_scroll_line; + unsigned int rem_scroll_line; + unsigned int const_height; // if set only one per line +}; + +class WActorGallery : public WPictureView +{ +public: + WActorGallery(Actors& actors); + +}; + +class WArtworkGallery : public WPictureView +{ +public: + WArtworkGallery(MovieInfo& movie); + WArtworkGallery(SeriesInfo& series); +protected: + void addTVMedias(TVMedias& medias, bool banner=false); + void addTVMedia(TVMedia& media, bool banner=false); + +}; + +#endif diff --git a/wseriesview.cc b/wseriesview.cc new file mode 100644 index 0000000..4a28d3e --- /dev/null +++ b/wseriesview.cc @@ -0,0 +1,73 @@ +/* + Copyright 2014 Marten Richter + + This file is part of VOMP. + + VOMP is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + VOMP is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with VOMP; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include "wseriesview.h" +#include "i18n.h" +#include + + +WSeriesView::WSeriesView(SeriesInfo* series): +WTextbox(NULL) +{ + // portions from nopacity plugin by Louis Braun + if (series) + { + std::stringstream info; + info << tr("TheTVDB Information") << ":\n\n"; + + if (!series->episode.name.empty()) { + info << tr("Episode") << ": " << series->episode.name << " (" << tr("Season") << " " << series->episode.season << ", " << tr("Episode") << " " << series->episode.number << ")\n\n"; + } + if (!series->episode.overview.empty()) { + info << tr("Episode Overview") << ": " << series->episode.overview << "\n\n"; + } + if (!series->episode.firstAired.empty()) { + info << tr("First aired") << ": " << series->episode.firstAired << "\n\n"; + } + if (!series->episode.guestStars.empty()) { + info << tr("Guest Stars") << ": " << series->episode.guestStars << "\n\n"; + } + if (series->episode.rating > 0) { + info << tr("TheMovieDB Rating") << ": " << series->episode.rating << "\n\n"; + } + if (!series->overview.empty()) { + info << tr("Series Overview") << ": " << series->overview << "\n\n"; + } + if (!series->firstAired.empty()) { + info << tr("First aired") << ": " << series->firstAired << "\n\n"; + } + if (!series->genre.empty()) { + info << tr("Genre") << ": " << series->genre << "\n\n"; + } + if (!series->network.empty()) { + info << tr("Network") << ": " << series->network << "\n\n"; + } + if (series->rating > 0) { + info << tr("TheMovieDB Rating") << ": " << series->rating << "\n\n"; + } + if (!series->status.empty()) { + info << tr("Status") << ": " << series->status << "\n\n"; + } + setText(info.str().c_str()); + } else { + setText("This is a bug!"); + } + +} diff --git a/wseriesview.h b/wseriesview.h new file mode 100644 index 0000000..0b9f715 --- /dev/null +++ b/wseriesview.h @@ -0,0 +1,43 @@ +/* + Copyright 2014 Marten Richter + + This file is part of VOMP. + + VOMP is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + VOMP is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with VOMP; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef WSERIESVIEW_H +#define WSERIESIEW_H + +#include +#include + +#include "defines.h" +#include "wtextbox.h" +#include "seriesinfo.h" + +class Colour; + +class WSeriesView : public WTextbox +{ + public: + WSeriesView(SeriesInfo* seriesinfo); + + + private: + +}; + +#endif diff --git a/wtabbar.cc b/wtabbar.cc index a33bae7..044a90a 100644 --- a/wtabbar.cc +++ b/wtabbar.cc @@ -108,6 +108,7 @@ int WTabBar::handleCommand(int command) // 0 - not handled // 1 - handled - stop command here // 4 - handled - pane is returning control to here + // 5 - activate button bar and let button process the call, this for simple up and down scroll views // FIXME standardise these int paneRetCode = tabs[visiblePane].pane->handleCommand(command); @@ -128,6 +129,14 @@ int WTabBar::handleCommand(int command) if (visiblePane != tabs.size() - 1) symbolRight.nextColour = DrawStyle::SELECTHIGHLIGHT; draw(); return 1; + } else if (paneRetCode == 5) + { + buttonBarActive = true; + tabs[visiblePane].button->setActive(true); + if (visiblePane != 0) symbolLeft.nextColour = DrawStyle::SELECTHIGHLIGHT; + if (visiblePane != tabs.size() - 1) symbolRight.nextColour = DrawStyle::SELECTHIGHLIGHT; + draw(); + // no return! } } @@ -149,6 +158,8 @@ int WTabBar::handleCommand(int command) draw(); return 1; } + case Remote::UP: + case Remote::DF_UP: case Remote::DOWN: case Remote::DF_DOWN: { @@ -305,3 +316,17 @@ bool WTabBar::mouseLBDOWN(int x, int y) { return false; } +void WTabBar::activateFocus(bool active) +{ + if (active) + { + tabs[visiblePane].button->setActive(true); + buttonBarActive = true; + + } else { + tabs[visiblePane].button->setActive(false); + buttonBarActive = false; + + } +} + diff --git a/wtabbar.h b/wtabbar.h index db70ccd..bfd8d70 100644 --- a/wtabbar.h +++ b/wtabbar.h @@ -45,6 +45,7 @@ class WTabBar : public Boxx int handleCommand(int command); bool mouseMove(int x, int y) ; bool mouseLBDOWN(int x, int y); + void activateFocus(bool active); private: bool left(); diff --git a/wtextbox.cc b/wtextbox.cc index 048bec0..7cb6045 100644 --- a/wtextbox.cc +++ b/wtextbox.cc @@ -21,6 +21,7 @@ #include "wtextbox.h" #include "colour.h" +#include "remote.h" WTextbox::WTextbox(const char* ttext): foreColour(DrawStyle::LIGHTTEXT) @@ -37,6 +38,9 @@ foreColour(DrawStyle::LIGHTTEXT) paraMode = true; if (ttext) setText(ttext); + + cur_scroll_line=0; + rem_scroll_line=0; } WTextbox::~WTextbox() @@ -67,7 +71,7 @@ void WTextbox::draw() Boxx::draw(); if (text) { - if (paraMode) drawPara(text, textX, textY, foreColour); + if (paraMode) rem_scroll_line=drawPara(text, textX, textY, foreColour,cur_scroll_line); else drawText(text, textX, textY, foreColour); } } @@ -77,3 +81,46 @@ void WTextbox::setTextPos(int x, int y) textX = x; textY = y; } + +int WTextbox::handleCommand(int command) +{ + switch(command) + { + case Remote::DF_UP: + case Remote::UP: + { + if (cur_scroll_line > 0) + { + cur_scroll_line--; + rem_scroll_line++; + return 1; + } + else + { + return 4; // Signal return control to parent + } + } + case Remote::DF_DOWN: + case Remote::DOWN: + { + if (rem_scroll_line > 0) + { + cur_scroll_line++; + rem_scroll_line--; + return 1; + } else { + return 4; + } + } + case Remote::LEFT: + case Remote::RIGHT: + case Remote::DF_LEFT: + case Remote::DF_RIGHT: + { + return 5; + } + + } + + return 0; +} diff --git a/wtextbox.h b/wtextbox.h index cc80935..5003157 100644 --- a/wtextbox.h +++ b/wtextbox.h @@ -40,6 +40,9 @@ class WTextbox : public Boxx void setTextPos(int x, int y); // optional void setParaMode(bool mode); + // if added as a pane + int handleCommand(int command); + private: char* text; @@ -47,6 +50,8 @@ class WTextbox : public Boxx int textX; int textY; bool paraMode; + unsigned int cur_scroll_line; + unsigned int rem_scroll_line; }; #endif