]> git.vomp.tv Git - vompclient-marten.git/commitdiff
Normalize line endings
authorMarten Richter <marten.richter@freenet.de>
Mon, 5 Nov 2012 07:11:01 +0000 (08:11 +0100)
committerMarten Richter <marten.richter@freenet.de>
Mon, 5 Nov 2012 07:11:01 +0000 (08:11 +0100)
20 files changed:
vopts.cc
vradiorec.cc
vrecording.cc
vrecordinglist.cc
vteletextview.cc
vteletextview.h
vtimerlist.cc
vvideolivetv.cc
vvideomedia.cc
vvideorec.cc
vwelcome.cc
wbutton.cc
wjpeg.cc
wjpeg.h
wjpegcomplex.cc
wjpegcomplex.h
wjpegsimple.cc
wjpegsimple.h
wselectlist.cc
wselectlist.h

index 3ea90a40c7303df9b98b9dbc6fcb68cd26b594ef..64920d398b888b58df097b8abf1028e3618fc316 100644 (file)
--- a/vopts.cc
+++ b/vopts.cc
-/*\r
-    Copyright 2007 Chris Tallon\r
-\r
-    This file is part of VOMP.\r
-\r
-    VOMP is free software; you can redistribute it and/or modify\r
-    it under the terms of the GNU General Public License as published by\r
-    the Free Software Foundation; either version 2 of the License, or\r
-    (at your option) any later version.\r
-\r
-    VOMP is distributed in the hope that it will be useful,\r
-    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-    GNU General Public License for more details.\r
-\r
-    You should have received a copy of the GNU General Public License\r
-    along with VOMP; if not, write to the Free Software\r
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
-*/\r
-\r
-#include "vopts.h"\r
-\r
-#include "colour.h"\r
-#include "video.h"\r
-#include "audio.h"\r
-#include "remote.h"\r
-#include "boxstack.h"\r
-#include "woptionpane.h"\r
-#include "wremoteconfig.h"\r
-#include "log.h"\r
-#include "option.h"\r
-#include "vdr.h"\r
-#include "command.h"\r
-\r
-#ifdef VOMP_PLATTFORM_MVP\r
-#include "mediaoptions.h"\r
-#endif\r
-//#include "vdr.h"\r
-//#include "command.h"\r
-\r
-VOpts::VOpts()\r
-{\r
-  setTitleBarOn(1);\r
-  setTitleBarColour(DrawStyle::TITLEBARBACKGROUND);\r
-  setTitleText(tr("Options"));\r
-\r
-\r
-  setSize(520, 360);\r
-  createBuffer();\r
-  if (Video::getInstance()->getFormat() == Video::PAL)\r
-    setPosition(100, 110);\r
-  else\r
-    setPosition(90, 90);\r
-  \r
-  tabbar.setPosition(6, 32);\r
-  tabbar.setSize(getWidth() - 12, getHeight() - 34);\r
-  add(&tabbar);\r
-  \r
-  Option* option;\r
-  WOptionPane* wop;\r
-  \r
-  //  --- edit options start here\r
-  \r
-  static const char* options1[] = {"Old", "New"};\r
-\r
-  static const char* options5[] = {"Chop sides", "Letterbox"};\r
-  static const char* options6[] = {"On", "Off", "Last state"};\r
-  static const char* options7[] = {"All", "FTA only"};\r
-  static const char* options15[] = {"Alphabetical", "Chronological"};\r
-\r
-  static const char* options13[] = {"1024", "2048", "4096", "8192", "16384", "32768", "65536"};\r
-  static const char* options14[] = {"No", "Yes"};\r
-  // Get list of languages from VDR and construct options table\r
-  LangCode = VDR::getInstance()->getLanguageList();\r
-  options2 = new const char*[LangCode.size()];\r
-  options2keys = new const char*[LangCode.size()];\r
-  I18n::lang_code_list::const_iterator iter;\r
-  UINT LangNumber = 0;\r
-  for (iter = LangCode.begin(); iter != LangCode.end(); ++iter,++LangNumber)\r
-  {\r
-    options2[LangNumber] = iter->second.c_str();\r
-    options2keys[LangNumber] = iter->first.c_str();\r
-  }\r
-\r
-  numPanes = 4;\r
-  panes = new Boxx*[numPanes];\r
-
-  wop = new WOptionPane();\r
-  tabbar.addTab(tr("General"), wop);\r
-  panes[0] = wop;\r
-#ifdef MVP_REMOTE_TYPES\r
-  option = new Option(1, "Remote control type",      "General", "Remote type",           Option::TYPE_TEXT, 2, 0, 0, options1);\r
-  options.push_back(option);\r
-  wop->addOptionLine(option);\r
-#endif\r
-  option = new Option(2, "Language",                 "General", "LangCode",              Option::TYPE_KEYED_TEXT, LangCode.size(), 0, 0, options2, options2keys);\r
-  options.push_back(option);\r
-  wop->addOptionLine(option);\r
-\r
-\r
-  UINT suppconn = Video::getInstance()->getSupportedFormats();\r
-  if (suppconn) {\r
-         int defaultch = 0;\r
-         if (suppconn & Video::COMPOSITERGB) {\r
-                 defaultch = 0;\r
-                 options3.push_back("RGB+composite");\r
-                 options3keys.push_back("RGB+composite");\r
-         }\r
-         if (Video::SVIDEO & suppconn) {\r
-                 options3.push_back("S-Video");\r
-                 options3keys.push_back("S-Video");\r
-         }\r
-         if (Video::HDMI & suppconn) {\r
-                 defaultch = options3.size();\r
-                 options3.push_back("HDMI");\r
-                 options3keys.push_back("HDMI");\r
-         }\r
-         if (Video::HDMI3D & suppconn) {\r
-                 options3.push_back("HDMI3D");\r
-                 options3keys.push_back("HDMI3D");\r
-         }\r
-         option = new Option(3, "TV connection type", "TV", "Connection",\r
-                         Option::TYPE_KEYED_TEXT, options3.size(), defaultch, 0,\r
-                         &(options3[0]), &(options3keys[0]));\r
-\r
-         options.push_back(option);\r
-         wop->addOptionLine(option);\r
-  }\r
-\r
-  UINT suppformats = Video::getInstance()->supportedTVFormats();\r
-  if (suppformats) {\r
-         int defaultch = 0;\r
-         options16.push_back("NTSC");\r
-         options16keys.push_back("NTSC");\r
-         if (suppformats & Video::PAL) {\r
-                 defaultch = 1;\r
-                 options16.push_back("PAL");\r
-                 options16keys.push_back("PAL");\r
-         }\r
-         if (Video::NTSC_J & suppformats) {\r
-                 options16.push_back("NTSC-J");\r
-                 options16keys.push_back("NTSC-J");\r
-         }\r
-         if (Video::PAL_M & suppformats) {\r
-                 options16.push_back("PAL-M");\r
-                 options16keys.push_back("PAL-M");\r
-         }\r
-\r
-         option = new Option(16, "TV standard (needs restart)", "General", "Override Video Format",\r
-                         Option::TYPE_KEYED_TEXT, options16.size(), defaultch, 0,\r
-                         &(options16[0]), &(options16keys[0]));\r
-\r
-         options.push_back(option);\r
-         wop->addOptionLine(option);\r
-  }\r
-\r
-  UINT supptvsize=Video::getInstance()->supportedTVsize();\r
-  if (supptvsize) {\r
-         int defaultch=0;\r
-         options4.push_back("4:3");\r
-         options4keys.push_back("4:3");\r
-      if (Video::ASPECT16X9 & supptvsize) {\r
-         options4.push_back("16:9");\r
-         options4keys.push_back("16:9");\r
-         defaultch=1;\r
-      }\r
-      if (Video::ASPECT14X9 & supptvsize) {\r
-         options4.push_back("14:9");\r
-         options4keys.push_back("14:9");\r
-      }\r
-         option = new Option(4, "TV aspect ratio", "TV", "Aspect",\r
-                               Option::TYPE_KEYED_TEXT, options4.size(), defaultch, 0,\r
-                               &(options4[0]), &(options4keys[0]));\r
-         options.push_back(option);\r
-         wop->addOptionLine(option);\r
-  }\r
-\r
-  option = new Option(5, "16:9 on 4:3 display mode", "TV",      "Widemode",              Option::TYPE_TEXT, 2, 0, 0, options5);\r
-  options.push_back(option);\r
-  wop->addOptionLine(option);\r
-  option = new Option(6, "Power state after bootup", "General", "Power After Boot",      Option::TYPE_TEXT, 3, 0, 0, options6);\r
-  options.push_back(option);\r
-  wop->addOptionLine(option);\r
-  option = new Option(7, "Display channels",         "General", "Channels",              Option::TYPE_TEXT, 2, 0, 0, options7);\r
-  options.push_back(option);\r
-  wop->addOptionLine(option);\r
-  option = new Option(15, "Recordings sort order",   "General", "Recordings Sort Order", Option::TYPE_TEXT, 2, 0, 0, options15);\r
-  options.push_back(option);\r
-  wop->addOptionLine(option);\r
-\r
-  Remote::getInstance()->addOptionsToPanes(0,&options,wop);\r
-  Video::getInstance()->addOptionsToPanes(0,&options,wop);\r
-  Audio::getInstance()->addOptionsToPanes(0,&options,wop);\r
-\r
-    \r
-/*  WRemoteConfig* wrc = new WRemoteConfig();\r
-  tabbar.addTab(tr("Remote Control"), wrc);*/\r
-  Remote::getInstance()->addOptionPagesToWTB(&tabbar);\r
- // panes[1] = wrc;\r
-\r
-  Video::getInstance()->addOptionPagesToWTB(&tabbar);\r
-  Audio::getInstance()->addOptionPagesToWTB(&tabbar);\r
-#ifdef VOMP_PLATTFORM_MVP\r
-  MediaOptions::getInstance()->addOptionPagesToWTB(&tabbar);\r
-#endif\r
-\r
-\r
-  wop = new WOptionPane(); \r
-  tabbar.addTab(tr("Timers"), wop);\r
-  panes[1] = wop;\r
-  \r
-  option = new Option(9, "Default start margin (minutes)",  "Timers", "Start margin",  Option::TYPE_INT, 20, 5, 0, NULL);\r
-  options.push_back(option);\r
-  wop->addOptionLine(option);\r
-  option = new Option(10, "Default end margin (minutes)",   "Timers", "End margin",    Option::TYPE_INT, 20, 5, 0, NULL);\r
-  options.push_back(option);\r
-  wop->addOptionLine(option);\r
-  option = new Option(11, "Default priority",               "Timers", "Priority",      Option::TYPE_INT, 100, 99, 0, NULL);\r
-  options.push_back(option);\r
-  wop->addOptionLine(option);\r
-  option = new Option(12, "Default lifetime",               "Timers", "Lifetime",      Option::TYPE_INT, 100, 99, 0, NULL);\r
-  options.push_back(option);\r
-  wop->addOptionLine(option);\r
-\r
-  Remote::getInstance()->addOptionsToPanes(1,&options,wop);\r
-  Video::getInstance()->addOptionsToPanes(1,&options,wop);\r
-  Audio::getInstance()->addOptionsToPanes(1,&options,wop);\r
-\r
-    \r
-  wop = new WOptionPane(); \r
-  tabbar.addTab(tr("Advanced"), wop);\r
-  panes[2] = wop;\r
-  \r
-  option = new Option(8, "VDR-Pri 0=OK !See forums!",  "General",  "Live priority",      Option::TYPE_INT,  100, 0, 0, NULL);\r
-  options.push_back(option);\r
-  wop->addOptionLine(option);\r
-  option = new Option(13, "TCP receive window size",   "Advanced", "TCP receive window", Option::TYPE_TEXT, 7, /*1*/DEFAULT_TCP_WINDOWSIZENR, 0, options13);\r
-  options.push_back(option);\r
-  wop->addOptionLine(option);\r
-#ifdef PAL_WSS\r
-  option = new Option(14, "Use WSS (PAL only)",        "General",  "WSS",                Option::TYPE_TEXT, 2, 0, 0, options14);\r
-  options.push_back(option);\r
-  wop->addOptionLine(option);\r
-#endif\r
-\r
-  Remote::getInstance()->addOptionsToPanes(2,&options,wop);\r
-  Video::getInstance()->addOptionsToPanes(2,&options,wop);\r
-  Audio::getInstance()->addOptionsToPanes(2,&options,wop);\r
-}\r
-\r
-VOpts::~VOpts()\r
-{\r
- // for (int i = 0; i < numPanes; i++) delete panes[i]; //Move to TabBar, Marten\r
-  delete[] panes;\r
-\r
-  for(vector<Option*>::iterator j = options.begin(); j != options.end(); j++) delete *j;\r
-  delete[] options2;\r
-  delete[] options2keys;\r
-}\r
-\r
-int VOpts::handleCommand(int command)\r
-{\r
-  // either is active, handle back\r
-  if (command == Remote::BACK)\r
-  {\r
-    doSave();\r
-    return 4;\r
-  }\r
-  else\r
-  {\r
-    int retval = tabbar.handleCommand(command);\r
-    if (retval == 1)\r
-    {\r
-      BoxStack::getInstance()->update(this);\r
-      return 2;\r
-    }\r
-    else if (retval == 2)\r
-    {\r
-      // command was taken and actively ignored\r
-      return 2;\r
-    }\r
-    else\r
-    {\r
-      return 1; // ???\r
-    }\r
-  }\r
-}\r
-\r
-void VOpts::doSave()\r
-{\r
-  VDR* vdr = VDR::getInstance();\r
-\r
-  Remote::getInstance()->saveOptionstoServer(); //Remote\r
-  Video::getInstance()->saveOptionstoServer(); //Video\r
-  Audio::getInstance()->saveOptionstoServer(); //Remote\r
-#ifdef VOMP_PLATTFORM_MVP\r
-  MediaOptions::getInstance()->saveOptionstoServer(); //Media\r
-#endif\r
-\r
-  // Damn, and the dynamic idea was going *so* well...\r
-  //Whats about a check with typeid operator?\r
-  WOptionPane* wop;\r
-  wop = (WOptionPane*)panes[0];\r
-  wop->saveOpts();  \r
-  wop = (WOptionPane*)panes[1];\r
-  wop->saveOpts();  \r
-  wop = (WOptionPane*)panes[2];\r
-  wop->saveOpts();  \r
-\r
-\r
-  for (UINT i = 0; i < options.size(); i++)\r
-  {\r
-    if (options[i]->configChoice == options[i]->userSetChoice) continue; // no change\r
-\r
-    Log::getInstance()->log("Options", Log::DEBUG, "Option %i has changed", i);\r
-\r
-    // Save to vdr\r
-\r
-    if (options[i]->optionType == Option::TYPE_TEXT)\r
-    {\r
-      vdr->configSave(options[i]->configSection, options[i]->configKey, options[i]->options[options[i]->userSetChoice]);\r
-    }\r
-    else if (options[i]->optionType == Option::TYPE_KEYED_TEXT)\r
-    {\r
-      vdr->configSave(options[i]->configSection, options[i]->configKey, options[i]->optionkeys[options[i]->userSetChoice]);\r
-    }\r
-    else\r
-    {\r
-      char buffer[20];\r
-      sprintf(buffer, "%i", options[i]->userSetChoice);\r
-      vdr->configSave(options[i]->configSection, options[i]->configKey, buffer);\r
-    }\r
-    \r
-    // Set new setting\r
-    if (options[i]->opthandler == NULL) //Ok, noone else is handling this, we are doing it\r
-    {\r
-      switch(options[i]->id)\r
-      {\r
-        case 1:\r
-        {\r
-#ifdef MVP_REMOTE_TYPES\r
-          if (options[i]->userSetChoice == 1)\r
-          {\r
-            Log::getInstance()->log("Options", Log::DEBUG, "Setting New Remote");\r
-            Remote::getInstance()->setRemoteType(Remote::NEWREMOTE);\r
-          }\r
-          else\r
-          {\r
-            Log::getInstance()->log("Options", Log::DEBUG, "Setting Old Remote");\r
-            Remote::getInstance()->setRemoteType(Remote::OLDREMOTE);\r
-          }\r
-#endif\r
-          break;\r
-        }\r
-        case 2:\r
-        {\r
-          Message* m = new Message();\r
-          m->message = Message::CHANGE_LANGUAGE;\r
-          m->to = Command::getInstance();\r
-          Command::getInstance()->postMessageNoLock(m);\r
-          break;\r
-        }\r
-        case 3:\r
-        {\r
-               if (STRCASECMP(options[i]->optionkeys[options[i]->userSetChoice], "RGB+composite")==0)\r
-               {\r
-                       Log::getInstance()->log("Options", Log::DEBUG, "Setting RGB/Composite");\r
-                       Video::getInstance()->setConnection(Video::COMPOSITERGB);\r
-               }\r
-               else  if (STRCASECMP(options[i]->optionkeys[options[i]->userSetChoice], "S-Video")==0)\r
-               {\r
-                       Log::getInstance()->log("Options", Log::DEBUG, "Setting S-Video");\r
-                       Video::getInstance()->setConnection(Video::SVIDEO);\r
-               }\r
-               else  if (STRCASECMP(options[i]->optionkeys[options[i]->userSetChoice], "HDMI")==0)\r
-               {\r
-                       Log::getInstance()->log("Options", Log::DEBUG, "Setting HDMI");\r
-                       Video::getInstance()->setConnection(Video::HDMI);\r
-               }\r
-               else  if (STRCASECMP(options[i]->optionkeys[options[i]->userSetChoice], "HDMI3D")==0)\r
-               {\r
-                       Log::getInstance()->log("Options", Log::DEBUG, "Setting HDMI");\r
-                       Video::getInstance()->setConnection(Video::HDMI3D);\r
-               }\r
-               break;\r
-        }\r
-        case 4:\r
-        {\r
-          if (STRCASECMP(options[i]->optionkeys[options[i]->userSetChoice], "16:9")==0)\r
-          {\r
-            Log::getInstance()->log("Options", Log::DEBUG, "Setting 16:9 TV");\r
-            Video::getInstance()->setTVsize(Video::ASPECT16X9);\r
-          }\r
-          else  if (STRCASECMP(options[i]->optionkeys[options[i]->userSetChoice], "4:3")==0)\r
-          {\r
-            Log::getInstance()->log("Options", Log::DEBUG, "Setting 4:3 TV");\r
-            Video::getInstance()->setTVsize(Video::ASPECT4X3);\r
-          }\r
-          else  if (STRCASECMP(options[i]->optionkeys[options[i]->userSetChoice], "14:9")==0)\r
-          {\r
-                 Log::getInstance()->log("Options", Log::DEBUG, "Setting 14:9 TV");\r
-                 Video::getInstance()->setTVsize(Video::ASPECT14X9);\r
-          }\r
-          break;\r
-        }\r
-        case 5:\r
-        {\r
-          if (options[i]->userSetChoice == 1)\r
-          {\r
-            Log::getInstance()->log("Options", Log::DEBUG, "Setting letterbox");\r
-            Video::getInstance()->setMode(Video::LETTERBOX);\r
-          }\r
-          else\r
-          {\r
-            Log::getInstance()->log("Options", Log::DEBUG, "Setting chop-sides");\r
-            Video::getInstance()->setMode(Video::NORMAL);\r
-          }\r
-          break;\r
-        }\r
-        case 13:\r
-        {\r
-          size_t newTCPsize = 2048;\r
-          if (options[i]->userSetChoice == 0) newTCPsize = 1024;\r
-          else if (options[i]->userSetChoice == 1) newTCPsize = 2048;\r
-          else if (options[i]->userSetChoice == 2) newTCPsize = 4096;\r
-          else if (options[i]->userSetChoice == 3) newTCPsize = 8192;\r
-          else if (options[i]->userSetChoice == 4) newTCPsize = 16384;\r
-          else if (options[i]->userSetChoice == 5) newTCPsize = 32768;\r
-          else if (options[i]->userSetChoice == 6) newTCPsize = 65536;\r
-          Log::getInstance()->log("Options", Log::DEBUG, "Setting TCP window size %i", newTCPsize);\r
-          VDR::getInstance()->setReceiveWindow(newTCPsize);\r
-          break;\r
-        }\r
-      }\r
-    }\r
-    else\r
-    {\r
-      options[i]->opthandler->handleOptionChanges(options[i]);\r
-    }\r
-  }\r
-}\r
-\r
-void VOpts::processMessage(Message* m)\r
-{\r
-  if (m->message == Message::MOUSE_MOVE)\r
-  {\r
-    int x=(m->parameter>>16)-getScreenX();\r
-    int y=(m->parameter&0xFFFF)-getScreenY();\r
-    if (tabbar.mouseMove(x,y))\r
-    {\r
-      BoxStack::getInstance()->update(this);\r
-    }\r
-    \r
-  }\r
-  else if (m->message == Message::MOUSE_LBDOWN)\r
-  {\r
-    int x=(m->parameter>>16)-getScreenX();\r
-    int y=(m->parameter&0xFFFF)-getScreenY();\r
-    if (tabbar.mouseLBDOWN(x,y)) \r
-    {\r
-      BoxStack::getInstance()->update(this);\r
-    } \r
-    else if (x<0 || y <0 || x>(int)getWidth() || y>(int)getHeight())\r
-    {\r
-      BoxStack::getInstance()->handleCommand(Remote::BACK); //simulate cancel press\r
-    }\r
-  }\r
-}\r
-\r
+/*
+    Copyright 2007 Chris Tallon
+
+    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 "vopts.h"
+
+#include "colour.h"
+#include "video.h"
+#include "audio.h"
+#include "remote.h"
+#include "boxstack.h"
+#include "woptionpane.h"
+#include "wremoteconfig.h"
+#include "log.h"
+#include "option.h"
+#include "vdr.h"
+#include "command.h"
+
+#ifdef VOMP_PLATTFORM_MVP
+#include "mediaoptions.h"
+#endif
+//#include "vdr.h"
+//#include "command.h"
+
+VOpts::VOpts()
+{
+  setTitleBarOn(1);
+  setTitleBarColour(DrawStyle::TITLEBARBACKGROUND);
+  setTitleText(tr("Options"));
+
+
+  setSize(520, 360);
+  createBuffer();
+  if (Video::getInstance()->getFormat() == Video::PAL)
+    setPosition(100, 110);
+  else
+    setPosition(90, 90);
+  
+  tabbar.setPosition(6, 32);
+  tabbar.setSize(getWidth() - 12, getHeight() - 34);
+  add(&tabbar);
+  
+  Option* option;
+  WOptionPane* wop;
+  
+  //  --- edit options start here
+  
+  static const char* options1[] = {"Old", "New"};
+
+  static const char* options5[] = {"Chop sides", "Letterbox"};
+  static const char* options6[] = {"On", "Off", "Last state"};
+  static const char* options7[] = {"All", "FTA only"};
+  static const char* options15[] = {"Alphabetical", "Chronological"};
+
+  static const char* options13[] = {"1024", "2048", "4096", "8192", "16384", "32768", "65536"};
+  static const char* options14[] = {"No", "Yes"};
+  // Get list of languages from VDR and construct options table
+  LangCode = VDR::getInstance()->getLanguageList();
+  options2 = new const char*[LangCode.size()];
+  options2keys = new const char*[LangCode.size()];
+  I18n::lang_code_list::const_iterator iter;
+  UINT LangNumber = 0;
+  for (iter = LangCode.begin(); iter != LangCode.end(); ++iter,++LangNumber)
+  {
+    options2[LangNumber] = iter->second.c_str();
+    options2keys[LangNumber] = iter->first.c_str();
+  }
+
+  numPanes = 4;
+  panes = new Boxx*[numPanes];
+
+  wop = new WOptionPane();
+  tabbar.addTab(tr("General"), wop);
+  panes[0] = wop;
+#ifdef MVP_REMOTE_TYPES
+  option = new Option(1, "Remote control type",      "General", "Remote type",           Option::TYPE_TEXT, 2, 0, 0, options1);
+  options.push_back(option);
+  wop->addOptionLine(option);
+#endif
+  option = new Option(2, "Language",                 "General", "LangCode",              Option::TYPE_KEYED_TEXT, LangCode.size(), 0, 0, options2, options2keys);
+  options.push_back(option);
+  wop->addOptionLine(option);
+
+
+  UINT suppconn = Video::getInstance()->getSupportedFormats();
+  if (suppconn) {
+         int defaultch = 0;
+         if (suppconn & Video::COMPOSITERGB) {
+                 defaultch = 0;
+                 options3.push_back("RGB+composite");
+                 options3keys.push_back("RGB+composite");
+         }
+         if (Video::SVIDEO & suppconn) {
+                 options3.push_back("S-Video");
+                 options3keys.push_back("S-Video");
+         }
+         if (Video::HDMI & suppconn) {
+                 defaultch = options3.size();
+                 options3.push_back("HDMI");
+                 options3keys.push_back("HDMI");
+         }
+         if (Video::HDMI3D & suppconn) {
+                 options3.push_back("HDMI3D");
+                 options3keys.push_back("HDMI3D");
+         }
+         option = new Option(3, "TV connection type", "TV", "Connection",
+                         Option::TYPE_KEYED_TEXT, options3.size(), defaultch, 0,
+                         &(options3[0]), &(options3keys[0]));
+
+         options.push_back(option);
+         wop->addOptionLine(option);
+  }
+
+  UINT suppformats = Video::getInstance()->supportedTVFormats();
+  if (suppformats) {
+         int defaultch = 0;
+         options16.push_back("NTSC");
+         options16keys.push_back("NTSC");
+         if (suppformats & Video::PAL) {
+                 defaultch = 1;
+                 options16.push_back("PAL");
+                 options16keys.push_back("PAL");
+         }
+         if (Video::NTSC_J & suppformats) {
+                 options16.push_back("NTSC-J");
+                 options16keys.push_back("NTSC-J");
+         }
+         if (Video::PAL_M & suppformats) {
+                 options16.push_back("PAL-M");
+                 options16keys.push_back("PAL-M");
+         }
+
+         option = new Option(16, "TV standard (needs restart)", "General", "Override Video Format",
+                         Option::TYPE_KEYED_TEXT, options16.size(), defaultch, 0,
+                         &(options16[0]), &(options16keys[0]));
+
+         options.push_back(option);
+         wop->addOptionLine(option);
+  }
+
+  UINT supptvsize=Video::getInstance()->supportedTVsize();
+  if (supptvsize) {
+         int defaultch=0;
+         options4.push_back("4:3");
+         options4keys.push_back("4:3");
+      if (Video::ASPECT16X9 & supptvsize) {
+         options4.push_back("16:9");
+         options4keys.push_back("16:9");
+         defaultch=1;
+      }
+      if (Video::ASPECT14X9 & supptvsize) {
+         options4.push_back("14:9");
+         options4keys.push_back("14:9");
+      }
+         option = new Option(4, "TV aspect ratio", "TV", "Aspect",
+                               Option::TYPE_KEYED_TEXT, options4.size(), defaultch, 0,
+                               &(options4[0]), &(options4keys[0]));
+         options.push_back(option);
+         wop->addOptionLine(option);
+  }
+
+  option = new Option(5, "16:9 on 4:3 display mode", "TV",      "Widemode",              Option::TYPE_TEXT, 2, 0, 0, options5);
+  options.push_back(option);
+  wop->addOptionLine(option);
+  option = new Option(6, "Power state after bootup", "General", "Power After Boot",      Option::TYPE_TEXT, 3, 0, 0, options6);
+  options.push_back(option);
+  wop->addOptionLine(option);
+  option = new Option(7, "Display channels",         "General", "Channels",              Option::TYPE_TEXT, 2, 0, 0, options7);
+  options.push_back(option);
+  wop->addOptionLine(option);
+  option = new Option(15, "Recordings sort order",   "General", "Recordings Sort Order", Option::TYPE_TEXT, 2, 0, 0, options15);
+  options.push_back(option);
+  wop->addOptionLine(option);
+
+  Remote::getInstance()->addOptionsToPanes(0,&options,wop);
+  Video::getInstance()->addOptionsToPanes(0,&options,wop);
+  Audio::getInstance()->addOptionsToPanes(0,&options,wop);
+
+    
+/*  WRemoteConfig* wrc = new WRemoteConfig();
+  tabbar.addTab(tr("Remote Control"), wrc);*/
+  Remote::getInstance()->addOptionPagesToWTB(&tabbar);
+ // panes[1] = wrc;
+
+  Video::getInstance()->addOptionPagesToWTB(&tabbar);
+  Audio::getInstance()->addOptionPagesToWTB(&tabbar);
+#ifdef VOMP_PLATTFORM_MVP
+  MediaOptions::getInstance()->addOptionPagesToWTB(&tabbar);
+#endif
+
+
+  wop = new WOptionPane(); 
+  tabbar.addTab(tr("Timers"), wop);
+  panes[1] = wop;
+  
+  option = new Option(9, "Default start margin (minutes)",  "Timers", "Start margin",  Option::TYPE_INT, 20, 5, 0, NULL);
+  options.push_back(option);
+  wop->addOptionLine(option);
+  option = new Option(10, "Default end margin (minutes)",   "Timers", "End margin",    Option::TYPE_INT, 20, 5, 0, NULL);
+  options.push_back(option);
+  wop->addOptionLine(option);
+  option = new Option(11, "Default priority",               "Timers", "Priority",      Option::TYPE_INT, 100, 99, 0, NULL);
+  options.push_back(option);
+  wop->addOptionLine(option);
+  option = new Option(12, "Default lifetime",               "Timers", "Lifetime",      Option::TYPE_INT, 100, 99, 0, NULL);
+  options.push_back(option);
+  wop->addOptionLine(option);
+
+  Remote::getInstance()->addOptionsToPanes(1,&options,wop);
+  Video::getInstance()->addOptionsToPanes(1,&options,wop);
+  Audio::getInstance()->addOptionsToPanes(1,&options,wop);
+
+    
+  wop = new WOptionPane(); 
+  tabbar.addTab(tr("Advanced"), wop);
+  panes[2] = wop;
+  
+  option = new Option(8, "VDR-Pri 0=OK !See forums!",  "General",  "Live priority",      Option::TYPE_INT,  100, 0, 0, NULL);
+  options.push_back(option);
+  wop->addOptionLine(option);
+  option = new Option(13, "TCP receive window size",   "Advanced", "TCP receive window", Option::TYPE_TEXT, 7, /*1*/DEFAULT_TCP_WINDOWSIZENR, 0, options13);
+  options.push_back(option);
+  wop->addOptionLine(option);
+#ifdef PAL_WSS
+  option = new Option(14, "Use WSS (PAL only)",        "General",  "WSS",                Option::TYPE_TEXT, 2, 0, 0, options14);
+  options.push_back(option);
+  wop->addOptionLine(option);
+#endif
+
+  Remote::getInstance()->addOptionsToPanes(2,&options,wop);
+  Video::getInstance()->addOptionsToPanes(2,&options,wop);
+  Audio::getInstance()->addOptionsToPanes(2,&options,wop);
+}
+
+VOpts::~VOpts()
+{
+ // for (int i = 0; i < numPanes; i++) delete panes[i]; //Move to TabBar, Marten
+  delete[] panes;
+
+  for(vector<Option*>::iterator j = options.begin(); j != options.end(); j++) delete *j;
+  delete[] options2;
+  delete[] options2keys;
+}
+
+int VOpts::handleCommand(int command)
+{
+  // either is active, handle back
+  if (command == Remote::BACK)
+  {
+    doSave();
+    return 4;
+  }
+  else
+  {
+    int retval = tabbar.handleCommand(command);
+    if (retval == 1)
+    {
+      BoxStack::getInstance()->update(this);
+      return 2;
+    }
+    else if (retval == 2)
+    {
+      // command was taken and actively ignored
+      return 2;
+    }
+    else
+    {
+      return 1; // ???
+    }
+  }
+}
+
+void VOpts::doSave()
+{
+  VDR* vdr = VDR::getInstance();
+
+  Remote::getInstance()->saveOptionstoServer(); //Remote
+  Video::getInstance()->saveOptionstoServer(); //Video
+  Audio::getInstance()->saveOptionstoServer(); //Remote
+#ifdef VOMP_PLATTFORM_MVP
+  MediaOptions::getInstance()->saveOptionstoServer(); //Media
+#endif
+
+  // Damn, and the dynamic idea was going *so* well...
+  //Whats about a check with typeid operator?
+  WOptionPane* wop;
+  wop = (WOptionPane*)panes[0];
+  wop->saveOpts();  
+  wop = (WOptionPane*)panes[1];
+  wop->saveOpts();  
+  wop = (WOptionPane*)panes[2];
+  wop->saveOpts();  
+
+
+  for (UINT i = 0; i < options.size(); i++)
+  {
+    if (options[i]->configChoice == options[i]->userSetChoice) continue; // no change
+
+    Log::getInstance()->log("Options", Log::DEBUG, "Option %i has changed", i);
+
+    // Save to vdr
+
+    if (options[i]->optionType == Option::TYPE_TEXT)
+    {
+      vdr->configSave(options[i]->configSection, options[i]->configKey, options[i]->options[options[i]->userSetChoice]);
+    }
+    else if (options[i]->optionType == Option::TYPE_KEYED_TEXT)
+    {
+      vdr->configSave(options[i]->configSection, options[i]->configKey, options[i]->optionkeys[options[i]->userSetChoice]);
+    }
+    else
+    {
+      char buffer[20];
+      sprintf(buffer, "%i", options[i]->userSetChoice);
+      vdr->configSave(options[i]->configSection, options[i]->configKey, buffer);
+    }
+    
+    // Set new setting
+    if (options[i]->opthandler == NULL) //Ok, noone else is handling this, we are doing it
+    {
+      switch(options[i]->id)
+      {
+        case 1:
+        {
+#ifdef MVP_REMOTE_TYPES
+          if (options[i]->userSetChoice == 1)
+          {
+            Log::getInstance()->log("Options", Log::DEBUG, "Setting New Remote");
+            Remote::getInstance()->setRemoteType(Remote::NEWREMOTE);
+          }
+          else
+          {
+            Log::getInstance()->log("Options", Log::DEBUG, "Setting Old Remote");
+            Remote::getInstance()->setRemoteType(Remote::OLDREMOTE);
+          }
+#endif
+          break;
+        }
+        case 2:
+        {
+          Message* m = new Message();
+          m->message = Message::CHANGE_LANGUAGE;
+          m->to = Command::getInstance();
+          Command::getInstance()->postMessageNoLock(m);
+          break;
+        }
+        case 3:
+        {
+               if (STRCASECMP(options[i]->optionkeys[options[i]->userSetChoice], "RGB+composite")==0)
+               {
+                       Log::getInstance()->log("Options", Log::DEBUG, "Setting RGB/Composite");
+                       Video::getInstance()->setConnection(Video::COMPOSITERGB);
+               }
+               else  if (STRCASECMP(options[i]->optionkeys[options[i]->userSetChoice], "S-Video")==0)
+               {
+                       Log::getInstance()->log("Options", Log::DEBUG, "Setting S-Video");
+                       Video::getInstance()->setConnection(Video::SVIDEO);
+               }
+               else  if (STRCASECMP(options[i]->optionkeys[options[i]->userSetChoice], "HDMI")==0)
+               {
+                       Log::getInstance()->log("Options", Log::DEBUG, "Setting HDMI");
+                       Video::getInstance()->setConnection(Video::HDMI);
+               }
+               else  if (STRCASECMP(options[i]->optionkeys[options[i]->userSetChoice], "HDMI3D")==0)
+               {
+                       Log::getInstance()->log("Options", Log::DEBUG, "Setting HDMI");
+                       Video::getInstance()->setConnection(Video::HDMI3D);
+               }
+               break;
+        }
+        case 4:
+        {
+          if (STRCASECMP(options[i]->optionkeys[options[i]->userSetChoice], "16:9")==0)
+          {
+            Log::getInstance()->log("Options", Log::DEBUG, "Setting 16:9 TV");
+            Video::getInstance()->setTVsize(Video::ASPECT16X9);
+          }
+          else  if (STRCASECMP(options[i]->optionkeys[options[i]->userSetChoice], "4:3")==0)
+          {
+            Log::getInstance()->log("Options", Log::DEBUG, "Setting 4:3 TV");
+            Video::getInstance()->setTVsize(Video::ASPECT4X3);
+          }
+          else  if (STRCASECMP(options[i]->optionkeys[options[i]->userSetChoice], "14:9")==0)
+          {
+                 Log::getInstance()->log("Options", Log::DEBUG, "Setting 14:9 TV");
+                 Video::getInstance()->setTVsize(Video::ASPECT14X9);
+          }
+          break;
+        }
+        case 5:
+        {
+          if (options[i]->userSetChoice == 1)
+          {
+            Log::getInstance()->log("Options", Log::DEBUG, "Setting letterbox");
+            Video::getInstance()->setMode(Video::LETTERBOX);
+          }
+          else
+          {
+            Log::getInstance()->log("Options", Log::DEBUG, "Setting chop-sides");
+            Video::getInstance()->setMode(Video::NORMAL);
+          }
+          break;
+        }
+        case 13:
+        {
+          size_t newTCPsize = 2048;
+          if (options[i]->userSetChoice == 0) newTCPsize = 1024;
+          else if (options[i]->userSetChoice == 1) newTCPsize = 2048;
+          else if (options[i]->userSetChoice == 2) newTCPsize = 4096;
+          else if (options[i]->userSetChoice == 3) newTCPsize = 8192;
+          else if (options[i]->userSetChoice == 4) newTCPsize = 16384;
+          else if (options[i]->userSetChoice == 5) newTCPsize = 32768;
+          else if (options[i]->userSetChoice == 6) newTCPsize = 65536;
+          Log::getInstance()->log("Options", Log::DEBUG, "Setting TCP window size %i", newTCPsize);
+          VDR::getInstance()->setReceiveWindow(newTCPsize);
+          break;
+        }
+      }
+    }
+    else
+    {
+      options[i]->opthandler->handleOptionChanges(options[i]);
+    }
+  }
+}
+
+void VOpts::processMessage(Message* m)
+{
+  if (m->message == Message::MOUSE_MOVE)
+  {
+    int x=(m->parameter>>16)-getScreenX();
+    int y=(m->parameter&0xFFFF)-getScreenY();
+    if (tabbar.mouseMove(x,y))
+    {
+      BoxStack::getInstance()->update(this);
+    }
+    
+  }
+  else if (m->message == Message::MOUSE_LBDOWN)
+  {
+    int x=(m->parameter>>16)-getScreenX();
+    int y=(m->parameter&0xFFFF)-getScreenY();
+    if (tabbar.mouseLBDOWN(x,y)) 
+    {
+      BoxStack::getInstance()->update(this);
+    } 
+    else if (x<0 || y <0 || x>(int)getWidth() || y>(int)getHeight())
+    {
+      BoxStack::getInstance()->handleCommand(Remote::BACK); //simulate cancel press
+    }
+  }
+}
+
index 566274e2953d0a5691188b0a16eca335a70c5f58..1dc28a7d797053016e0f3d12e08fb86d741bcd1a 100644 (file)
-/*\r
-    Copyright 2004-2006 Chris Tallon\r
-\r
-    This file is part of VOMP.\r
-\r
-    VOMP is free software; you can redistribute it and/or modify\r
-    it under the terms of the GNU General Public License as published by\r
-    the Free Software Foundation; either version 2 of the License, or\r
-    (at your option) any later version.\r
-\r
-    VOMP is distributed in the hope that it will be useful,\r
-    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-    GNU General Public License for more details.\r
-\r
-    You should have received a copy of the GNU General Public License\r
-    along with VOMP; if not, write to the Free Software\r
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
-*/\r
-\r
-#include "vradiorec.h"\r
-\r
-#include "command.h"\r
-#include "osd.h"\r
-#include "player.h"\r
-#include "wsymbol.h"\r
-#include "recording.h"\r
-#include "message.h"\r
-#include "vdr.h"\r
-#include "video.h"\r
-#include "timers.h"\r
-#include "playerradio.h"\r
-#include "boxstack.h"\r
-#include "remote.h"\r
-#include "vinfo.h"\r
-#include "i18n.h"\r
-#include "log.h"\r
-\r
-VRadioRec::VRadioRec(Recording* rec)\r
-{\r
-  boxstack = BoxStack::getInstance();\r
-  vdr = VDR::getInstance();\r
-  video = Video::getInstance();\r
-  timers = Timers::getInstance();\r
-  myRec = rec;\r
-  playing = false;\r
-  startMargin = 0;\r
-  endMargin = 0;\r
-\r
-  player = new PlayerRadio(Command::getInstance(), this);\r
-\r
-  char* cstartMargin = vdr->configLoad("Timers", "Start margin");\r
-  char* cendMargin = vdr->configLoad("Timers", "End margin");\r
-  if (!cstartMargin)\r
-  {\r
-    startMargin = 300; // 5 mins default\r
-  }\r
-  else\r
-  {\r
-    startMargin = atoi(cstartMargin) * 60;\r
-    delete[] cstartMargin;\r
-  }\r
-\r
-  if (!cendMargin)\r
-  {\r
-    endMargin = 300; // 5 mins default\r
-  }\r
-  else\r
-  {\r
-    endMargin = atoi(cendMargin) * 60;\r
-    delete[] cendMargin;\r
-  }\r
-\r
-  Log::getInstance()->log("VRadioRec", Log::DEBUG, "SM: %u EM: %u", startMargin, endMargin);\r
-\r
-  setSize(video->getScreenWidth(), video->getScreenHeight());\r
-  createBuffer();\r
-  setPosition(0, 0);\r
-\r
-  barRegion.x = 0;\r
-  barRegion.y = video->getScreenHeight() - 58;   // FIXME, need to be - 1? and below?\r
-  barRegion.w = video->getScreenWidth();\r
-  barRegion.h = 58;\r
-\r
-  clocksRegion.x = barRegion.x + 140;\r
-  clocksRegion.y = barRegion.y + 12;\r
-  clocksRegion.w = 170;\r
-  clocksRegion.h = getFontHeight();\r
-\r
-\r
-  barBlue.set(0, 0, 150, 150);\r
-\r
-  barShowing = false;\r
-}\r
-\r
-void VRadioRec::preDelete()\r
-{\r
-  timers->cancelTimer(this, 1);\r
-  timers->cancelTimer(this, 2);\r
-}\r
-\r
-VRadioRec::~VRadioRec()\r
-{\r
-  if (playing) stopPlay();\r
-\r
-\r
-  // kill recInfo in case resumePoint has changed (likely)\r
-  myRec->dropRecInfo();\r
-  // FIXME - do this properly - save the resume point back to the server manually and update\r
-  // rec->recInfo->resumePoint - this will fix the ~10s offset problem as well\r
-}\r
-\r
-void VRadioRec::draw()\r
-{\r
-  fillColour(DrawStyle::BLACK);\r
-}\r
-\r
-void VRadioRec::go()\r
-{\r
-  Log::getInstance()->log("VRadioRec", Log::DEBUG, "Starting stream: %s", myRec->getFileName());\r
-  ULONG lengthFrames = 0;\r
-  bool isPesRecording;\r
-  ULLONG lengthBytes = vdr->streamRecording(myRec->getFileName(), &lengthFrames, &isPesRecording);\r
-  myRec->IsPesRecording = isPesRecording;\r
-\r
-  bool cantStart = false;\r
-\r
-  if (!lengthBytes) cantStart = true;\r
-  else if (!player->init(lengthBytes, lengthFrames, myRec->IsPesRecording)) cantStart = true;\r
-  else\r
-  {\r
-    doBar(0);\r
-  //  player->setStartBytes(startBytes);\r
-    player->play();\r
-    playing = true;\r
-  }\r
-\r
-  if (cantStart)\r
-  {\r
-    stopPlay(); // clean up\r
-\r
-    if (!vdr->isConnected())\r
-    {\r
-      Command::getInstance()->connectionLost();\r
-      return;\r
-    }\r
-\r
-    Message* m = new Message();\r
-    m->message = Message::CLOSE_ME;\r
-    m->from = this;\r
-    m->to = boxstack;\r
-    Command::getInstance()->postMessageNoLock(m);\r
-\r
-    VInfo* vi = new VInfo();\r
-    vi->setSize(400, 150);\r
-    vi->createBuffer();\r
-    if (video->getFormat() == Video::PAL)\r
-      vi->setPosition(170, 200);\r
-    else\r
-      vi->setPosition(160, 150);\r
-    vi->setExitable();\r
-    vi->setBorderOn(1);\r
-    vi->setTitleBarOn(0);\r
-    vi->setOneLiner(tr("Error playing recording"));\r
-    vi->draw();\r
-\r
-    m = new Message();\r
-    m->message = Message::ADD_VIEW;\r
-    m->to = boxstack;\r
-    m->parameter = (ULONG)vi;\r
-    Command::getInstance()->postMessageNoLock(m);\r
-  }\r
-}\r
-\r
-int VRadioRec::handleCommand(int command)\r
-{\r
-  switch(command)\r
-  {\r
-    case Remote::PLAY:\r
-    {\r
-      player->play();\r
-      doBar(0);\r
-      return 2;\r
-    }\r
-    case Remote::PLAYPAUSE:\r
-    {\r
-       player->playpause();\r
-        doBar(0);\r
-        return 2;\r
-    }\r
-\r
-    case Remote::STOP:\r
-    case Remote::BACK:\r
-    case Remote::MENU:\r
-    {\r
-      if (playing) stopPlay();\r
-      return 4;\r
-    }\r
-    case Remote::PAUSE:\r
-    {\r
-      player->pause();\r
-      doBar(0);\r
-      return 2;\r
-    }\r
-    case Remote::SKIPFORWARD:\r
-    {\r
-      doBar(3);\r
-      player->skipForward(60);\r
-      return 2;\r
-    }\r
-    case Remote::SKIPBACK:\r
-    {\r
-      doBar(4);\r
-      player->skipBackward(60);\r
-      return 2;\r
-    }\r
-    case Remote::YELLOW:\r
-    {\r
-      doBar(2);\r
-      player->skipBackward(10);\r
-      return 2;\r
-    }\r
-    case Remote::BLUE:\r
-    {\r
-      doBar(1);\r
-      player->skipForward(10);\r
-      return 2;\r
-    }\r
-    case Remote::OK:\r
-    {\r
-      if (barShowing) removeBar();\r
-      else doBar(0);\r
-      return 2;\r
-    }\r
-\r
-    case Remote::ZERO:  player->jumpToPercent(0);  doBar(0);  return 2;\r
-    case Remote::ONE:   player->jumpToPercent(10); doBar(0);  return 2;\r
-    case Remote::TWO:   player->jumpToPercent(20); doBar(0);  return 2;\r
-    case Remote::THREE: player->jumpToPercent(30); doBar(0);  return 2;\r
-    case Remote::FOUR:  player->jumpToPercent(40); doBar(0);  return 2;\r
-    case Remote::FIVE:  player->jumpToPercent(50); doBar(0);  return 2;\r
-    case Remote::SIX:   player->jumpToPercent(60); doBar(0);  return 2;\r
-    case Remote::SEVEN: player->jumpToPercent(70); doBar(0);  return 2;\r
-    case Remote::EIGHT: player->jumpToPercent(80); doBar(0);  return 2;\r
-    case Remote::NINE:  player->jumpToPercent(90); doBar(0);  return 2;\r
-\r
-#ifdef DEV\r
-    case Remote::RED:\r
-    {\r
-      //player->test1();\r
-\r
-      return 2;\r
-    }\r
-    case Remote::GREEN:\r
-    {\r
-      //player->test2();\r
-      return 2;\r
-    }\r
-#endif\r
-\r
-  }\r
-\r
-  return 1;\r
-}\r
-\r
-void VRadioRec::processMessage(Message* m)\r
-{\r
-  if (m->message == Message::MOUSE_LBDOWN)\r
-  {\r
-    int x=(m->parameter>>16)-(int)getScreenX();\r
-    int y=(m->parameter&0xFFFF)-(int)getScreenY();\r
-    if (!barShowing)\r
-    {\r
-      boxstack->handleCommand(Remote::OK); //simulate rok press\r
-    }\r
-    else if ((int)barRegion.x<=x && (int)barRegion.y<=y && ((int)barRegion.x+(int)barRegion.w)>=x\r
-             &&  ((int)barRegion.y+(int)barRegion.h)>=y)\r
-    {\r
-      int progBarXbase = barRegion.x + 300;\r
-      if (x>=(int)barRegion.x + progBarXbase + 24\r
-        && x<=(int)barRegion.x + progBarXbase + 4 + 302\r
-        && y>=(int)barRegion.y + 12 - 2\r
-        && y<=(int)barRegion.y + 12 - 2+28)\r
-      {\r
-        int cx=x-(barRegion.x + progBarXbase + 4);\r
-        double percent=((double)cx)/302.*100.;\r
-        player->jumpToPercent(percent);\r
-        doBar(3);\r
-        return;\r
-        //  int progressWidth = 302 * currentFrameNum / lengthFrames;\r
-        //  rectangle(barRegion.x + progBarXbase + 4, barRegion.y + 16, progressWidth, 16, DrawStyle::SELECTHIGHLIGHT);\r
-      }\r
-    }\r
-    else\r
-    {\r
-      boxstack->handleCommand(Remote::OK); //simulate rok press\r
-    }\r
-  }\r
-  else if (m->message == Message::PLAYER_EVENT)\r
-  {\r
-    if (m->from != player) return;\r
-\r
-    Log::getInstance()->log("VRadioRec", Log::DEBUG, "Message received");\r
-\r
-    switch(m->parameter)\r
-    {\r
-      case Player::CONNECTION_LOST: // connection lost detected\r
-      {\r
-        // I can't handle this, send it to command\r
-        Message* m2 = new Message();\r
-        m2->to = Command::getInstance();\r
-        m2->message = Message::CONNECTION_LOST;\r
-        Command::getInstance()->postMessageNoLock(m2);\r
-        break;\r
-      }\r
-      case Player::STOP_PLAYBACK:\r
-      {\r
-        // FIXME Obselete ish - improve this\r
-        Message* m2 = new Message(); // Must be done after this thread finishes, and must break into master mutex\r
-        m2->to = Command::getInstance();\r
-        m2->message = Message::STOP_PLAYBACK;\r
-        Command::getInstance()->postMessageNoLock(m2);\r
-        break;\r
-      }\r
-    }\r
-  }\r
-}\r
-\r
-void VRadioRec::stopPlay()\r
-{\r
-  Log::getInstance()->log("VRadioRec", Log::DEBUG, "Pre stopPlay");\r
-\r
-  removeBar();\r
-  player->stop();\r
-  vdr->stopStreaming();\r
-  delete player;\r
-\r
-  playing = false;\r
-\r
-  if (!vdr->isConnected()) { Command::getInstance()->connectionLost(); return; }\r
-  Log::getInstance()->log("VRadioRec", Log::DEBUG, "Post stopPlay");\r
-}\r
-\r
-void VRadioRec::doBar(int action)\r
-{\r
-  barShowing = true;\r
-\r
-  rectangle(barRegion, barBlue);\r
-\r
-  /* Work out what to display - choices:\r
-\r
-  Playing  >\r
-  Paused   ||\r
-\r
-  Specials, informed by parameter\r
-\r
-  Skip forward 10s    >|\r
-  Skip backward 10s   |<\r
-  Skip forward 1m     >>|\r
-  Skip backward 1m    |<<\r
-\r
-  */\r
-\r
-  WSymbol w;\r
-  TEMPADD(&w);\r
-  w.nextSymbol = 0;\r
-  w.setPosition(barRegion.x + 66, barRegion.y + 16);\r
-\r
-  UCHAR playerState = 0;\r
-\r
-  if (action)\r
-  {\r
-    if (action == 1)       w.nextSymbol = WSymbol::SKIPFORWARD;\r
-    else if (action == 2)  w.nextSymbol = WSymbol::SKIPBACK;\r
-    else if (action == 3)  w.nextSymbol = WSymbol::SKIPFORWARD2;\r
-    else if (action == 4)  w.nextSymbol = WSymbol::SKIPBACK2;\r
-  }\r
-  else\r
-  {\r
-    playerState = player->getState();\r
-    if (playerState == Player::S_PAUSE_P)      w.nextSymbol = WSymbol::PAUSE;\r
-    else if (playerState == Player::S_PAUSE_I) w.nextSymbol = WSymbol::PAUSE;\r
-    else                                       w.nextSymbol = WSymbol::PLAY;\r
-  }\r
-\r
-  w.draw();\r
-\r
-  drawBarClocks();\r
-\r
-  BoxStack::getInstance()->update(this, &barRegion);\r
-\r
-  timers->setTimerD(this, 1, 4); // only set the getridofbar timer if not ffwd/fbwd\r
-  timers->setTimerD(this, 2, 0, 200000000);\r
-}\r
-\r
-void VRadioRec::timercall(int clientReference)\r
-{\r
-  switch(clientReference)\r
-  {\r
-    case 1:\r
-    {\r
-      // Remove bar\r
-      removeBar();\r
-      break;\r
-    }\r
-    case 2:\r
-    {\r
-      // Update clock\r
-      if (!barShowing) break;\r
-      drawBarClocks();\r
-      boxstack->update(this, &barRegion);\r
-      \r
-      timers->setTimerD(this, 2, 0, 200000000);\r
-      break;\r
-    }\r
-  }\r
-}\r
-\r
-void VRadioRec::drawBarClocks()\r
-{\r
-  Log* logger = Log::getInstance();\r
-  logger->log("VRadioRec", Log::DEBUG, "Draw bar clocks");\r
-\r
-  // Draw RTC\r
-  // Blank the area first\r
-  rectangle(barRegion.x + 624, barRegion.y + 12, 60, 30, barBlue);\r
-  char timeString[20];\r
-  time_t t;\r
-  time(&t);\r
-  struct tm* tms = localtime(&t);\r
-  strftime(timeString, 19, "%H:%M", tms);\r
-  drawText(timeString, barRegion.x + 624, barRegion.y + 12, DrawStyle::LIGHTTEXT);\r
-\r
-  // Draw clocks\r
-\r
-  rectangle(clocksRegion, barBlue);\r
-\r
-/*\r
-  ULONG currentFrameNum = player->getCurrentFrameNum();\r
-  ULONG lengthFrames;\r
-  if (myRec->recInfo->timerEnd > time(NULL))\r
-  {\r
-    // chasing playback\r
-    // Work out an approximate length in frames (good to 1s...)\r
-    lengthFrames = (myRec->recInfo->timerEnd - myRec->recInfo->timerStart) * video->getFPS();\r
-  }\r
-  else\r
-  {\r
-//    lengthFrames = player->getLengthFrames();\r
-    lengthFrames = 0;\r
-  }\r
-\r
-  hmsf currentFrameHMSF = video->framesToHMSF(currentFrameNum);\r
-  hmsf lengthHMSF = video->framesToHMSF(lengthFrames);\r
-\r
-  char buffer[100];\r
-  if (currentFrameNum >= lengthFrames)\r
-  {\r
-    strcpy(buffer, "-:--:-- / -:--:--");\r
-  }\r
-  else\r
-  {\r
-    SNPRINTF(buffer, 99, "%01i:%02i:%02i / %01i:%02i:%02i", currentFrameHMSF.hours, currentFrameHMSF.minutes, currentFrameHMSF.seconds, lengthHMSF.hours, lengthHMSF.minutes, lengthHMSF.seconds);\r
-    logger->log("VRadioRec", Log::DEBUG, buffer);\r
-  }\r
-*/\r
-\r
-  ULONG currentSeconds = player->getCurrentSeconds();\r
-  ULONG lengthSeconds = player->getLengthSeconds();\r
-  char buffer[100];\r
-\r
-  if (lengthSeconds && (currentSeconds < lengthSeconds))\r
-  {\r
-    ULONG dcurrentSeconds = currentSeconds;\r
-    ULONG dlengthSeconds = lengthSeconds;\r
-\r
-    ULONG currentHours = dcurrentSeconds / 3600;\r
-    dcurrentSeconds %= 3600;\r
-    ULONG currentMinutes = dcurrentSeconds / 60;\r
-    dcurrentSeconds %= 60;\r
-\r
-    ULONG lengthHours = dlengthSeconds / 3600;\r
-    dlengthSeconds %= 3600;\r
-    ULONG lengthMinutes = dlengthSeconds / 60;\r
-    dlengthSeconds %= 60;\r
-\r
-    SNPRINTF(buffer, 99, "%01lu:%02lu:%02lu / %01lu:%02lu:%02lu", currentHours, currentMinutes, dcurrentSeconds, lengthHours, lengthMinutes, dlengthSeconds);\r
-    logger->log("VRadioRec", Log::DEBUG, buffer);\r
-  }\r
-  else\r
-  {\r
-    strcpy(buffer, "-:--:-- / -:--:--");\r
-  }\r
-\r
-  drawText(buffer, clocksRegion.x, clocksRegion.y, DrawStyle::LIGHTTEXT);\r
-\r
-  // Draw progress bar\r
-  int progBarXbase = barRegion.x + 300;\r
-\r
-  rectangle(barRegion.x + progBarXbase, barRegion.y + 12, 310, 24, DrawStyle::LIGHTTEXT);\r
-  rectangle(barRegion.x + progBarXbase + 2, barRegion.y + 14, 306, 20, barBlue);\r
-\r
-  if (currentSeconds > lengthSeconds) return;\r
-  if (lengthSeconds == 0) return;\r
-\r
-  // Draw yellow portion\r
-  int progressWidth = 302 * currentSeconds / lengthSeconds;\r
-  rectangle(barRegion.x + progBarXbase + 4, barRegion.y + 16, progressWidth, 16, DrawStyle::SELECTHIGHLIGHT);\r
-/*\r
-\r
-  if (myRec->recInfo->timerEnd > time(NULL)) // if chasing\r
-  {\r
-    int nrWidth = (int)(302 * ((double)(lengthFrames - 0) / lengthFrames)); // 0 inserted instead of getlengthframes\r
-\r
-    Log::getInstance()->log("GVASDF", Log::DEBUG, "Length Frames: %lu", lengthFrames);\r
-//    Log::getInstance()->log("GVASDF", Log::DEBUG, "Player lf: %lu", player->getLengthFrames());\r
-    Log::getInstance()->log("GVASDF", Log::DEBUG, "NR WDITH: %i", nrWidth);\r
-    rectangle(barRegion.x + progBarXbase + 4 + 302 - nrWidth, barRegion.y + 16, nrWidth, 16, DrawStyle::RED);\r
-  }\r
-*/\r
-\r
-  logger->log("VRadioRec", Log::DEBUG, "blips");\r
-\r
-  // Now calc position for start margin blips\r
-  int posPix;\r
-\r
-  posPix = 302 * startMargin / lengthSeconds;\r
-  logger->log("VRadioRec", Log::DEBUG, "posPix %i", posPix);\r
-\r
-  rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 - 2, 2, 2, DrawStyle::LIGHTTEXT);\r
-  rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 + 24, 2, 2, DrawStyle::LIGHTTEXT);\r
-\r
-  posPix = 302 * (lengthSeconds - endMargin) / lengthSeconds;\r
-\r
-  rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 - 2, 2, 2, DrawStyle::LIGHTTEXT);\r
-  rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 + 24, 2, 2, DrawStyle::LIGHTTEXT);\r
-}\r
-\r
-void VRadioRec::removeBar()\r
-{\r
-  if (!barShowing) return;\r
-  timers->cancelTimer(this, 2);\r
-  barShowing = false;\r
-  rectangle(barRegion, DrawStyle::BLACK);\r
-  boxstack->update(this, &barRegion);\r
-}\r
-\r
+/*
+    Copyright 2004-2006 Chris Tallon
+
+    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 "vradiorec.h"
+
+#include "command.h"
+#include "osd.h"
+#include "player.h"
+#include "wsymbol.h"
+#include "recording.h"
+#include "message.h"
+#include "vdr.h"
+#include "video.h"
+#include "timers.h"
+#include "playerradio.h"
+#include "boxstack.h"
+#include "remote.h"
+#include "vinfo.h"
+#include "i18n.h"
+#include "log.h"
+
+VRadioRec::VRadioRec(Recording* rec)
+{
+  boxstack = BoxStack::getInstance();
+  vdr = VDR::getInstance();
+  video = Video::getInstance();
+  timers = Timers::getInstance();
+  myRec = rec;
+  playing = false;
+  startMargin = 0;
+  endMargin = 0;
+
+  player = new PlayerRadio(Command::getInstance(), this);
+
+  char* cstartMargin = vdr->configLoad("Timers", "Start margin");
+  char* cendMargin = vdr->configLoad("Timers", "End margin");
+  if (!cstartMargin)
+  {
+    startMargin = 300; // 5 mins default
+  }
+  else
+  {
+    startMargin = atoi(cstartMargin) * 60;
+    delete[] cstartMargin;
+  }
+
+  if (!cendMargin)
+  {
+    endMargin = 300; // 5 mins default
+  }
+  else
+  {
+    endMargin = atoi(cendMargin) * 60;
+    delete[] cendMargin;
+  }
+
+  Log::getInstance()->log("VRadioRec", Log::DEBUG, "SM: %u EM: %u", startMargin, endMargin);
+
+  setSize(video->getScreenWidth(), video->getScreenHeight());
+  createBuffer();
+  setPosition(0, 0);
+
+  barRegion.x = 0;
+  barRegion.y = video->getScreenHeight() - 58;   // FIXME, need to be - 1? and below?
+  barRegion.w = video->getScreenWidth();
+  barRegion.h = 58;
+
+  clocksRegion.x = barRegion.x + 140;
+  clocksRegion.y = barRegion.y + 12;
+  clocksRegion.w = 170;
+  clocksRegion.h = getFontHeight();
+
+
+  barBlue.set(0, 0, 150, 150);
+
+  barShowing = false;
+}
+
+void VRadioRec::preDelete()
+{
+  timers->cancelTimer(this, 1);
+  timers->cancelTimer(this, 2);
+}
+
+VRadioRec::~VRadioRec()
+{
+  if (playing) stopPlay();
+
+
+  // kill recInfo in case resumePoint has changed (likely)
+  myRec->dropRecInfo();
+  // FIXME - do this properly - save the resume point back to the server manually and update
+  // rec->recInfo->resumePoint - this will fix the ~10s offset problem as well
+}
+
+void VRadioRec::draw()
+{
+  fillColour(DrawStyle::BLACK);
+}
+
+void VRadioRec::go()
+{
+  Log::getInstance()->log("VRadioRec", Log::DEBUG, "Starting stream: %s", myRec->getFileName());
+  ULONG lengthFrames = 0;
+  bool isPesRecording;
+  ULLONG lengthBytes = vdr->streamRecording(myRec->getFileName(), &lengthFrames, &isPesRecording);
+  myRec->IsPesRecording = isPesRecording;
+
+  bool cantStart = false;
+
+  if (!lengthBytes) cantStart = true;
+  else if (!player->init(lengthBytes, lengthFrames, myRec->IsPesRecording)) cantStart = true;
+  else
+  {
+    doBar(0);
+  //  player->setStartBytes(startBytes);
+    player->play();
+    playing = true;
+  }
+
+  if (cantStart)
+  {
+    stopPlay(); // clean up
+
+    if (!vdr->isConnected())
+    {
+      Command::getInstance()->connectionLost();
+      return;
+    }
+
+    Message* m = new Message();
+    m->message = Message::CLOSE_ME;
+    m->from = this;
+    m->to = boxstack;
+    Command::getInstance()->postMessageNoLock(m);
+
+    VInfo* vi = new VInfo();
+    vi->setSize(400, 150);
+    vi->createBuffer();
+    if (video->getFormat() == Video::PAL)
+      vi->setPosition(170, 200);
+    else
+      vi->setPosition(160, 150);
+    vi->setExitable();
+    vi->setBorderOn(1);
+    vi->setTitleBarOn(0);
+    vi->setOneLiner(tr("Error playing recording"));
+    vi->draw();
+
+    m = new Message();
+    m->message = Message::ADD_VIEW;
+    m->to = boxstack;
+    m->parameter = (ULONG)vi;
+    Command::getInstance()->postMessageNoLock(m);
+  }
+}
+
+int VRadioRec::handleCommand(int command)
+{
+  switch(command)
+  {
+    case Remote::PLAY:
+    {
+      player->play();
+      doBar(0);
+      return 2;
+    }
+    case Remote::PLAYPAUSE:
+    {
+       player->playpause();
+        doBar(0);
+        return 2;
+    }
+
+    case Remote::STOP:
+    case Remote::BACK:
+    case Remote::MENU:
+    {
+      if (playing) stopPlay();
+      return 4;
+    }
+    case Remote::PAUSE:
+    {
+      player->pause();
+      doBar(0);
+      return 2;
+    }
+    case Remote::SKIPFORWARD:
+    {
+      doBar(3);
+      player->skipForward(60);
+      return 2;
+    }
+    case Remote::SKIPBACK:
+    {
+      doBar(4);
+      player->skipBackward(60);
+      return 2;
+    }
+    case Remote::YELLOW:
+    {
+      doBar(2);
+      player->skipBackward(10);
+      return 2;
+    }
+    case Remote::BLUE:
+    {
+      doBar(1);
+      player->skipForward(10);
+      return 2;
+    }
+    case Remote::OK:
+    {
+      if (barShowing) removeBar();
+      else doBar(0);
+      return 2;
+    }
+
+    case Remote::ZERO:  player->jumpToPercent(0);  doBar(0);  return 2;
+    case Remote::ONE:   player->jumpToPercent(10); doBar(0);  return 2;
+    case Remote::TWO:   player->jumpToPercent(20); doBar(0);  return 2;
+    case Remote::THREE: player->jumpToPercent(30); doBar(0);  return 2;
+    case Remote::FOUR:  player->jumpToPercent(40); doBar(0);  return 2;
+    case Remote::FIVE:  player->jumpToPercent(50); doBar(0);  return 2;
+    case Remote::SIX:   player->jumpToPercent(60); doBar(0);  return 2;
+    case Remote::SEVEN: player->jumpToPercent(70); doBar(0);  return 2;
+    case Remote::EIGHT: player->jumpToPercent(80); doBar(0);  return 2;
+    case Remote::NINE:  player->jumpToPercent(90); doBar(0);  return 2;
+
+#ifdef DEV
+    case Remote::RED:
+    {
+      //player->test1();
+
+      return 2;
+    }
+    case Remote::GREEN:
+    {
+      //player->test2();
+      return 2;
+    }
+#endif
+
+  }
+
+  return 1;
+}
+
+void VRadioRec::processMessage(Message* m)
+{
+  if (m->message == Message::MOUSE_LBDOWN)
+  {
+    int x=(m->parameter>>16)-(int)getScreenX();
+    int y=(m->parameter&0xFFFF)-(int)getScreenY();
+    if (!barShowing)
+    {
+      boxstack->handleCommand(Remote::OK); //simulate rok press
+    }
+    else if ((int)barRegion.x<=x && (int)barRegion.y<=y && ((int)barRegion.x+(int)barRegion.w)>=x
+             &&  ((int)barRegion.y+(int)barRegion.h)>=y)
+    {
+      int progBarXbase = barRegion.x + 300;
+      if (x>=(int)barRegion.x + progBarXbase + 24
+        && x<=(int)barRegion.x + progBarXbase + 4 + 302
+        && y>=(int)barRegion.y + 12 - 2
+        && y<=(int)barRegion.y + 12 - 2+28)
+      {
+        int cx=x-(barRegion.x + progBarXbase + 4);
+        double percent=((double)cx)/302.*100.;
+        player->jumpToPercent(percent);
+        doBar(3);
+        return;
+        //  int progressWidth = 302 * currentFrameNum / lengthFrames;
+        //  rectangle(barRegion.x + progBarXbase + 4, barRegion.y + 16, progressWidth, 16, DrawStyle::SELECTHIGHLIGHT);
+      }
+    }
+    else
+    {
+      boxstack->handleCommand(Remote::OK); //simulate rok press
+    }
+  }
+  else if (m->message == Message::PLAYER_EVENT)
+  {
+    if (m->from != player) return;
+
+    Log::getInstance()->log("VRadioRec", Log::DEBUG, "Message received");
+
+    switch(m->parameter)
+    {
+      case Player::CONNECTION_LOST: // connection lost detected
+      {
+        // I can't handle this, send it to command
+        Message* m2 = new Message();
+        m2->to = Command::getInstance();
+        m2->message = Message::CONNECTION_LOST;
+        Command::getInstance()->postMessageNoLock(m2);
+        break;
+      }
+      case Player::STOP_PLAYBACK:
+      {
+        // FIXME Obselete ish - improve this
+        Message* m2 = new Message(); // Must be done after this thread finishes, and must break into master mutex
+        m2->to = Command::getInstance();
+        m2->message = Message::STOP_PLAYBACK;
+        Command::getInstance()->postMessageNoLock(m2);
+        break;
+      }
+    }
+  }
+}
+
+void VRadioRec::stopPlay()
+{
+  Log::getInstance()->log("VRadioRec", Log::DEBUG, "Pre stopPlay");
+
+  removeBar();
+  player->stop();
+  vdr->stopStreaming();
+  delete player;
+
+  playing = false;
+
+  if (!vdr->isConnected()) { Command::getInstance()->connectionLost(); return; }
+  Log::getInstance()->log("VRadioRec", Log::DEBUG, "Post stopPlay");
+}
+
+void VRadioRec::doBar(int action)
+{
+  barShowing = true;
+
+  rectangle(barRegion, barBlue);
+
+  /* Work out what to display - choices:
+
+  Playing  >
+  Paused   ||
+
+  Specials, informed by parameter
+
+  Skip forward 10s    >|
+  Skip backward 10s   |<
+  Skip forward 1m     >>|
+  Skip backward 1m    |<<
+
+  */
+
+  WSymbol w;
+  TEMPADD(&w);
+  w.nextSymbol = 0;
+  w.setPosition(barRegion.x + 66, barRegion.y + 16);
+
+  UCHAR playerState = 0;
+
+  if (action)
+  {
+    if (action == 1)       w.nextSymbol = WSymbol::SKIPFORWARD;
+    else if (action == 2)  w.nextSymbol = WSymbol::SKIPBACK;
+    else if (action == 3)  w.nextSymbol = WSymbol::SKIPFORWARD2;
+    else if (action == 4)  w.nextSymbol = WSymbol::SKIPBACK2;
+  }
+  else
+  {
+    playerState = player->getState();
+    if (playerState == Player::S_PAUSE_P)      w.nextSymbol = WSymbol::PAUSE;
+    else if (playerState == Player::S_PAUSE_I) w.nextSymbol = WSymbol::PAUSE;
+    else                                       w.nextSymbol = WSymbol::PLAY;
+  }
+
+  w.draw();
+
+  drawBarClocks();
+
+  BoxStack::getInstance()->update(this, &barRegion);
+
+  timers->setTimerD(this, 1, 4); // only set the getridofbar timer if not ffwd/fbwd
+  timers->setTimerD(this, 2, 0, 200000000);
+}
+
+void VRadioRec::timercall(int clientReference)
+{
+  switch(clientReference)
+  {
+    case 1:
+    {
+      // Remove bar
+      removeBar();
+      break;
+    }
+    case 2:
+    {
+      // Update clock
+      if (!barShowing) break;
+      drawBarClocks();
+      boxstack->update(this, &barRegion);
+      
+      timers->setTimerD(this, 2, 0, 200000000);
+      break;
+    }
+  }
+}
+
+void VRadioRec::drawBarClocks()
+{
+  Log* logger = Log::getInstance();
+  logger->log("VRadioRec", Log::DEBUG, "Draw bar clocks");
+
+  // Draw RTC
+  // Blank the area first
+  rectangle(barRegion.x + 624, barRegion.y + 12, 60, 30, barBlue);
+  char timeString[20];
+  time_t t;
+  time(&t);
+  struct tm* tms = localtime(&t);
+  strftime(timeString, 19, "%H:%M", tms);
+  drawText(timeString, barRegion.x + 624, barRegion.y + 12, DrawStyle::LIGHTTEXT);
+
+  // Draw clocks
+
+  rectangle(clocksRegion, barBlue);
+
+/*
+  ULONG currentFrameNum = player->getCurrentFrameNum();
+  ULONG lengthFrames;
+  if (myRec->recInfo->timerEnd > time(NULL))
+  {
+    // chasing playback
+    // Work out an approximate length in frames (good to 1s...)
+    lengthFrames = (myRec->recInfo->timerEnd - myRec->recInfo->timerStart) * video->getFPS();
+  }
+  else
+  {
+//    lengthFrames = player->getLengthFrames();
+    lengthFrames = 0;
+  }
+
+  hmsf currentFrameHMSF = video->framesToHMSF(currentFrameNum);
+  hmsf lengthHMSF = video->framesToHMSF(lengthFrames);
+
+  char buffer[100];
+  if (currentFrameNum >= lengthFrames)
+  {
+    strcpy(buffer, "-:--:-- / -:--:--");
+  }
+  else
+  {
+    SNPRINTF(buffer, 99, "%01i:%02i:%02i / %01i:%02i:%02i", currentFrameHMSF.hours, currentFrameHMSF.minutes, currentFrameHMSF.seconds, lengthHMSF.hours, lengthHMSF.minutes, lengthHMSF.seconds);
+    logger->log("VRadioRec", Log::DEBUG, buffer);
+  }
+*/
+
+  ULONG currentSeconds = player->getCurrentSeconds();
+  ULONG lengthSeconds = player->getLengthSeconds();
+  char buffer[100];
+
+  if (lengthSeconds && (currentSeconds < lengthSeconds))
+  {
+    ULONG dcurrentSeconds = currentSeconds;
+    ULONG dlengthSeconds = lengthSeconds;
+
+    ULONG currentHours = dcurrentSeconds / 3600;
+    dcurrentSeconds %= 3600;
+    ULONG currentMinutes = dcurrentSeconds / 60;
+    dcurrentSeconds %= 60;
+
+    ULONG lengthHours = dlengthSeconds / 3600;
+    dlengthSeconds %= 3600;
+    ULONG lengthMinutes = dlengthSeconds / 60;
+    dlengthSeconds %= 60;
+
+    SNPRINTF(buffer, 99, "%01lu:%02lu:%02lu / %01lu:%02lu:%02lu", currentHours, currentMinutes, dcurrentSeconds, lengthHours, lengthMinutes, dlengthSeconds);
+    logger->log("VRadioRec", Log::DEBUG, buffer);
+  }
+  else
+  {
+    strcpy(buffer, "-:--:-- / -:--:--");
+  }
+
+  drawText(buffer, clocksRegion.x, clocksRegion.y, DrawStyle::LIGHTTEXT);
+
+  // Draw progress bar
+  int progBarXbase = barRegion.x + 300;
+
+  rectangle(barRegion.x + progBarXbase, barRegion.y + 12, 310, 24, DrawStyle::LIGHTTEXT);
+  rectangle(barRegion.x + progBarXbase + 2, barRegion.y + 14, 306, 20, barBlue);
+
+  if (currentSeconds > lengthSeconds) return;
+  if (lengthSeconds == 0) return;
+
+  // Draw yellow portion
+  int progressWidth = 302 * currentSeconds / lengthSeconds;
+  rectangle(barRegion.x + progBarXbase + 4, barRegion.y + 16, progressWidth, 16, DrawStyle::SELECTHIGHLIGHT);
+/*
+
+  if (myRec->recInfo->timerEnd > time(NULL)) // if chasing
+  {
+    int nrWidth = (int)(302 * ((double)(lengthFrames - 0) / lengthFrames)); // 0 inserted instead of getlengthframes
+
+    Log::getInstance()->log("GVASDF", Log::DEBUG, "Length Frames: %lu", lengthFrames);
+//    Log::getInstance()->log("GVASDF", Log::DEBUG, "Player lf: %lu", player->getLengthFrames());
+    Log::getInstance()->log("GVASDF", Log::DEBUG, "NR WDITH: %i", nrWidth);
+    rectangle(barRegion.x + progBarXbase + 4 + 302 - nrWidth, barRegion.y + 16, nrWidth, 16, DrawStyle::RED);
+  }
+*/
+
+  logger->log("VRadioRec", Log::DEBUG, "blips");
+
+  // Now calc position for start margin blips
+  int posPix;
+
+  posPix = 302 * startMargin / lengthSeconds;
+  logger->log("VRadioRec", Log::DEBUG, "posPix %i", posPix);
+
+  rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 - 2, 2, 2, DrawStyle::LIGHTTEXT);
+  rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 + 24, 2, 2, DrawStyle::LIGHTTEXT);
+
+  posPix = 302 * (lengthSeconds - endMargin) / lengthSeconds;
+
+  rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 - 2, 2, 2, DrawStyle::LIGHTTEXT);
+  rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 + 24, 2, 2, DrawStyle::LIGHTTEXT);
+}
+
+void VRadioRec::removeBar()
+{
+  if (!barShowing) return;
+  timers->cancelTimer(this, 2);
+  barShowing = false;
+  rectangle(barRegion, DrawStyle::BLACK);
+  boxstack->update(this, &barRegion);
+}
+
index c3b2461b2569545050a15561f258adf7b7680410..b285061635b6c91dfd651169592535c0d5803f44 100644 (file)
-/*\r
-    Copyright 2004-2008 Chris Tallon\r
-\r
-    This file is part of VOMP.\r
-\r
-    VOMP is free software; you can redistribute it and/or modify\r
-    it under the terms of the GNU General Public License as published by\r
-    the Free Software Foundation; either version 2 of the License, or\r
-    (at your option) any later version.\r
-\r
-    VOMP is distributed in the hope that it will be useful,\r
-    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-    GNU General Public License for more details.\r
-\r
-    You should have received a copy of the GNU General Public License\r
-    along with VOMP; if not, write to the Free Software\r
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
-*/\r
-\r
-#include "vrecording.h"\r
-\r
-#include "remote.h"\r
-#include "recinfo.h"\r
-#include "vquestion.h"\r
-#include "vinfo.h"\r
-#include "vdr.h"\r
-#include "colour.h"\r
-#include "video.h"\r
-#include "i18n.h"\r
-#include "command.h"\r
-#include "vrecmove.h"\r
-#include "boxstack.h"\r
-#include "recman.h"\r
-#include "vrecordinglist.h"\r
-#include "recording.h"\r
-#include "message.h"\r
-#include "log.h"\r
-\r
-VRecording::VRecording(RecMan* trecman, Recording* trec)\r
-{\r
-  rec = trec;\r
-  recman = trecman;\r
-  \r
-  Log::getInstance()->log("VRecording", Log::DEBUG, "%s", rec->getProgName());\r
-  rec->loadRecInfo();\r
-  Log::getInstance()->log("VRecording", Log::DEBUG, "%s", rec->getProgName());\r
-\r
-  setSize(570, 420);\r
-  createBuffer();\r
-  if (Video::getInstance()->getFormat() == Video::PAL)\r
-  {\r
-    setPosition(80, 70);\r
-  }\r
-  else\r
-  {\r
-    setPosition(70, 35);\r
-  }\r
-\r
-  setTitleBarOn(1);\r
-  setBorderOn(1);\r
-  setTitleText(rec->getProgName());\r
-  setTitleBarColour(DrawStyle::TITLEBARBACKGROUND);\r
-\r
-  summary.setPosition(10, 30 + 5);\r
-  summary.setSize(area.w - 20, area.h - 30 - 15 - 50);\r
-  summary.setParaMode(true);\r
-\r
-  if (rec->recInfo &&strlen(rec->recInfo->summary))\r
-    summary.setText(rec->recInfo->summary);\r
-  else\r
-    summary.setText(tr("Summary unavailable"));\r
-\r
-  add(&summary);\r
-  \r
-  \r
-  buttonPlay.setPosition(10, area.h - 40);\r
-  buttonResume.setPosition(150, area.h - 40);\r
-  buttonMove.setPosition(290, area.h - 40);\r
-  buttonDelete.setPosition(430, area.h - 40);\r
-  \r
-  int sfh = getFontHeight();\r
-  \r
-  buttonPlay.setSize(130, sfh);\r
-  buttonResume.setSize(130, sfh);\r
-  buttonMove.setSize(130, sfh);\r
-  buttonDelete.setSize(130, sfh);\r
-  \r
-  buttonRegion.x = 10;\r
-  buttonRegion.y = area.h - 40;\r
-  buttonRegion.w = 550;\r
-  buttonRegion.h = sfh;\r
-\r
-  buttonPlay.setText(tr("Play"));\r
-  buttonResume.setText(tr("Resume"));\r
-  buttonMove.setText(tr("Move"));\r
-  buttonDelete.setText(tr("Delete"));\r
-  \r
-  add(&buttonPlay);\r
-  add(&buttonResume);    \r
-  add(&buttonMove);\r
-  add(&buttonDelete);\r
-  \r
-  buttonPlay.setActive(1);\r
-  selected = 1;\r
-}\r
-\r
-VRecording::~VRecording()\r
-{\r
-}\r
-\r
-void VRecording::setParent(VRecordingList* tvRecList)\r
-{\r
-  vRecList = tvRecList;\r
-}\r
-\r
-void VRecording::draw()\r
-{\r
-  TBBoxx::draw();\r
-}\r
-\r
-int VRecording::handleCommand(int command)\r
-{\r
-  switch(command)\r
-  {\r
-    case Remote::LEFT:\r
-    case Remote::DF_LEFT:\r
-    case Remote::DF_UP:\r
-    case Remote::UP:\r
-    {\r
-      doLeft();\r
-      return 2;\r
-    }\r
-    case Remote::RIGHT:\r
-    case Remote::DF_RIGHT:\r
-    case Remote::DF_DOWN:\r
-    case Remote::DOWN:\r
-    {\r
-      doRight();\r
-      return 2;\r
-    }\r
-    case Remote::OK:\r
-    {\r
-\r
-      if (selected == 1)\r
-      {\r
-        Message* m = new Message(); // Must be done after this view deleted\r
-        m->from = this;\r
-        m->to = vRecList;\r
-        m->message = Message::PLAY_SELECTED_RECORDING;\r
-        Command::getInstance()->postMessageNoLock(m);\r
-        return 4;\r
-      }\r
-\r
-      if (selected == 2)\r
-      {\r
-        Message* m = new Message(); // Must be done after this view deleted\r
-        m->from = this;\r
-        m->to = vRecList;\r
-        m->message = Message::RESUME_SELECTED_RECORDING;\r
-        Command::getInstance()->postMessageNoLock(m);\r
-        return 4;\r
-      }\r
-\r
-      if (selected == 3)\r
-      {\r
-        VRecMove* vrm = new VRecMove(recman);\r
-        vrm->setParent(this);\r
-        vrm->draw();\r
-        BoxStack::getInstance()->add(vrm);\r
-        BoxStack::getInstance()->update(vrm);\r
-        return 2;\r
-      }\r
-\r
-      if (selected == 4)\r
-      {\r
-        VQuestion* v = new VQuestion(this);\r
-        v->setSize(260, 180);\r
-        v->createBuffer();\r
-        v->setTitleBarColour(DrawStyle::DANGER);\r
-        v->setTitleBarOn(1);\r
-        v->setBorderOn(1);\r
-        v->setTitleText(tr("Delete recording"));\r
-        v->setMainText(tr("Are you sure you want to delete this recording?"));\r
-        v->setDefault(VQuestion::NO);\r
-        if (Video::getInstance()->getFormat() == Video::PAL)\r
-        {\r
-          v->setPosition(230, 160);\r
-        }\r
-        else\r
-        {\r
-          v->setPosition(220, 140);\r
-        }\r
-\r
-        v->draw();\r
-        BoxStack::getInstance()->add(v);\r
-        BoxStack::getInstance()->update(v);\r
-        return 2;\r
-      }\r
-    }\r
-\r
-    case Remote::BACK:\r
-    {\r
-      return 4;\r
-    }\r
-  }\r
-  // stop command getting to any more views\r
-  return 1;\r
-}\r
-\r
-void VRecording::doRight()\r
-{\r
-  switch(selected)\r
-  {\r
-    case 1:\r
-      buttonPlay.setActive(0);\r
-      buttonResume.setActive(1);\r
-      buttonPlay.draw();\r
-      buttonResume.draw();\r
-      break;\r
-    case 2:\r
-      buttonResume.setActive(0);\r
-      buttonMove.setActive(1);\r
-      buttonResume.draw();\r
-      buttonMove.draw();\r
-      break;\r
-    case 3:\r
-      buttonMove.setActive(0);\r
-      buttonDelete.setActive(1);\r
-      buttonMove.draw();\r
-      buttonDelete.draw();\r
-      break;\r
-    case 4:\r
-      buttonDelete.setActive(0);\r
-      buttonPlay.setActive(1);\r
-      buttonDelete.draw();\r
-      buttonPlay.draw();\r
-      break;\r
-  }\r
-  \r
-  if (++selected == 5) selected = 1;\r
-  \r
-  BoxStack::getInstance()->update(this, &buttonRegion);\r
-}\r
-\r
-void VRecording::doLeft()\r
-{\r
-  switch(selected)\r
-  {\r
-    case 1:\r
-      buttonPlay.setActive(0);\r
-      buttonDelete.setActive(1);\r
-      buttonPlay.draw();\r
-      buttonDelete.draw();\r
-      break;\r
-    case 2:\r
-      buttonResume.setActive(0);\r
-      buttonPlay.setActive(1);\r
-      buttonResume.draw();\r
-      buttonPlay.draw();\r
-      break;\r
-    case 3:\r
-      buttonMove.setActive(0);\r
-      buttonResume.setActive(1);\r
-      buttonMove.draw();\r
-      buttonResume.draw();\r
-      break;\r
-    case 4:\r
-      buttonDelete.setActive(0);\r
-      buttonMove.setActive(1);\r
-      buttonDelete.draw();\r
-      buttonMove.draw();\r
-      break;\r
-  }\r
-  \r
-  if (--selected == 0) selected = 4;\r
-  \r
-  BoxStack::getInstance()->update(this, &buttonRegion);\r
-}\r
-\r
-void VRecording::processMessage(Message* m)\r
-{\r
-  if (m->message == Message::MOUSE_MOVE)\r
-  {\r
-    if (buttonPlay.mouseMove((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))\r
-    {\r
-      buttonPlay.setActive(1);\r
-      buttonResume.setActive(0);\r
-      buttonMove.setActive(0);\r
-      buttonDelete.setActive(0);\r
-      selected=1;\r
-      draw();\r
-      BoxStack::getInstance()->update(this);\r
-    }\r
-    else if (buttonResume.mouseMove((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))\r
-    {\r
-      buttonPlay.setActive(0);\r
-      buttonResume.setActive(1);\r
-      buttonMove.setActive(0);\r
-      buttonDelete.setActive(0);\r
-      selected=2;\r
-      draw();\r
-      BoxStack::getInstance()->update(this);\r
-    }\r
-    else if (buttonMove.mouseMove((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))\r
-    {\r
-      buttonPlay.setActive(0);\r
-      buttonResume.setActive(0);\r
-      buttonMove.setActive(1);\r
-      buttonDelete.setActive(0);\r
-      selected=3;\r
-      draw();\r
-      BoxStack::getInstance()->update(this);\r
-    }\r
-    else if (buttonDelete.mouseMove((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))\r
-    {\r
-      buttonPlay.setActive(0);\r
-      buttonResume.setActive(0);\r
-      buttonMove.setActive(0);\r
-      buttonDelete.setActive(1);\r
-      selected=4;\r
-      draw();\r
-      BoxStack::getInstance()->update(this);\r
-    }\r
-  }\r
-  else if (m->message == Message::MOUSE_LBDOWN)\r
-  {\r
-    if (buttonPlay.mouseLBDOWN((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))\r
-    {\r
-      BoxStack::getInstance()->handleCommand(Remote::OK); //simulate OK press\r
-    }\r
-    else if (buttonResume.mouseLBDOWN((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))\r
-    {\r
-      BoxStack::getInstance()->handleCommand(Remote::OK); //simulate OK press\r
-    }\r
-    else if (buttonMove.mouseLBDOWN((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))\r
-    {\r
-      BoxStack::getInstance()->handleCommand(Remote::OK); //simulate OK press\r
-    }\r
-    else if (buttonDelete.mouseLBDOWN((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))\r
-    {\r
-      BoxStack::getInstance()->handleCommand(Remote::OK); //simulate OK press\r
-    }\r
-    else\r
-    {\r
-      //check if press is outside this view! then simulate cancel\r
-      int x=(m->parameter>>16)-getScreenX();\r
-      int y=(m->parameter&0xFFFF)-getScreenY();\r
-      if (x<0 || y <0 || x>(int)getWidth() || y>(int)getHeight())\r
-      {\r
-        BoxStack::getInstance()->handleCommand(Remote::BACK); //simulate cancel press\r
-      }\r
-    }\r
-  }\r
-  else if (m->message == Message::QUESTION_YES)\r
-  {\r
-    if (selected == 4)\r
-    {\r
-      Message* m2 = new Message(); // Delete self\r
-      m2->from = this;\r
-      m2->to = BoxStack::getInstance();\r
-      m2->message = Message::CLOSE_ME;\r
-      Command::getInstance()->postMessageNoLock(m2);\r
-\r
-      m2 = new Message(); // OK. Want this to delete before this message does its job\r
-      m2->from = this;\r
-      m2->to = vRecList;\r
-      m2->message = Message::DELETE_SELECTED_RECORDING;\r
-      Command::getInstance()->postMessageNoLock(m2);\r
-    }\r
-  }\r
-  else if (m->message == Message::MOVE_RECORDING)\r
-  {\r
-    Message* m2 = new Message(); // Delete self\r
-    m2->from = this;\r
-    m2->to = BoxStack::getInstance();\r
-    m2->message = Message::CLOSE_ME;\r
-    Command::getInstance()->postMessageNoLock(m2);\r
-\r
-    m2 = new Message();\r
-    m2->from = this;\r
-    m2->to = vRecList;\r
-    m2->message = Message::MOVE_RECORDING;\r
-    m2->parameter = m->parameter;\r
-    Command::getInstance()->postMessageNoLock(m2);\r
-  }\r
-}\r
-\r
+/*
+    Copyright 2004-2008 Chris Tallon
+
+    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 "vrecording.h"
+
+#include "remote.h"
+#include "recinfo.h"
+#include "vquestion.h"
+#include "vinfo.h"
+#include "vdr.h"
+#include "colour.h"
+#include "video.h"
+#include "i18n.h"
+#include "command.h"
+#include "vrecmove.h"
+#include "boxstack.h"
+#include "recman.h"
+#include "vrecordinglist.h"
+#include "recording.h"
+#include "message.h"
+#include "log.h"
+
+VRecording::VRecording(RecMan* trecman, Recording* trec)
+{
+  rec = trec;
+  recman = trecman;
+  
+  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);
+  }
+  else
+  {
+    setPosition(70, 35);
+  }
+
+  setTitleBarOn(1);
+  setBorderOn(1);
+  setTitleText(rec->getProgName());
+  setTitleBarColour(DrawStyle::TITLEBARBACKGROUND);
+
+  summary.setPosition(10, 30 + 5);
+  summary.setSize(area.w - 20, area.h - 30 - 15 - 50);
+  summary.setParaMode(true);
+
+  if (rec->recInfo &&strlen(rec->recInfo->summary))
+    summary.setText(rec->recInfo->summary);
+  else
+    summary.setText(tr("Summary unavailable"));
+
+  add(&summary);
+  
+  
+  buttonPlay.setPosition(10, area.h - 40);
+  buttonResume.setPosition(150, area.h - 40);
+  buttonMove.setPosition(290, area.h - 40);
+  buttonDelete.setPosition(430, area.h - 40);
+  
+  int sfh = getFontHeight();
+  
+  buttonPlay.setSize(130, sfh);
+  buttonResume.setSize(130, sfh);
+  buttonMove.setSize(130, sfh);
+  buttonDelete.setSize(130, sfh);
+  
+  buttonRegion.x = 10;
+  buttonRegion.y = area.h - 40;
+  buttonRegion.w = 550;
+  buttonRegion.h = sfh;
+
+  buttonPlay.setText(tr("Play"));
+  buttonResume.setText(tr("Resume"));
+  buttonMove.setText(tr("Move"));
+  buttonDelete.setText(tr("Delete"));
+  
+  add(&buttonPlay);
+  add(&buttonResume);    
+  add(&buttonMove);
+  add(&buttonDelete);
+  
+  buttonPlay.setActive(1);
+  selected = 1;
+}
+
+VRecording::~VRecording()
+{
+}
+
+void VRecording::setParent(VRecordingList* tvRecList)
+{
+  vRecList = tvRecList;
+}
+
+void VRecording::draw()
+{
+  TBBoxx::draw();
+}
+
+int VRecording::handleCommand(int command)
+{
+  switch(command)
+  {
+    case Remote::LEFT:
+    case Remote::DF_LEFT:
+    case Remote::DF_UP:
+    case Remote::UP:
+    {
+      doLeft();
+      return 2;
+    }
+    case Remote::RIGHT:
+    case Remote::DF_RIGHT:
+    case Remote::DF_DOWN:
+    case Remote::DOWN:
+    {
+      doRight();
+      return 2;
+    }
+    case Remote::OK:
+    {
+
+      if (selected == 1)
+      {
+        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 == 2)
+      {
+        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 == 3)
+      {
+        VRecMove* vrm = new VRecMove(recman);
+        vrm->setParent(this);
+        vrm->draw();
+        BoxStack::getInstance()->add(vrm);
+        BoxStack::getInstance()->update(vrm);
+        return 2;
+      }
+
+      if (selected == 4)
+      {
+        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;
+      }
+    }
+
+    case Remote::BACK:
+    {
+      return 4;
+    }
+  }
+  // stop command getting to any more views
+  return 1;
+}
+
+void VRecording::doRight()
+{
+  switch(selected)
+  {
+    case 1:
+      buttonPlay.setActive(0);
+      buttonResume.setActive(1);
+      buttonPlay.draw();
+      buttonResume.draw();
+      break;
+    case 2:
+      buttonResume.setActive(0);
+      buttonMove.setActive(1);
+      buttonResume.draw();
+      buttonMove.draw();
+      break;
+    case 3:
+      buttonMove.setActive(0);
+      buttonDelete.setActive(1);
+      buttonMove.draw();
+      buttonDelete.draw();
+      break;
+    case 4:
+      buttonDelete.setActive(0);
+      buttonPlay.setActive(1);
+      buttonDelete.draw();
+      buttonPlay.draw();
+      break;
+  }
+  
+  if (++selected == 5) selected = 1;
+  
+  BoxStack::getInstance()->update(this, &buttonRegion);
+}
+
+void VRecording::doLeft()
+{
+  switch(selected)
+  {
+    case 1:
+      buttonPlay.setActive(0);
+      buttonDelete.setActive(1);
+      buttonPlay.draw();
+      buttonDelete.draw();
+      break;
+    case 2:
+      buttonResume.setActive(0);
+      buttonPlay.setActive(1);
+      buttonResume.draw();
+      buttonPlay.draw();
+      break;
+    case 3:
+      buttonMove.setActive(0);
+      buttonResume.setActive(1);
+      buttonMove.draw();
+      buttonResume.draw();
+      break;
+    case 4:
+      buttonDelete.setActive(0);
+      buttonMove.setActive(1);
+      buttonDelete.draw();
+      buttonMove.draw();
+      break;
+  }
+  
+  if (--selected == 0) selected = 4;
+  
+  BoxStack::getInstance()->update(this, &buttonRegion);
+}
+
+void VRecording::processMessage(Message* m)
+{
+  if (m->message == Message::MOUSE_MOVE)
+  {
+    if (buttonPlay.mouseMove((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))
+    {
+      buttonPlay.setActive(1);
+      buttonResume.setActive(0);
+      buttonMove.setActive(0);
+      buttonDelete.setActive(0);
+      selected=1;
+      draw();
+      BoxStack::getInstance()->update(this);
+    }
+    else if (buttonResume.mouseMove((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))
+    {
+      buttonPlay.setActive(0);
+      buttonResume.setActive(1);
+      buttonMove.setActive(0);
+      buttonDelete.setActive(0);
+      selected=2;
+      draw();
+      BoxStack::getInstance()->update(this);
+    }
+    else if (buttonMove.mouseMove((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))
+    {
+      buttonPlay.setActive(0);
+      buttonResume.setActive(0);
+      buttonMove.setActive(1);
+      buttonDelete.setActive(0);
+      selected=3;
+      draw();
+      BoxStack::getInstance()->update(this);
+    }
+    else if (buttonDelete.mouseMove((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))
+    {
+      buttonPlay.setActive(0);
+      buttonResume.setActive(0);
+      buttonMove.setActive(0);
+      buttonDelete.setActive(1);
+      selected=4;
+      draw();
+      BoxStack::getInstance()->update(this);
+    }
+  }
+  else if (m->message == Message::MOUSE_LBDOWN)
+  {
+    if (buttonPlay.mouseLBDOWN((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))
+    {
+      BoxStack::getInstance()->handleCommand(Remote::OK); //simulate OK press
+    }
+    else if (buttonResume.mouseLBDOWN((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))
+    {
+      BoxStack::getInstance()->handleCommand(Remote::OK); //simulate OK press
+    }
+    else if (buttonMove.mouseLBDOWN((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))
+    {
+      BoxStack::getInstance()->handleCommand(Remote::OK); //simulate OK press
+    }
+    else if (buttonDelete.mouseLBDOWN((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))
+    {
+      BoxStack::getInstance()->handleCommand(Remote::OK); //simulate OK press
+    }
+    else
+    {
+      //check if press is outside this view! then simulate cancel
+      int x=(m->parameter>>16)-getScreenX();
+      int y=(m->parameter&0xFFFF)-getScreenY();
+      if (x<0 || y <0 || x>(int)getWidth() || y>(int)getHeight())
+      {
+        BoxStack::getInstance()->handleCommand(Remote::BACK); //simulate cancel press
+      }
+    }
+  }
+  else if (m->message == Message::QUESTION_YES)
+  {
+    if (selected == 4)
+    {
+      Message* m2 = new Message(); // Delete self
+      m2->from = this;
+      m2->to = BoxStack::getInstance();
+      m2->message = Message::CLOSE_ME;
+      Command::getInstance()->postMessageNoLock(m2);
+
+      m2 = new Message(); // OK. Want this to delete before this message does its job
+      m2->from = this;
+      m2->to = vRecList;
+      m2->message = Message::DELETE_SELECTED_RECORDING;
+      Command::getInstance()->postMessageNoLock(m2);
+    }
+  }
+  else if (m->message == Message::MOVE_RECORDING)
+  {
+    Message* m2 = new Message(); // Delete self
+    m2->from = this;
+    m2->to = BoxStack::getInstance();
+    m2->message = Message::CLOSE_ME;
+    Command::getInstance()->postMessageNoLock(m2);
+
+    m2 = new Message();
+    m2->from = this;
+    m2->to = vRecList;
+    m2->message = Message::MOVE_RECORDING;
+    m2->parameter = m->parameter;
+    Command::getInstance()->postMessageNoLock(m2);
+  }
+}
+
index 5e872c6499a217571fefbd483f26a6ed7660629e..0426ae83fb791a113a7c7aaa552943ceed827615 100644 (file)
-/*\r
-    Copyright 2004-2007 Chris Tallon\r
-\r
-    This file is part of VOMP.\r
-\r
-    VOMP is free software; you can redistribute it and/or modify\r
-    it under the terms of the GNU General Public License as published by\r
-    the Free Software Foundation; either version 2 of the License, or\r
-    (at your option) any later version.\r
-\r
-    VOMP is distributed in the hope that it will be useful,\r
-    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-    GNU General Public License for more details.\r
-\r
-    You should have received a copy of the GNU General Public License\r
-    along with VOMP; if not, write to the Free Software\r
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
-*/\r
-\r
-#include "vrecordinglist.h"\r
-\r
-#include "recman.h"\r
-#include "directory.h"\r
-#include "recording.h"\r
-#include "remote.h"\r
-#include "wsymbol.h"\r
-#include "boxstack.h"\r
-#include "vrecordingmenu.h"\r
-#include "vrecording.h"\r
-#include "vdr.h"\r
-#include "vvideorec.h"\r
-#include "vradiorec.h"\r
-#include "colour.h"\r
-#include "video.h"\r
-#include "i18n.h"\r
-#include "command.h"\r
-#include "vinfo.h"\r
-#include "log.h"\r
-\r
-VRecordingList::VRecordingList()\r
-{\r
-  boxstack = BoxStack::getInstance();\r
-  recman = NULL;\r
-  loading = true;\r
-\r
-  setSize(570, 420);\r
-  createBuffer();\r
-  if (Video::getInstance()->getFormat() == Video::PAL)\r
-  {\r
-    setPosition(80, 70);\r
-  }\r
-  else\r
-  {\r
-    setPosition(70, 35);\r
-  }\r
-\r
-  setTitleBarOn(1);\r
-  setTitleBarColour(DrawStyle::TITLEBARBACKGROUND);\r
-\r
-  sl.setPosition(10, 30 + 5);\r
-  sl.setSize(area.w - 20, area.h - 30 - 15 - 30);\r
-  add(&sl);\r
-}\r
-\r
-VRecordingList::~VRecordingList()\r
-{\r
-  delete recman;\r
-}\r
-\r
-void VRecordingList::drawData(bool doIndexPop)\r
-{\r
-  int saveIndex = sl.getCurrentOption();\r
-  int saveTop = sl.getTopOption();\r
-  sl.clear();\r
-  sl.addColumn(0);\r
-  sl.addColumn(110);\r
-\r
-  int first = 1;\r
-\r
-  char tempA[300]; // FIXME  this is guesswork!\r
-  char tempB[300]; // FIXME\r
-  struct tm* btime;\r
-\r
-  Directory* currentSubDir;\r
-  DirectoryList::iterator i;\r
-  DirectoryList* dirList = recman->getDirectories();\r
-  for (i = dirList->begin(); i != dirList->end(); i++)\r
-  {\r
-    currentSubDir = *i;\r
-    SNPRINTF(tempA, 299, tr("<dir> %lu\t%s"), currentSubDir->getNumRecordings(), currentSubDir->name);\r
-    currentSubDir->index = sl.addOption(tempA, 0, first);\r
-    first = 0;\r
-  }\r
-  // FIXME convert the whole program to time_t's\r
-\r
-  Recording* currentRec;\r
-  RecordingList::iterator j;\r
-  RecordingList* recList = recman->getRecordings();\r
-  for (j = recList->begin(); j != recList->end(); j++)\r
-  {\r
-    currentRec = *j;\r
-    time_t recStartTime = (time_t)currentRec->getStartTime();\r
-    btime = localtime(&recStartTime);\r
-//NMT does not like this too!\r
-       //#ifndef _MSC_VER\r
-//    strftime(tempA, 299, "%0d/%0m %0H:%0M ", btime);\r
-//#else\r
-    strftime(tempA, 299, "%d/%m %H:%M ", btime);\r
-//#endif\r
-    sprintf(tempB, "%s\t%s", tempA, currentRec->getProgName());\r
-    currentRec->index = sl.addOption(tempB, 0, first);\r
-    first = 0;\r
-  }\r
-\r
-  if (doIndexPop)\r
-  {\r
-    sl.hintSetCurrent(slIndexStack.top());\r
-    slIndexStack.pop();\r
-  }\r
-  else\r
-  {\r
-    sl.hintSetCurrent(saveIndex);\r
-    sl.hintSetTop(saveTop);\r
-  }\r
-  sl.draw();\r
-  doShowingBar();\r
-}\r
-\r
-void VRecordingList::draw(bool doIndexPop)\r
-{\r
-  if (!loading)\r
-  {\r
-    if (recman->isSubDir())\r
-    {\r
-      char title[300];\r
-      SNPRINTF(title, 299, tr("Recordings - %s"), recman->getCurDirName());\r
-      setTitleText(title, 364);\r
-    }\r
-    else\r
-    {\r
-      setTitleText(tr("Recordings"));\r
-    }\r
-  }\r
-\r
-  TBBoxx::draw();\r
-\r
-  if (loading)\r
-  {\r
-    drawText(tr("Loading..."), 240, 180, DrawStyle::LIGHTTEXT);\r
-  }\r
-  else\r
-  {\r
-    char freeSpace[50];\r
-    int gigFree = recman->getFreeSpace() / 1024;\r
-    SNPRINTF(freeSpace, 49, tr("%lu%% used, %iGB free"), recman->getUsedPercent(), gigFree);\r
-    drawTextRJ(freeSpace, 560, 5, DrawStyle::LIGHTTEXT);\r
-    // Symbols\r
-\r
-    WSymbol w;\r
-    TEMPADD(&w);\r
-    w.nextSymbol = WSymbol::UP;\r
-    w.setPosition(20, 385);\r
-    w.draw();\r
-    w.nextSymbol = WSymbol::DOWN;\r
-    w.setPosition(50, 385);\r
-    w.draw();\r
-    w.nextSymbol = WSymbol::SKIPBACK;\r
-    w.setPosition(85, 385);\r
-    w.draw();\r
-    w.nextSymbol = WSymbol::SKIPFORWARD;\r
-    w.setPosition(115, 385);\r
-    w.draw();\r
-    w.nextSymbol = WSymbol::PLAY;\r
-    w.setPosition(150, 385);\r
-    w.draw();\r
-    drawTextRJ(tr("[ok] = menu"), 560, 385, DrawStyle::LIGHTTEXT);\r
-\r
-    // All static stuff done\r
-    drawData(doIndexPop);\r
-  }\r
-}\r
-\r
-void VRecordingList::doShowingBar()\r
-{\r
-  int topOption = sl.getTopOption() + 1;\r
-  if (sl.getNumOptions() == 0) topOption = 0;\r
-\r
-  rectangle(220, 385, 180, 25, DrawStyle::VIEWBACKGROUND);\r
-  char showing[200];\r
-  sprintf(showing, tr("%i to %i of %i"), topOption, sl.getBottomOption(), sl.getNumOptions());\r
-  drawText(showing, 220, 385, DrawStyle::LIGHTTEXT);\r
-}\r
-\r
-void VRecordingList::processMessage(Message* m)\r
-{\r
-  Log::getInstance()->log("VRecordingList", Log::DEBUG, "Got message value %lu", m->message);\r
-\r
-  if (m->message == Message::MOUSE_MOVE)\r
-  {\r
-    if (sl.mouseMove((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))\r
-    {\r
-      sl.draw();\r
-      doShowingBar();\r
-      boxstack->update(this);\r
-    }\r
-  }\r
-  else if (m->message == Message::MOUSE_LBDOWN)\r
-  {\r
-    if (sl.mouseLBDOWN((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))\r
-    {\r
-      boxstack->handleCommand(Remote::OK); //simulate OK press\r
-    }\r
-    else\r
-    {\r
-      //check if press is outside this view! then simulate cancel\r
-      int x=(m->parameter>>16)-getScreenX();\r
-      int y=(m->parameter&0xFFFF)-getScreenY();\r
-      if (x<0 || y <0 || x>(int)getWidth() || y>(int)getHeight())\r
-      {\r
-        boxstack->handleCommand(Remote::BACK); //simulate cancel press\r
-      }\r
-    }\r
-  }\r
-  else if (m->message == Message::DELETE_SELECTED_RECORDING)\r
-  {\r
-    Log::getInstance()->log("VRecordingList", Log::DEBUG, "Doing delete selected");\r
-    doDeleteSelected();\r
-  }\r
-  else if (m->message == Message::MOVE_RECORDING)\r
-  {\r
-    Log::getInstance()->log("VRecordingList", Log::DEBUG, "Doing move recording");\r
-    doMoveRecording((Directory*)m->parameter);\r
-  }\r
-  else if (m->message == Message::PLAY_SELECTED_RECORDING)\r
-  {\r
-    doPlay(false);\r
-  }\r
-  else if (m->message == Message::RESUME_SELECTED_RECORDING)\r
-  {\r
-    doPlay(true);\r
-  }\r
-}\r
-\r
-void VRecordingList::doDeleteSelected()\r
-{\r
-  Recording* toDelete = getCurrentOptionRecording();\r
-\r
-  if (!toDelete) return;\r
-\r
-  Log::getInstance()->log("VRecordingList", Log::DEBUG, "FOUND: %i %s %s", toDelete->index, toDelete->getProgName(), toDelete->getFileName());\r
-\r
-  int success = recman->deleteRecording(toDelete);\r
-  if (!VDR::getInstance()->isConnected())\r
-  {\r
-    Command::getInstance()->connectionLost();\r
-    return;\r
-  }\r
-\r
-  if (success != 1)\r
-  {\r
-    VInfo* vi = new VInfo();\r
-    vi->setSize(360, 200);\r
-    vi->createBuffer();\r
-    if (Video::getInstance()->getFormat() == Video::PAL)\r
-      vi->setPosition(190, 170);\r
-    else\r
-      vi->setPosition(180, 120);\r
-    vi->setOneLiner(tr("Failed to delete recording"));\r
-    vi->setExitable();\r
-    vi->setBorderOn(1);\r
-    vi->setTitleBarColour(DrawStyle::DANGER);\r
-    vi->okButton();\r
-    vi->draw();\r
-    boxstack->add(vi);\r
-    boxstack->update(vi);\r
-  }\r
-  else\r
-  {\r
-    draw();\r
-    boxstack->update(this);\r
-  }\r
-\r
-}\r
-\r
-void VRecordingList::doMoveRecording(Directory* toDir)\r
-{\r
-  Recording* toMove = getCurrentOptionRecording();\r
-  if (!toMove || !toDir) return;\r
-\r
-  Log::getInstance()->log("VRecordingList", Log::DEBUG, "MOVE: %s %s", toMove->getProgName(), toDir->name);\r
-\r
-  int success = recman->moveRecording(toMove, toDir);\r
-  if (!VDR::getInstance()->isConnected())\r
-  {\r
-    Command::getInstance()->connectionLost();\r
-    return;\r
-  }\r
-\r
-  if (success != 1)\r
-  {\r
-    VInfo* vi = new VInfo();\r
-    vi->setSize(360, 200);\r
-    vi->createBuffer();\r
-    if (Video::getInstance()->getFormat() == Video::PAL)\r
-      vi->setPosition(190, 170);\r
-    else\r
-      vi->setPosition(180, 120);\r
-    vi->setOneLiner(tr("Failed to move recording"));\r
-    vi->setExitable();\r
-    vi->setBorderOn(1);\r
-    vi->setTitleBarColour(DrawStyle::DANGER);\r
-    vi->okButton();\r
-    vi->draw();\r
-    boxstack->add(vi);\r
-    boxstack->update(vi);\r
-  }\r
-  else\r
-  {\r
-    draw();\r
-    boxstack->update(this);\r
-  }\r
-}\r
-\r
-int VRecordingList::doPlay(bool resume)\r
-{\r
-  Recording* toPlay = getCurrentOptionRecording();\r
-  if (toPlay)\r
-  {\r
-    toPlay->loadRecInfo(); // check if still need this\r
-    toPlay->loadMarks();\r
-       bool ish264;\r
-\r
-    bool isRadio = toPlay->isRadio(ish264);\r
-\r
-    if (isRadio)\r
-    {\r
-      VRadioRec* radrec = new VRadioRec(toPlay);\r
-      radrec->draw();\r
-      boxstack->add(radrec);\r
-      boxstack->update(radrec);\r
-      radrec->go();\r
-    }\r
-    else\r
-    {\r
-               if (ish264 && !Video::getInstance()->supportsh264()) {\r
-                       VInfo* vi = new VInfo();\r
-                       vi->setSize(360, 200);\r
-                       vi->createBuffer();\r
-                       if (Video::getInstance()->getFormat() == Video::PAL)\r
-                               vi->setPosition(190, 170);\r
-                       else\r
-                               vi->setPosition(180, 120);\r
-                       vi->setOneLiner(tr("H264 video not supported"));\r
-                       vi->setExitable();\r
-                       vi->setBorderOn(1);\r
-                       vi->setTitleBarColour(DrawStyle::DANGER);\r
-                       vi->okButton();\r
-                       vi->draw();\r
-                       boxstack->add(vi);\r
-                       boxstack->update(vi);\r
-                       \r
-               } else {\r
-                       VVideoRec* vidrec = new VVideoRec(toPlay, ish264);\r
-                       vidrec->draw();\r
-                       boxstack->add(vidrec);\r
-                       boxstack->update(vidrec);\r
-                       vidrec->go(resume);\r
-               }\r
-    }\r
-    return 1;\r
-  }\r
-  // should not get to here\r
-  return 0;\r
-}\r
-\r
-Recording* VRecordingList::getCurrentOptionRecording()\r
-{\r
-  Recording* currentRec;\r
-  RecordingList::iterator j;\r
-  RecordingList* recList = recman->getRecordings();\r
-  for (j = recList->begin(); j != recList->end(); j++)\r
-  {\r
-    currentRec = *j;\r
-    if (currentRec->index == sl.getCurrentOption()) return currentRec;\r
-  }\r
-\r
-  return NULL;\r
-}\r
-\r
-int VRecordingList::handleCommand(int command)\r
-{\r
-  switch(command)\r
-  {\r
-    case Remote::DF_UP:\r
-    case Remote::UP:\r
-    {\r
-      sl.up();\r
-      sl.draw();\r
-\r
-      doShowingBar();\r
-      boxstack->update(this);\r
-      return 2;\r
-    }\r
-    case Remote::DF_DOWN:\r
-    case Remote::DOWN:\r
-    {\r
-      sl.down();\r
-      sl.draw();\r
-\r
-      doShowingBar();\r
-      boxstack->update(this);\r
-      return 2;\r
-    }\r
-    case Remote::SKIPBACK:\r
-    {\r
-      sl.pageUp();\r
-      sl.draw();\r
-\r
-      doShowingBar();\r
-      boxstack->update(this);\r
-      return 2;\r
-    }\r
-    case Remote::SKIPFORWARD:\r
-    {\r
-      sl.pageDown();\r
-      sl.draw();\r
-\r
-      doShowingBar();\r
-      boxstack->update(this);\r
-      return 2;\r
-    }\r
-    case Remote::OK:\r
-    {\r
-      if (sl.getNumOptions() == 0) return 2;\r
-\r
-      // Check to see if it is a sub directory\r
-      Directory* currentSubDir;\r
-      DirectoryList::iterator i;\r
-      DirectoryList* dirList = recman->getDirectories();\r
-      for (i = dirList->begin(); i != dirList->end(); i++)\r
-      {\r
-        currentSubDir = *i;\r
-        if (currentSubDir->index == sl.getCurrentOption())\r
-        {\r
-          if (recman->down(currentSubDir))\r
-          {\r
-            slIndexStack.push(sl.getCurrentOption());\r
-            sl.clear();\r
-            draw();\r
-            boxstack->update(this);\r
-          }\r
-          return 2;\r
-        }\r
-      }\r
-\r
-      // check to see if it's a recording\r
-      Recording* current = getCurrentOptionRecording();\r
-      if (current)\r
-      {\r
-        Log::getInstance()->log("VRecordingList", Log::DEBUG, "Found the option you pointed at. %s %s", current->getProgName(), current->getFileName());\r
-\r
-/*\r
-        VRecordingMenu* v = new VRecordingMenu(recman);\r
-        v->setParent(this);\r
-        v->setRecording(current);\r
-        v->draw();\r
-        boxstack->add(v);\r
-        boxstack->update(v);\r
-*/        \r
-        VRecording* vr = new VRecording(recman, current);\r
-        vr->setParent(this);\r
-        vr->draw();\r
-        boxstack->add(vr);\r
-        boxstack->update(vr);\r
-        \r
-        return 2;\r
-      }\r
-      // should not get to here\r
-      return 1;\r
-    }\r
-    case Remote::BACK:\r
-    {\r
-      if (recman->isSubDir())\r
-      {\r
-        recman->up();\r
-        sl.clear();\r
-        draw(true);\r
-        boxstack->update(this);\r
-        return 2;\r
-      }\r
-      else\r
-      {\r
-        return 4;\r
-      }\r
-    }\r
-    case Remote::PLAYPAUSE:\r
-    case Remote::PLAY:\r
-    {\r
-      if (doPlay(true)) return 2;\r
-      return 1;\r
-    }\r
-    case Remote::LEFT:\r
-    case Remote::RIGHT:\r
-    case Remote::ZERO:\r
-    {\r
-      reSort();\r
-      return 2;\r
-    }\r
-  }\r
-  // stop command getting to any more views\r
-  return 1;\r
-}\r
-\r
-bool VRecordingList::load()\r
-{\r
-  VDR* vdr = VDR::getInstance();\r
-\r
-  recman = new RecMan();\r
-\r
-  bool success = vdr->getRecordingsList(recman);\r
-\r
-  if (success)\r
-  {\r
-    loading = false;\r
-    char* defaultSortOrder = vdr->configLoad("General", "Recordings Sort Order");\r
-    if (defaultSortOrder)\r
-    {\r
-      if (!STRCASECMP(defaultSortOrder, "Chronological")) recman->setSortOrderChron();\r
-      delete[] defaultSortOrder;\r
-    }\r
-    recman->sort();\r
-    draw();\r
-    boxstack->update(this);\r
-  }\r
-\r
-  return success;\r
-}\r
-\r
-void VRecordingList::reSort()\r
-{\r
-  recman->toggleSortOrder();\r
-  recman->sort();\r
-  sl.clear();\r
-  draw();\r
-  boxstack->update(this);\r
-}\r
-\r
+/*
+    Copyright 2004-2007 Chris Tallon
+
+    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 "vrecordinglist.h"
+
+#include "recman.h"
+#include "directory.h"
+#include "recording.h"
+#include "remote.h"
+#include "wsymbol.h"
+#include "boxstack.h"
+#include "vrecordingmenu.h"
+#include "vrecording.h"
+#include "vdr.h"
+#include "vvideorec.h"
+#include "vradiorec.h"
+#include "colour.h"
+#include "video.h"
+#include "i18n.h"
+#include "command.h"
+#include "vinfo.h"
+#include "log.h"
+
+VRecordingList::VRecordingList()
+{
+  boxstack = BoxStack::getInstance();
+  recman = NULL;
+  loading = true;
+
+  setSize(570, 420);
+  createBuffer();
+  if (Video::getInstance()->getFormat() == Video::PAL)
+  {
+    setPosition(80, 70);
+  }
+  else
+  {
+    setPosition(70, 35);
+  }
+
+  setTitleBarOn(1);
+  setTitleBarColour(DrawStyle::TITLEBARBACKGROUND);
+
+  sl.setPosition(10, 30 + 5);
+  sl.setSize(area.w - 20, area.h - 30 - 15 - 30);
+  add(&sl);
+}
+
+VRecordingList::~VRecordingList()
+{
+  delete recman;
+}
+
+void VRecordingList::drawData(bool doIndexPop)
+{
+  int saveIndex = sl.getCurrentOption();
+  int saveTop = sl.getTopOption();
+  sl.clear();
+  sl.addColumn(0);
+  sl.addColumn(110);
+
+  int first = 1;
+
+  char tempA[300]; // FIXME  this is guesswork!
+  char tempB[300]; // FIXME
+  struct tm* btime;
+
+  Directory* currentSubDir;
+  DirectoryList::iterator i;
+  DirectoryList* dirList = recman->getDirectories();
+  for (i = dirList->begin(); i != dirList->end(); i++)
+  {
+    currentSubDir = *i;
+    SNPRINTF(tempA, 299, tr("<dir> %lu\t%s"), currentSubDir->getNumRecordings(), currentSubDir->name);
+    currentSubDir->index = sl.addOption(tempA, 0, first);
+    first = 0;
+  }
+  // FIXME convert the whole program to time_t's
+
+  Recording* currentRec;
+  RecordingList::iterator j;
+  RecordingList* recList = recman->getRecordings();
+  for (j = recList->begin(); j != recList->end(); j++)
+  {
+    currentRec = *j;
+    time_t recStartTime = (time_t)currentRec->getStartTime();
+    btime = localtime(&recStartTime);
+//NMT does not like this too!
+       //#ifndef _MSC_VER
+//    strftime(tempA, 299, "%0d/%0m %0H:%0M ", btime);
+//#else
+    strftime(tempA, 299, "%d/%m %H:%M ", btime);
+//#endif
+    sprintf(tempB, "%s\t%s", tempA, currentRec->getProgName());
+    currentRec->index = sl.addOption(tempB, 0, first);
+    first = 0;
+  }
+
+  if (doIndexPop)
+  {
+    sl.hintSetCurrent(slIndexStack.top());
+    slIndexStack.pop();
+  }
+  else
+  {
+    sl.hintSetCurrent(saveIndex);
+    sl.hintSetTop(saveTop);
+  }
+  sl.draw();
+  doShowingBar();
+}
+
+void VRecordingList::draw(bool doIndexPop)
+{
+  if (!loading)
+  {
+    if (recman->isSubDir())
+    {
+      char title[300];
+      SNPRINTF(title, 299, tr("Recordings - %s"), recman->getCurDirName());
+      setTitleText(title, 364);
+    }
+    else
+    {
+      setTitleText(tr("Recordings"));
+    }
+  }
+
+  TBBoxx::draw();
+
+  if (loading)
+  {
+    drawText(tr("Loading..."), 240, 180, DrawStyle::LIGHTTEXT);
+  }
+  else
+  {
+    char freeSpace[50];
+    int gigFree = recman->getFreeSpace() / 1024;
+    SNPRINTF(freeSpace, 49, tr("%lu%% used, %iGB free"), recman->getUsedPercent(), gigFree);
+    drawTextRJ(freeSpace, 560, 5, DrawStyle::LIGHTTEXT);
+    // Symbols
+
+    WSymbol w;
+    TEMPADD(&w);
+    w.nextSymbol = WSymbol::UP;
+    w.setPosition(20, 385);
+    w.draw();
+    w.nextSymbol = WSymbol::DOWN;
+    w.setPosition(50, 385);
+    w.draw();
+    w.nextSymbol = WSymbol::SKIPBACK;
+    w.setPosition(85, 385);
+    w.draw();
+    w.nextSymbol = WSymbol::SKIPFORWARD;
+    w.setPosition(115, 385);
+    w.draw();
+    w.nextSymbol = WSymbol::PLAY;
+    w.setPosition(150, 385);
+    w.draw();
+    drawTextRJ(tr("[ok] = menu"), 560, 385, DrawStyle::LIGHTTEXT);
+
+    // All static stuff done
+    drawData(doIndexPop);
+  }
+}
+
+void VRecordingList::doShowingBar()
+{
+  int topOption = sl.getTopOption() + 1;
+  if (sl.getNumOptions() == 0) topOption = 0;
+
+  rectangle(220, 385, 180, 25, DrawStyle::VIEWBACKGROUND);
+  char showing[200];
+  sprintf(showing, tr("%i to %i of %i"), topOption, sl.getBottomOption(), sl.getNumOptions());
+  drawText(showing, 220, 385, DrawStyle::LIGHTTEXT);
+}
+
+void VRecordingList::processMessage(Message* m)
+{
+  Log::getInstance()->log("VRecordingList", Log::DEBUG, "Got message value %lu", m->message);
+
+  if (m->message == Message::MOUSE_MOVE)
+  {
+    if (sl.mouseMove((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))
+    {
+      sl.draw();
+      doShowingBar();
+      boxstack->update(this);
+    }
+  }
+  else if (m->message == Message::MOUSE_LBDOWN)
+  {
+    if (sl.mouseLBDOWN((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))
+    {
+      boxstack->handleCommand(Remote::OK); //simulate OK press
+    }
+    else
+    {
+      //check if press is outside this view! then simulate cancel
+      int x=(m->parameter>>16)-getScreenX();
+      int y=(m->parameter&0xFFFF)-getScreenY();
+      if (x<0 || y <0 || x>(int)getWidth() || y>(int)getHeight())
+      {
+        boxstack->handleCommand(Remote::BACK); //simulate cancel press
+      }
+    }
+  }
+  else if (m->message == Message::DELETE_SELECTED_RECORDING)
+  {
+    Log::getInstance()->log("VRecordingList", Log::DEBUG, "Doing delete selected");
+    doDeleteSelected();
+  }
+  else if (m->message == Message::MOVE_RECORDING)
+  {
+    Log::getInstance()->log("VRecordingList", Log::DEBUG, "Doing move recording");
+    doMoveRecording((Directory*)m->parameter);
+  }
+  else if (m->message == Message::PLAY_SELECTED_RECORDING)
+  {
+    doPlay(false);
+  }
+  else if (m->message == Message::RESUME_SELECTED_RECORDING)
+  {
+    doPlay(true);
+  }
+}
+
+void VRecordingList::doDeleteSelected()
+{
+  Recording* toDelete = getCurrentOptionRecording();
+
+  if (!toDelete) return;
+
+  Log::getInstance()->log("VRecordingList", Log::DEBUG, "FOUND: %i %s %s", toDelete->index, toDelete->getProgName(), toDelete->getFileName());
+
+  int success = recman->deleteRecording(toDelete);
+  if (!VDR::getInstance()->isConnected())
+  {
+    Command::getInstance()->connectionLost();
+    return;
+  }
+
+  if (success != 1)
+  {
+    VInfo* vi = new VInfo();
+    vi->setSize(360, 200);
+    vi->createBuffer();
+    if (Video::getInstance()->getFormat() == Video::PAL)
+      vi->setPosition(190, 170);
+    else
+      vi->setPosition(180, 120);
+    vi->setOneLiner(tr("Failed to delete recording"));
+    vi->setExitable();
+    vi->setBorderOn(1);
+    vi->setTitleBarColour(DrawStyle::DANGER);
+    vi->okButton();
+    vi->draw();
+    boxstack->add(vi);
+    boxstack->update(vi);
+  }
+  else
+  {
+    draw();
+    boxstack->update(this);
+  }
+
+}
+
+void VRecordingList::doMoveRecording(Directory* toDir)
+{
+  Recording* toMove = getCurrentOptionRecording();
+  if (!toMove || !toDir) return;
+
+  Log::getInstance()->log("VRecordingList", Log::DEBUG, "MOVE: %s %s", toMove->getProgName(), toDir->name);
+
+  int success = recman->moveRecording(toMove, toDir);
+  if (!VDR::getInstance()->isConnected())
+  {
+    Command::getInstance()->connectionLost();
+    return;
+  }
+
+  if (success != 1)
+  {
+    VInfo* vi = new VInfo();
+    vi->setSize(360, 200);
+    vi->createBuffer();
+    if (Video::getInstance()->getFormat() == Video::PAL)
+      vi->setPosition(190, 170);
+    else
+      vi->setPosition(180, 120);
+    vi->setOneLiner(tr("Failed to move recording"));
+    vi->setExitable();
+    vi->setBorderOn(1);
+    vi->setTitleBarColour(DrawStyle::DANGER);
+    vi->okButton();
+    vi->draw();
+    boxstack->add(vi);
+    boxstack->update(vi);
+  }
+  else
+  {
+    draw();
+    boxstack->update(this);
+  }
+}
+
+int VRecordingList::doPlay(bool resume)
+{
+  Recording* toPlay = getCurrentOptionRecording();
+  if (toPlay)
+  {
+    toPlay->loadRecInfo(); // check if still need this
+    toPlay->loadMarks();
+       bool ish264;
+
+    bool isRadio = toPlay->isRadio(ish264);
+
+    if (isRadio)
+    {
+      VRadioRec* radrec = new VRadioRec(toPlay);
+      radrec->draw();
+      boxstack->add(radrec);
+      boxstack->update(radrec);
+      radrec->go();
+    }
+    else
+    {
+               if (ish264 && !Video::getInstance()->supportsh264()) {
+                       VInfo* vi = new VInfo();
+                       vi->setSize(360, 200);
+                       vi->createBuffer();
+                       if (Video::getInstance()->getFormat() == Video::PAL)
+                               vi->setPosition(190, 170);
+                       else
+                               vi->setPosition(180, 120);
+                       vi->setOneLiner(tr("H264 video not supported"));
+                       vi->setExitable();
+                       vi->setBorderOn(1);
+                       vi->setTitleBarColour(DrawStyle::DANGER);
+                       vi->okButton();
+                       vi->draw();
+                       boxstack->add(vi);
+                       boxstack->update(vi);
+                       
+               } else {
+                       VVideoRec* vidrec = new VVideoRec(toPlay, ish264);
+                       vidrec->draw();
+                       boxstack->add(vidrec);
+                       boxstack->update(vidrec);
+                       vidrec->go(resume);
+               }
+    }
+    return 1;
+  }
+  // should not get to here
+  return 0;
+}
+
+Recording* VRecordingList::getCurrentOptionRecording()
+{
+  Recording* currentRec;
+  RecordingList::iterator j;
+  RecordingList* recList = recman->getRecordings();
+  for (j = recList->begin(); j != recList->end(); j++)
+  {
+    currentRec = *j;
+    if (currentRec->index == sl.getCurrentOption()) return currentRec;
+  }
+
+  return NULL;
+}
+
+int VRecordingList::handleCommand(int command)
+{
+  switch(command)
+  {
+    case Remote::DF_UP:
+    case Remote::UP:
+    {
+      sl.up();
+      sl.draw();
+
+      doShowingBar();
+      boxstack->update(this);
+      return 2;
+    }
+    case Remote::DF_DOWN:
+    case Remote::DOWN:
+    {
+      sl.down();
+      sl.draw();
+
+      doShowingBar();
+      boxstack->update(this);
+      return 2;
+    }
+    case Remote::SKIPBACK:
+    {
+      sl.pageUp();
+      sl.draw();
+
+      doShowingBar();
+      boxstack->update(this);
+      return 2;
+    }
+    case Remote::SKIPFORWARD:
+    {
+      sl.pageDown();
+      sl.draw();
+
+      doShowingBar();
+      boxstack->update(this);
+      return 2;
+    }
+    case Remote::OK:
+    {
+      if (sl.getNumOptions() == 0) return 2;
+
+      // Check to see if it is a sub directory
+      Directory* currentSubDir;
+      DirectoryList::iterator i;
+      DirectoryList* dirList = recman->getDirectories();
+      for (i = dirList->begin(); i != dirList->end(); i++)
+      {
+        currentSubDir = *i;
+        if (currentSubDir->index == sl.getCurrentOption())
+        {
+          if (recman->down(currentSubDir))
+          {
+            slIndexStack.push(sl.getCurrentOption());
+            sl.clear();
+            draw();
+            boxstack->update(this);
+          }
+          return 2;
+        }
+      }
+
+      // check to see if it's a recording
+      Recording* current = getCurrentOptionRecording();
+      if (current)
+      {
+        Log::getInstance()->log("VRecordingList", Log::DEBUG, "Found the option you pointed at. %s %s", current->getProgName(), current->getFileName());
+
+/*
+        VRecordingMenu* v = new VRecordingMenu(recman);
+        v->setParent(this);
+        v->setRecording(current);
+        v->draw();
+        boxstack->add(v);
+        boxstack->update(v);
+*/        
+        VRecording* vr = new VRecording(recman, current);
+        vr->setParent(this);
+        vr->draw();
+        boxstack->add(vr);
+        boxstack->update(vr);
+        
+        return 2;
+      }
+      // should not get to here
+      return 1;
+    }
+    case Remote::BACK:
+    {
+      if (recman->isSubDir())
+      {
+        recman->up();
+        sl.clear();
+        draw(true);
+        boxstack->update(this);
+        return 2;
+      }
+      else
+      {
+        return 4;
+      }
+    }
+    case Remote::PLAYPAUSE:
+    case Remote::PLAY:
+    {
+      if (doPlay(true)) return 2;
+      return 1;
+    }
+    case Remote::LEFT:
+    case Remote::RIGHT:
+    case Remote::ZERO:
+    {
+      reSort();
+      return 2;
+    }
+  }
+  // stop command getting to any more views
+  return 1;
+}
+
+bool VRecordingList::load()
+{
+  VDR* vdr = VDR::getInstance();
+
+  recman = new RecMan();
+
+  bool success = vdr->getRecordingsList(recman);
+
+  if (success)
+  {
+    loading = false;
+    char* defaultSortOrder = vdr->configLoad("General", "Recordings Sort Order");
+    if (defaultSortOrder)
+    {
+      if (!STRCASECMP(defaultSortOrder, "Chronological")) recman->setSortOrderChron();
+      delete[] defaultSortOrder;
+    }
+    recman->sort();
+    draw();
+    boxstack->update(this);
+  }
+
+  return success;
+}
+
+void VRecordingList::reSort()
+{
+  recman->toggleSortOrder();
+  recman->sort();
+  sl.clear();
+  draw();
+  boxstack->update(this);
+}
+
index 113bf6b3a40a4132bdde8091a9f1da9a1090d0c0..de95dc1fc66a91d6ab32845f6edc44d705a529e7 100644 (file)
-/*\r
-    Copyright 2005-2008 Chris Tallon, Marten Richter\r
-\r
-    This file is part of VOMP.\r
-\r
-    VOMP is free software; you can redistribute it and/or modify\r
-    it under the terms of the GNU General Public License as published by\r
-    the Free Software Foundation; either version 2 of the License, or\r
-    (at your option) any later version.\r
-\r
-    VOMP is distributed in the hope that it will be useful,\r
-    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-    GNU General Public License for more details.\r
-\r
-    You should have received a copy of the GNU General Public License\r
-    along with VOMP; if not, write to the Free Software\r
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
-*/\r
-#include <math.h>\r
-#include "vteletextview.h"\r
-#include "video.h"\r
-#include "timers.h"\r
-#include "boxstack.h"\r
-#include "remote.h"\r
-\r
-\r
-VTeletextView::VTeletextView(TeletextDecoderVBIEBU* TTdecoder,Boxx* playerview)\r
-{   \r
-    ttdecoder=TTdecoder;\r
-    pv=playerview;\r
-    subtitlemode=false;\r
-    \r
-    \r
-\r
-    if (Video::getInstance()->getFormat() == Video::PAL)\r
-    { \r
-        //setSize(680, 550);\r
-        setSize(680,22); //Only first line\r
-        setPosition(40, 26);\r
-    }\r
-    else\r
-    {\r
-        setPosition(40, 30);\r
-        //setSize(680, 450);\r
-        setSize(680,18);//only first line\r
-    }\r
-    createBuffer();\r
-    keyindigit=1;\r
-    page=0x100;\r
-    \r
-}\r
-\r
-VTeletextView::~VTeletextView ()\r
-{\r
-    // Make sure the timer is deleted\r
-       Log::getInstance()->log("VTeletextView", Log::DEBUG, "VTeletextView destruct");\r
-  pv->draw();\r
-  BoxStack::getInstance()->update(pv);\r
-  Timers::getInstance()->cancelTimer(this, 1);\r
-  ttdecoder->unRegisterTeletextView(this);\r
-    \r
-}\r
-\r
-void VTeletextView::draw(bool completedraw, bool onlyfirstline)\r
-{\r
-       //Log::getInstance()->log("VTeletextView", Log::ERR, "Start draw");\r
-    Boxx::draw();\r
-    int x,y;\r
-    \r
-    Boxx *drawtarget=NULL;\r
-    int ox,oy;\r
-    for (y=0;y<25;y++) {\r
-       if (y==0) {\r
-               drawtarget=this;\r
-               ox=0;\r
-               oy=0;\r
-       } else {\r
-               drawtarget=pv;\r
-               ox=this->getScreenX();\r
-               oy=this->getScreenY();\r
-       }\r
-\r
-        for (x=0;x<40;x++) {\r
-            if (ttdecoder->isDirty(x,y) || completedraw) {\r
-                cTeletextChar c=ttdecoder->getChar(x,y);\r
-                c.SetDirty(false);\r
-                //Skip Blinking and conceal\r
-                drawtarget->drawTTChar(ox,oy,x,y,c);\r
-                ttdecoder->setChar(x,y,c);\r
-            }\r
-        }\r
-    //    Log::getInstance()->log("VTeletextView", Log::ERR, "Line %d",y);\r
-        if (onlyfirstline) break;\r
-    }\r
-  //  Log::getInstance()->log("VTeletextView", Log::ERR, "Start end");\r
-   \r
-    \r
-}\r
-\r
-\r
-\r
-\r
-\r
-int VTeletextView::handleCommand(int command) {\r
-    if (subtitlemode) return 0; //Ok we are in  subtitle mode, we are a slave of the player\r
-    switch (command) {\r
-    case Remote::OK:\r
-        return 2;\r
-    case Remote::BACK:\r
-        return 4;\r
-     case Remote::ZERO:\r
-    case Remote::ONE:\r
-    case Remote::TWO:\r
-    case Remote::THREE:\r
-    case Remote::FOUR:\r
-    case Remote::FIVE:\r
-    case Remote::SIX:\r
-    case Remote::SEVEN:\r
-    case Remote::EIGHT:\r
-    case Remote::NINE:\r
-    {\r
-      // key in teletext page\r
-      doKey(command);\r
-      return 2;\r
-    }\r
-    };\r
-\r
-    return 0;\r
-    \r
-}\r
-\r
-void VTeletextView::doKey(int command)\r
-{\r
-    char pagenums[3];\r
-    if (keyindigit==1){\r
-        if (command==9) return; //not allowed\r
-        page=command<<8;\r
-        pagenums[0]=command+ 48;\r
-        pagenums[1]='-';\r
-        pagenums[2]='-';\r
-        keyindigit++;\r
-    } else if (keyindigit==2) {\r
-        page|=command<<4;\r
-        pagenums[0]=48+((page &0xF00)>>8);\r
-        pagenums[1]=command+ 48;\r
-        pagenums[2]='-';\r
-        keyindigit++;\r
-    } else if (keyindigit==3) {\r
-        page|=command;\r
-        pagenums[0]=48+((page &0xF00)>>8);\r
-        pagenums[1]=48+((page &0x0F0)>>4);\r
-        pagenums[2]=48+command;\r
-        keyindigit=1;\r
-        ttdecoder->setPage(page);\r
-    }\r
-    ttdecoder->setKeyinDigits(pagenums,true);\r
-    Region toupdate;\r
-    toupdate.w=16*40;\r
-    if (Video::getInstance()->getFormat() == Video::PAL) {\r
-        toupdate.h=22;\r
-        \r
-     } else {\r
-        toupdate.h=18;\r
-        \r
-      }\r
-     toupdate.x=0;\r
-     toupdate.y=0;\r
-            \r
-     draw(false,true);\r
-     BoxStack::getInstance()->update(this,&toupdate);\r
-\r
-}\r
-\r
-void VTeletextView::timercall(int clientReference)\r
-{\r
-    \r
-}\r
-\r
-void VTeletextView::processMessage(Message* m)\r
-{\r
-    if (m->message == Message::TELETEXTUPDATE)\r
-    {\r
-        draw(false,false);\r
-        BoxStack::getInstance()->update(this);\r
-        BoxStack::getInstance()->update(pv);\r
-\r
-    } else if (m->message == Message::TELETEXTUPDATEFIRSTLINE) \r
-    {\r
-        Region toupdate;\r
-        toupdate.w=16*40;\r
-        if (Video::getInstance()->getFormat() == Video::PAL) {\r
-            toupdate.h=22;\r
-            \r
-        } else {\r
-            toupdate.h=18;\r
-            \r
-        }\r
-        toupdate.x=0;\r
-        toupdate.y=0;\r
-\r
-\r
-            \r
-        draw(false,true);\r
-        BoxStack::getInstance()->update(this,&toupdate);\r
-\r
-    }\r
-}\r
-\r
-\r
+/*
+    Copyright 2005-2008 Chris Tallon, 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 <math.h>
+#include "vteletextview.h"
+#include "video.h"
+#include "timers.h"
+#include "boxstack.h"
+#include "remote.h"
+
+
+VTeletextView::VTeletextView(TeletextDecoderVBIEBU* TTdecoder,Boxx* playerview)
+{   
+    ttdecoder=TTdecoder;
+    pv=playerview;
+    subtitlemode=false;
+    
+    
+
+    if (Video::getInstance()->getFormat() == Video::PAL)
+    { 
+        //setSize(680, 550);
+        setSize(680,22); //Only first line
+        setPosition(40, 26);
+    }
+    else
+    {
+        setPosition(40, 30);
+        //setSize(680, 450);
+        setSize(680,18);//only first line
+    }
+    createBuffer();
+    keyindigit=1;
+    page=0x100;
+    
+}
+
+VTeletextView::~VTeletextView ()
+{
+    // Make sure the timer is deleted
+       Log::getInstance()->log("VTeletextView", Log::DEBUG, "VTeletextView destruct");
+  pv->draw();
+  BoxStack::getInstance()->update(pv);
+  Timers::getInstance()->cancelTimer(this, 1);
+  ttdecoder->unRegisterTeletextView(this);
+    
+}
+
+void VTeletextView::draw(bool completedraw, bool onlyfirstline)
+{
+       //Log::getInstance()->log("VTeletextView", Log::ERR, "Start draw");
+    Boxx::draw();
+    int x,y;
+    
+    Boxx *drawtarget=NULL;
+    int ox,oy;
+    for (y=0;y<25;y++) {
+       if (y==0) {
+               drawtarget=this;
+               ox=0;
+               oy=0;
+       } else {
+               drawtarget=pv;
+               ox=this->getScreenX();
+               oy=this->getScreenY();
+       }
+
+        for (x=0;x<40;x++) {
+            if (ttdecoder->isDirty(x,y) || completedraw) {
+                cTeletextChar c=ttdecoder->getChar(x,y);
+                c.SetDirty(false);
+                //Skip Blinking and conceal
+                drawtarget->drawTTChar(ox,oy,x,y,c);
+                ttdecoder->setChar(x,y,c);
+            }
+        }
+    //    Log::getInstance()->log("VTeletextView", Log::ERR, "Line %d",y);
+        if (onlyfirstline) break;
+    }
+  //  Log::getInstance()->log("VTeletextView", Log::ERR, "Start end");
+   
+    
+}
+
+
+
+
+
+int VTeletextView::handleCommand(int command) {
+    if (subtitlemode) return 0; //Ok we are in  subtitle mode, we are a slave of the player
+    switch (command) {
+    case Remote::OK:
+        return 2;
+    case Remote::BACK:
+        return 4;
+     case Remote::ZERO:
+    case Remote::ONE:
+    case Remote::TWO:
+    case Remote::THREE:
+    case Remote::FOUR:
+    case Remote::FIVE:
+    case Remote::SIX:
+    case Remote::SEVEN:
+    case Remote::EIGHT:
+    case Remote::NINE:
+    {
+      // key in teletext page
+      doKey(command);
+      return 2;
+    }
+    };
+
+    return 0;
+    
+}
+
+void VTeletextView::doKey(int command)
+{
+    char pagenums[3];
+    if (keyindigit==1){
+        if (command==9) return; //not allowed
+        page=command<<8;
+        pagenums[0]=command+ 48;
+        pagenums[1]='-';
+        pagenums[2]='-';
+        keyindigit++;
+    } else if (keyindigit==2) {
+        page|=command<<4;
+        pagenums[0]=48+((page &0xF00)>>8);
+        pagenums[1]=command+ 48;
+        pagenums[2]='-';
+        keyindigit++;
+    } else if (keyindigit==3) {
+        page|=command;
+        pagenums[0]=48+((page &0xF00)>>8);
+        pagenums[1]=48+((page &0x0F0)>>4);
+        pagenums[2]=48+command;
+        keyindigit=1;
+        ttdecoder->setPage(page);
+    }
+    ttdecoder->setKeyinDigits(pagenums,true);
+    Region toupdate;
+    toupdate.w=16*40;
+    if (Video::getInstance()->getFormat() == Video::PAL) {
+        toupdate.h=22;
+        
+     } else {
+        toupdate.h=18;
+        
+      }
+     toupdate.x=0;
+     toupdate.y=0;
+            
+     draw(false,true);
+     BoxStack::getInstance()->update(this,&toupdate);
+
+}
+
+void VTeletextView::timercall(int clientReference)
+{
+    
+}
+
+void VTeletextView::processMessage(Message* m)
+{
+    if (m->message == Message::TELETEXTUPDATE)
+    {
+        draw(false,false);
+        BoxStack::getInstance()->update(this);
+        BoxStack::getInstance()->update(pv);
+
+    } else if (m->message == Message::TELETEXTUPDATEFIRSTLINE) 
+    {
+        Region toupdate;
+        toupdate.w=16*40;
+        if (Video::getInstance()->getFormat() == Video::PAL) {
+            toupdate.h=22;
+            
+        } else {
+            toupdate.h=18;
+            
+        }
+        toupdate.x=0;
+        toupdate.y=0;
+
+
+            
+        draw(false,true);
+        BoxStack::getInstance()->update(this,&toupdate);
+
+    }
+}
+
+
index af3b5c9efd1490fb10febdebd7b60b21f4803cde..01bf5e08fe895c32c1708040907129d72f69553a 100644 (file)
@@ -1,64 +1,64 @@
-/*\r
-    Copyright 2005-2008 Chris Tallon, Marten Richter\r
-\r
-    This file is part of VOMP.\r
-\r
-    VOMP is free software; you can redistribute it and/or modify\r
-    it under the terms of the GNU General Public License as published by\r
-    the Free Software Foundation; either version 2 of the License, or\r
-    (at your option) any later version.\r
-\r
-    VOMP is distributed in the hope that it will be useful,\r
-    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-    GNU General Public License for more details.\r
-\r
-    You should have received a copy of the GNU General Public License\r
-    along with VOMP; if not, write to the Free Software\r
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
-*/\r
-\r
-#ifndef VTELETEXTVIEW_H\r
-#define VTELETEXTVIEW_H\r
-\r
-#include <stdio.h>\r
-\r
-#include "boxx.h"\r
-#include "timerreceiver.h"\r
-#include "teletextdecodervbiebu.h"\r
-\r
-class VTeletextView : public Boxx, public TimerReceiver\r
-{\r
-  public:\r
-    VTeletextView (TeletextDecoderVBIEBU* TTdecoder, Boxx* playerview);\r
-    ~VTeletextView ();\r
-    void draw(bool completedraw, bool onlyfirstline);\r
-    void draw() {draw(true,false);};\r
-\r
-\r
-\r
-\r
-    void processMessage(Message* m);\r
-\r
-    void setSubtitleMode(bool mode) {subtitlemode=mode;};\r
-    bool isInSubtitleMode() {return subtitlemode;};\r
-\r
-    int handleCommand(int command);\r
-    void timercall(int clientReference);\r
-   \r
-\r
-  private:\r
-      void doKey(int command);\r
-    \r
-\r
-  protected:\r
-      TeletextDecoderVBIEBU* ttdecoder;\r
-      int keyindigit;\r
-      int page;\r
-      bool subtitlemode;\r
-     Boxx* pv;\r
-    \r
-\r
-};\r
-\r
-#endif\r
+/*
+    Copyright 2005-2008 Chris Tallon, 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 VTELETEXTVIEW_H
+#define VTELETEXTVIEW_H
+
+#include <stdio.h>
+
+#include "boxx.h"
+#include "timerreceiver.h"
+#include "teletextdecodervbiebu.h"
+
+class VTeletextView : public Boxx, public TimerReceiver
+{
+  public:
+    VTeletextView (TeletextDecoderVBIEBU* TTdecoder, Boxx* playerview);
+    ~VTeletextView ();
+    void draw(bool completedraw, bool onlyfirstline);
+    void draw() {draw(true,false);};
+
+
+
+
+    void processMessage(Message* m);
+
+    void setSubtitleMode(bool mode) {subtitlemode=mode;};
+    bool isInSubtitleMode() {return subtitlemode;};
+
+    int handleCommand(int command);
+    void timercall(int clientReference);
+   
+
+  private:
+      void doKey(int command);
+    
+
+  protected:
+      TeletextDecoderVBIEBU* ttdecoder;
+      int keyindigit;
+      int page;
+      bool subtitlemode;
+     Boxx* pv;
+    
+
+};
+
+#endif
index 2cc3558cbc9613f07930c28e1b314082726c8f77..58e050144474b49a4e24b7b862f8770bbd4b1caa 100644 (file)
-/*\r
-    Copyright 2004-2005 Chris Tallon\r
-\r
-    This file is part of VOMP.\r
-\r
-    VOMP is free software; you can redistribute it and/or modify\r
-    it under the terms of the GNU General Public License as published by\r
-    the Free Software Foundation; either version 2 of the License, or\r
-    (at your option) any later version.\r
-\r
-    VOMP is distributed in the hope that it will be useful,\r
-    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-    GNU General Public License for more details.\r
-\r
-    You should have received a copy of the GNU General Public License\r
-    along with VOMP; if not, write to the Free Software\r
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
-*/\r
-\r
-#include "vtimerlist.h"\r
-\r
-#include "message.h"\r
-#include "remote.h"\r
-#include "wsymbol.h"\r
-#include "colour.h"\r
-#include "video.h"\r
-#include "i18n.h"\r
-#include "timers.h"\r
-#include "vtimeredit.h"\r
-#include "command.h"\r
-#include "boxstack.h"\r
-#include "vdr.h"\r
-#include "vinfo.h"\r
-#include "log.h"\r
-\r
-VTimerList::VTimerList()\r
-{\r
-  recTimerList = NULL;\r
-\r
-  clockRegion.x = 420;\r
-  clockRegion.y = 0;\r
-  clockRegion.w = 150;\r
-  clockRegion.h = 30;\r
-\r
-\r
-\r
-  flipflop = true;\r
-\r
-  setSize(570, 420);\r
-  createBuffer();\r
-\r
-  indicatorsRegion.x = 6;\r
-  indicatorsRegion.y = 44;\r
-  indicatorsRegion.w = 18;\r
-  indicatorsRegion.h = 15 * (getFontHeight() + 1);\r
-\r
-  if (Video::getInstance()->getFormat() == Video::PAL)\r
-  {\r
-    setPosition(80, 70);\r
-  }\r
-  else\r
-  {\r
-    setPosition(70, 35);\r
-  }\r
-\r
-  setTitleBarOn(1);\r
-  setTitleText(tr("Timers"));\r
-  setTitleBarColour(DrawStyle::TITLEBARBACKGROUND);\r
-\r
-  sl.setPosition(30, 30 + 5);\r
-  sl.setSize(area.w - 40, area.h - 30 - 15 - 30);\r
-  add(&sl);\r
-}\r
-\r
-void VTimerList::preDelete()\r
-{\r
-  Timers::getInstance()->cancelTimer(this, 1);\r
-}\r
-\r
-VTimerList::~VTimerList()\r
-{\r
-  if (recTimerList)\r
-  {\r
-    for (UINT i = 0; i < recTimerList->size(); i++)\r
-    {\r
-      delete (*recTimerList)[i];\r
-    }\r
-\r
-    recTimerList->clear();\r
-    delete recTimerList;\r
-  }\r
-}\r
-\r
-void VTimerList::draw()\r
-{\r
-  // Draw statics\r
-\r
-  TBBoxx::draw();\r
-\r
-  WSymbol w;\r
-  TEMPADD(&w);\r
-\r
-  w.nextSymbol = WSymbol::UP;\r
-  w.setPosition(20, 385);\r
-  w.draw();\r
-\r
-  w.nextSymbol = WSymbol::DOWN;\r
-  w.setPosition(50, 385);\r
-  w.draw();\r
-\r
-  w.nextSymbol = WSymbol::SKIPBACK;\r
-  w.setPosition(85, 385);\r
-  w.draw();\r
-\r
-  w.nextSymbol = WSymbol::SKIPFORWARD;\r
-  w.setPosition(115, 385);\r
-  w.draw();\r
-\r
-  drawTextRJ("[ok] = edit", 560, 385, DrawStyle::LIGHTTEXT);\r
-\r
-  drawClock();\r
-  drawShowing();\r
-  drawIndicators();\r
-}\r
-\r
-bool VTimerList::load()\r
-{\r
-  recTimerList = VDR::getInstance()->getRecTimersList();\r
-\r
-  if (!recTimerList) return false;\r
-\r
-  char strA[300];\r
-  char strB[300];\r
-\r
-  struct tm* btime;\r
-\r
-  // FIXME all drawing stuff in this class and sl.clear somewhere?!\r
-\r
-  sl.addColumn(0);\r
-  sl.addColumn(110);\r
-\r
-  RecTimer* recTimer;\r
-  int first = 1;\r
-\r
-  for (UINT i = 0; i < recTimerList->size(); i++)\r
-  {\r
-    recTimer = (*recTimerList)[i];\r
-\r
-    btime = localtime((time_t*)&recTimer->startTime);\r
-    strftime(strA, 299, "%d/%m %H:%M ", btime);\r
-    SNPRINTF(strB, 299, "%s\t%s", strA, recTimer->getName());\r
-    sl.addOption(strB, (ULONG)recTimer, first);\r
-    first = 0;\r
-  }\r
-\r
-  return true;\r
-}\r
-\r
-void VTimerList::drawClock()\r
-{\r
-  // Blank the area first\r
-  rectangle(area.w - 150, 0, 150, 30, titleBarColour);\r
-\r
-  char timeString[20];\r
-  time_t t;\r
-  time(&t);\r
-  struct tm* tms = localtime(&t);\r
-  strftime(timeString, 19, "%d/%m %H:%M:%S", tms);\r
-  drawTextRJ(timeString, 560, 5, DrawStyle::LIGHTTEXT);\r
-\r
-  Timers::getInstance()->setTimerT(this, 1, t + 1);\r
-}\r
-\r
-void VTimerList::drawShowing()\r
-{\r
-  int topOption = sl.getTopOption() + 1;\r
-  if (sl.getNumOptions() == 0) topOption = 0;\r
-\r
-  rectangle(220, 385, 180, 25, DrawStyle::VIEWBACKGROUND);\r
-  char showing[200];\r
-  sprintf(showing, tr("%i to %i of %i"), topOption, sl.getBottomOption(), sl.getNumOptions());\r
-  drawText(showing, 220, 385, DrawStyle::LIGHTTEXT);\r
-}\r
-\r
-void VTimerList::drawIndicators()\r
-{\r
-  int top = sl.getTopOption();\r
-  int bottom = sl.getBottomOption();\r
-  int yinc = getFontHeight() + 1;\r
-  RecTimer* recTimer;\r
-\r
-  rectangle(6, 44, 18, 15*yinc, DrawStyle::VIEWBACKGROUND);\r
-\r
-  // The indexes recorded from the wselectlist into the index member of the RecTimer\r
-  // Is the same as the position in the vector of RecTimers\r
-  // Because they are in order, they don't change order and wselectlist starts from 0 up consecutively\r
-\r
-  int ypos = 44;\r
-  for (int current = top; current < bottom; current++)\r
-  {\r
-    recTimer = (*recTimerList)[current];\r
-\r
-    if (recTimer->recording) // Flashing red square\r
-    {\r
-      if (flipflop)\r
-      {\r
-        rectangle(6, ypos, 18, 16, DrawStyle::RED);\r
-        drawText("R", 8, ypos-3, DrawStyle::LIGHTTEXT);\r
-      }\r
-    }\r
-    else if (recTimer->pending)\r
-    {\r
-      rectangle(6, ypos, 18, 16, DrawStyle::RED);\r
-      drawText("X", 8, ypos-3, DrawStyle::BLACK);\r
-    }\r
-    else if (recTimer->active == 0)\r
-    {\r
-      rectangle(6, ypos, 18, 16, DrawStyle::SELECTHIGHLIGHT);\r
-      drawText("X", 8, ypos-3, DrawStyle::BLACK);\r
-    }\r
-    else\r
-    {\r
-//      if (flipflop) rectangle(6, ypos, 18, 16, DrawStyle::GREEN);\r
-    }\r
-\r
-    ypos += yinc;\r
-  }\r
-}\r
-\r
-void VTimerList::timercall(int clientReference)\r
-{\r
-  drawClock();\r
-  BoxStack::getInstance()->update(this, &clockRegion);\r
-\r
-  flipflop = !flipflop;\r
-  drawIndicators();\r
-  BoxStack::getInstance()->update(this, &indicatorsRegion);\r
-}\r
-\r
-int VTimerList::handleCommand(int command)\r
-{\r
-  switch(command)\r
-  {\r
-    case Remote::DF_UP:\r
-    case Remote::UP:\r
-    {\r
-      sl.up();\r
-      sl.draw();\r
-      drawShowing();\r
-      drawIndicators();\r
-      BoxStack::getInstance()->update(this);\r
-      return 2;\r
-    }\r
-    case Remote::DF_DOWN:\r
-    case Remote::DOWN:\r
-    {\r
-      sl.down();\r
-      sl.draw();\r
-      drawShowing();\r
-      drawIndicators();\r
-      BoxStack::getInstance()->update(this);\r
-      return 2;\r
-    }\r
-    case Remote::SKIPBACK:\r
-    {\r
-      sl.pageUp();\r
-      sl.draw();\r
-      drawShowing();\r
-      drawIndicators();\r
-      BoxStack::getInstance()->update(this);\r
-      return 2;\r
-    }\r
-    case Remote::SKIPFORWARD:\r
-    {\r
-      sl.pageDown();\r
-      sl.draw();\r
-      drawShowing();\r
-      drawIndicators();\r
-      BoxStack::getInstance()->update(this);\r
-      return 2;\r
-    }\r
-    case Remote::OK:\r
-    {\r
-      RecTimer* recTimer = NULL;\r
-      if (recTimerList) recTimer = (RecTimer*)sl.getCurrentOptionData();\r
-      if (recTimer == NULL) return 2;\r
-\r
-      VTimerEdit* v = new VTimerEdit(recTimer);\r
-      v->setParent(this);\r
-      v->draw();\r
-      BoxStack::getInstance()->add(v);\r
-      BoxStack::getInstance()->update(v);\r
-\r
-      return 2;\r
-    }\r
-    case Remote::BACK:\r
-    {\r
-      return 4;\r
-    }\r
-  }\r
-  // stop command getting to any more views\r
-  return 1;\r
-}\r
-\r
-void VTimerList::processMessage(Message* m)\r
-{\r
-  if (m->message == Message::MOUSE_MOVE)\r
-  {\r
-    if (sl.mouseMove((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))\r
-    {\r
-      sl.draw();\r
-      BoxStack::getInstance()->update(this);\r
-    }\r
-  }\r
-  else if (m->message == Message::MOUSE_LBDOWN)\r
-  {\r
-    if (sl.mouseLBDOWN((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))\r
-    {\r
-      BoxStack::getInstance()->handleCommand(Remote::OK); //simulate OK press\r
-    }\r
-    else\r
-    {\r
-      //check if press is outside this view! then simulate cancel\r
-      int x=(m->parameter>>16)-getScreenX();\r
-      int y=(m->parameter&0xFFFF)-getScreenY();\r
-      if (x<0 || y <0 || x>(int)getWidth() || y>(int)getHeight())\r
-      {\r
-        BoxStack::getInstance()->handleCommand(Remote::BACK); //simulate cancel press\r
-      }\r
-    }\r
-  }\r
-  else if (m->message == Message::DELETE_SELECTED_TIMER)\r
-  {\r
-    RecTimer* recTimer = (RecTimer*)sl.getCurrentOptionData();\r
-    if (recTimer == NULL) return;\r
-    Log::getInstance()->log("VTimerList", Log::DEBUG, "Got timer to delete");\r
-\r
-  \r
-    ULONG retval = VDR::getInstance()->deleteTimer(recTimer);\r
-    if (!VDR::getInstance()->isConnected()) { Command::getInstance()->connectionLost(); return; }\r
-    Log::getInstance()->log("VTimerList", Log::DEBUG, "Got return fron delete timer: %lu", retval);\r
-    \r
-    if (retval != 10)\r
-    {\r
-      VInfo* errorBox = new VInfo();\r
-      errorBox->setSize(360, 200);\r
-      errorBox->createBuffer();\r
-      if (Video::getInstance()->getFormat() == Video::PAL)\r
-        errorBox->setPosition(190, 170);\r
-      else\r
-        errorBox->setPosition(180, 120);\r
-\r
-    \r
-      if (retval == 1) errorBox->setOneLiner(tr("Timers being edited at VDR, please try later"));\r
-      else if (retval == 3)  errorBox->setOneLiner(tr("Unable to delete timer - timer is running"));\r
-      else if (retval == 4)  errorBox->setOneLiner(tr("Error - timer not found at VDR"));\r
-      else                   errorBox->setOneLiner(tr("Unknown error"));\r
-\r
-      errorBox->setExitable();\r
-      errorBox->setBorderOn(1);\r
-      errorBox->setTitleBarColour(DrawStyle::DANGER);\r
-      errorBox->okButton();\r
-      errorBox->draw();\r
-      BoxStack::getInstance()->add(errorBox);\r
-      BoxStack::getInstance()->update(errorBox);\r
-    }\r
-    \r
-    int saveIndex = sl.getCurrentOption();\r
-    int saveTop = sl.getTopOption();\r
-     \r
-    if (recTimerList)\r
-    {\r
-      for (UINT i = 0; i < recTimerList->size(); i++)\r
-      {\r
-        delete (*recTimerList)[i];\r
-      }\r
-\r
-      recTimerList->clear();\r
-      delete recTimerList;\r
-    }\r
-\r
-    sl.clear();\r
-    load();\r
-\r
-    sl.hintSetCurrent(saveIndex);\r
-    sl.hintSetTop(saveTop);\r
-    draw();\r
-    BoxStack::getInstance()->update(this);\r
-  }\r
-}\r
-\r
+/*
+    Copyright 2004-2005 Chris Tallon
+
+    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 "vtimerlist.h"
+
+#include "message.h"
+#include "remote.h"
+#include "wsymbol.h"
+#include "colour.h"
+#include "video.h"
+#include "i18n.h"
+#include "timers.h"
+#include "vtimeredit.h"
+#include "command.h"
+#include "boxstack.h"
+#include "vdr.h"
+#include "vinfo.h"
+#include "log.h"
+
+VTimerList::VTimerList()
+{
+  recTimerList = NULL;
+
+  clockRegion.x = 420;
+  clockRegion.y = 0;
+  clockRegion.w = 150;
+  clockRegion.h = 30;
+
+
+
+  flipflop = true;
+
+  setSize(570, 420);
+  createBuffer();
+
+  indicatorsRegion.x = 6;
+  indicatorsRegion.y = 44;
+  indicatorsRegion.w = 18;
+  indicatorsRegion.h = 15 * (getFontHeight() + 1);
+
+  if (Video::getInstance()->getFormat() == Video::PAL)
+  {
+    setPosition(80, 70);
+  }
+  else
+  {
+    setPosition(70, 35);
+  }
+
+  setTitleBarOn(1);
+  setTitleText(tr("Timers"));
+  setTitleBarColour(DrawStyle::TITLEBARBACKGROUND);
+
+  sl.setPosition(30, 30 + 5);
+  sl.setSize(area.w - 40, area.h - 30 - 15 - 30);
+  add(&sl);
+}
+
+void VTimerList::preDelete()
+{
+  Timers::getInstance()->cancelTimer(this, 1);
+}
+
+VTimerList::~VTimerList()
+{
+  if (recTimerList)
+  {
+    for (UINT i = 0; i < recTimerList->size(); i++)
+    {
+      delete (*recTimerList)[i];
+    }
+
+    recTimerList->clear();
+    delete recTimerList;
+  }
+}
+
+void VTimerList::draw()
+{
+  // Draw statics
+
+  TBBoxx::draw();
+
+  WSymbol w;
+  TEMPADD(&w);
+
+  w.nextSymbol = WSymbol::UP;
+  w.setPosition(20, 385);
+  w.draw();
+
+  w.nextSymbol = WSymbol::DOWN;
+  w.setPosition(50, 385);
+  w.draw();
+
+  w.nextSymbol = WSymbol::SKIPBACK;
+  w.setPosition(85, 385);
+  w.draw();
+
+  w.nextSymbol = WSymbol::SKIPFORWARD;
+  w.setPosition(115, 385);
+  w.draw();
+
+  drawTextRJ("[ok] = edit", 560, 385, DrawStyle::LIGHTTEXT);
+
+  drawClock();
+  drawShowing();
+  drawIndicators();
+}
+
+bool VTimerList::load()
+{
+  recTimerList = VDR::getInstance()->getRecTimersList();
+
+  if (!recTimerList) return false;
+
+  char strA[300];
+  char strB[300];
+
+  struct tm* btime;
+
+  // FIXME all drawing stuff in this class and sl.clear somewhere?!
+
+  sl.addColumn(0);
+  sl.addColumn(110);
+
+  RecTimer* recTimer;
+  int first = 1;
+
+  for (UINT i = 0; i < recTimerList->size(); i++)
+  {
+    recTimer = (*recTimerList)[i];
+
+    btime = localtime((time_t*)&recTimer->startTime);
+    strftime(strA, 299, "%d/%m %H:%M ", btime);
+    SNPRINTF(strB, 299, "%s\t%s", strA, recTimer->getName());
+    sl.addOption(strB, (ULONG)recTimer, first);
+    first = 0;
+  }
+
+  return true;
+}
+
+void VTimerList::drawClock()
+{
+  // Blank the area first
+  rectangle(area.w - 150, 0, 150, 30, titleBarColour);
+
+  char timeString[20];
+  time_t t;
+  time(&t);
+  struct tm* tms = localtime(&t);
+  strftime(timeString, 19, "%d/%m %H:%M:%S", tms);
+  drawTextRJ(timeString, 560, 5, DrawStyle::LIGHTTEXT);
+
+  Timers::getInstance()->setTimerT(this, 1, t + 1);
+}
+
+void VTimerList::drawShowing()
+{
+  int topOption = sl.getTopOption() + 1;
+  if (sl.getNumOptions() == 0) topOption = 0;
+
+  rectangle(220, 385, 180, 25, DrawStyle::VIEWBACKGROUND);
+  char showing[200];
+  sprintf(showing, tr("%i to %i of %i"), topOption, sl.getBottomOption(), sl.getNumOptions());
+  drawText(showing, 220, 385, DrawStyle::LIGHTTEXT);
+}
+
+void VTimerList::drawIndicators()
+{
+  int top = sl.getTopOption();
+  int bottom = sl.getBottomOption();
+  int yinc = getFontHeight() + 1;
+  RecTimer* recTimer;
+
+  rectangle(6, 44, 18, 15*yinc, DrawStyle::VIEWBACKGROUND);
+
+  // The indexes recorded from the wselectlist into the index member of the RecTimer
+  // Is the same as the position in the vector of RecTimers
+  // Because they are in order, they don't change order and wselectlist starts from 0 up consecutively
+
+  int ypos = 44;
+  for (int current = top; current < bottom; current++)
+  {
+    recTimer = (*recTimerList)[current];
+
+    if (recTimer->recording) // Flashing red square
+    {
+      if (flipflop)
+      {
+        rectangle(6, ypos, 18, 16, DrawStyle::RED);
+        drawText("R", 8, ypos-3, DrawStyle::LIGHTTEXT);
+      }
+    }
+    else if (recTimer->pending)
+    {
+      rectangle(6, ypos, 18, 16, DrawStyle::RED);
+      drawText("X", 8, ypos-3, DrawStyle::BLACK);
+    }
+    else if (recTimer->active == 0)
+    {
+      rectangle(6, ypos, 18, 16, DrawStyle::SELECTHIGHLIGHT);
+      drawText("X", 8, ypos-3, DrawStyle::BLACK);
+    }
+    else
+    {
+//      if (flipflop) rectangle(6, ypos, 18, 16, DrawStyle::GREEN);
+    }
+
+    ypos += yinc;
+  }
+}
+
+void VTimerList::timercall(int clientReference)
+{
+  drawClock();
+  BoxStack::getInstance()->update(this, &clockRegion);
+
+  flipflop = !flipflop;
+  drawIndicators();
+  BoxStack::getInstance()->update(this, &indicatorsRegion);
+}
+
+int VTimerList::handleCommand(int command)
+{
+  switch(command)
+  {
+    case Remote::DF_UP:
+    case Remote::UP:
+    {
+      sl.up();
+      sl.draw();
+      drawShowing();
+      drawIndicators();
+      BoxStack::getInstance()->update(this);
+      return 2;
+    }
+    case Remote::DF_DOWN:
+    case Remote::DOWN:
+    {
+      sl.down();
+      sl.draw();
+      drawShowing();
+      drawIndicators();
+      BoxStack::getInstance()->update(this);
+      return 2;
+    }
+    case Remote::SKIPBACK:
+    {
+      sl.pageUp();
+      sl.draw();
+      drawShowing();
+      drawIndicators();
+      BoxStack::getInstance()->update(this);
+      return 2;
+    }
+    case Remote::SKIPFORWARD:
+    {
+      sl.pageDown();
+      sl.draw();
+      drawShowing();
+      drawIndicators();
+      BoxStack::getInstance()->update(this);
+      return 2;
+    }
+    case Remote::OK:
+    {
+      RecTimer* recTimer = NULL;
+      if (recTimerList) recTimer = (RecTimer*)sl.getCurrentOptionData();
+      if (recTimer == NULL) return 2;
+
+      VTimerEdit* v = new VTimerEdit(recTimer);
+      v->setParent(this);
+      v->draw();
+      BoxStack::getInstance()->add(v);
+      BoxStack::getInstance()->update(v);
+
+      return 2;
+    }
+    case Remote::BACK:
+    {
+      return 4;
+    }
+  }
+  // stop command getting to any more views
+  return 1;
+}
+
+void VTimerList::processMessage(Message* m)
+{
+  if (m->message == Message::MOUSE_MOVE)
+  {
+    if (sl.mouseMove((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))
+    {
+      sl.draw();
+      BoxStack::getInstance()->update(this);
+    }
+  }
+  else if (m->message == Message::MOUSE_LBDOWN)
+  {
+    if (sl.mouseLBDOWN((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))
+    {
+      BoxStack::getInstance()->handleCommand(Remote::OK); //simulate OK press
+    }
+    else
+    {
+      //check if press is outside this view! then simulate cancel
+      int x=(m->parameter>>16)-getScreenX();
+      int y=(m->parameter&0xFFFF)-getScreenY();
+      if (x<0 || y <0 || x>(int)getWidth() || y>(int)getHeight())
+      {
+        BoxStack::getInstance()->handleCommand(Remote::BACK); //simulate cancel press
+      }
+    }
+  }
+  else if (m->message == Message::DELETE_SELECTED_TIMER)
+  {
+    RecTimer* recTimer = (RecTimer*)sl.getCurrentOptionData();
+    if (recTimer == NULL) return;
+    Log::getInstance()->log("VTimerList", Log::DEBUG, "Got timer to delete");
+
+  
+    ULONG retval = VDR::getInstance()->deleteTimer(recTimer);
+    if (!VDR::getInstance()->isConnected()) { Command::getInstance()->connectionLost(); return; }
+    Log::getInstance()->log("VTimerList", Log::DEBUG, "Got return fron delete timer: %lu", retval);
+    
+    if (retval != 10)
+    {
+      VInfo* errorBox = new VInfo();
+      errorBox->setSize(360, 200);
+      errorBox->createBuffer();
+      if (Video::getInstance()->getFormat() == Video::PAL)
+        errorBox->setPosition(190, 170);
+      else
+        errorBox->setPosition(180, 120);
+
+    
+      if (retval == 1) errorBox->setOneLiner(tr("Timers being edited at VDR, please try later"));
+      else if (retval == 3)  errorBox->setOneLiner(tr("Unable to delete timer - timer is running"));
+      else if (retval == 4)  errorBox->setOneLiner(tr("Error - timer not found at VDR"));
+      else                   errorBox->setOneLiner(tr("Unknown error"));
+
+      errorBox->setExitable();
+      errorBox->setBorderOn(1);
+      errorBox->setTitleBarColour(DrawStyle::DANGER);
+      errorBox->okButton();
+      errorBox->draw();
+      BoxStack::getInstance()->add(errorBox);
+      BoxStack::getInstance()->update(errorBox);
+    }
+    
+    int saveIndex = sl.getCurrentOption();
+    int saveTop = sl.getTopOption();
+     
+    if (recTimerList)
+    {
+      for (UINT i = 0; i < recTimerList->size(); i++)
+      {
+        delete (*recTimerList)[i];
+      }
+
+      recTimerList->clear();
+      delete recTimerList;
+    }
+
+    sl.clear();
+    load();
+
+    sl.hintSetCurrent(saveIndex);
+    sl.hintSetTop(saveTop);
+    draw();
+    BoxStack::getInstance()->update(this);
+  }
+}
+
index 69e8a49464a0cbf9d390ad48295f0fcb48a4ef69..4c2f1bee1b3c7edfbb2e9bce082ba72bbeb7b8f3 100644 (file)
-/*\r
-    Copyright 2007-2008 Chris Tallon\r
-\r
-    This file is part of VOMP.\r
-\r
-    VOMP is free software; you can redistribute it and/or modify\r
-    it under the terms of the GNU General Public License as published by\r
-    the Free Software Foundation; either version 2 of the License, or\r
-    (at your option) any later version.\r
-\r
-    VOMP is distributed in the hope that it will be useful,\r
-    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-    GNU General Public License for more details.\r
-\r
-    You should have received a copy of the GNU General Public License\r
-    along with VOMP; if not, write to the Free Software\r
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
-*/\r
-\r
-#include "vvideolivetv.h"\r
-\r
-#include "vchannellist.h"\r
-#include "video.h"\r
-#include "audio.h"\r
-#include "playerlive.h"\r
-#include "playerlivetv.h"\r
-#include "playerliveradio.h"\r
-#include "channel.h"\r
-#include "boxstack.h"\r
-#include "colour.h"\r
-#include "osd.h"\r
-#include "command.h"\r
-#include "i18n.h"\r
-#include "wtextbox.h"\r
-#include "remote.h"\r
-#include "vaudioselector.h"\r
-#include "colour.h"\r
-#include "event.h"\r
-#include "timers.h"\r
-#include "vepg.h"\r
-#include "bitmap.h"\r
-#include "log.h"\r
-#include "vteletextview.h"\r
-\r
-VVideoLiveTV::VVideoLiveTV(ChannelList* tchanList, ULONG initialChannelNumber, VChannelList* tvchannelList)\r
-: osdBack(0, 0, 0, 128)\r
-{\r
-  vdr = VDR::getInstance();\r
-  boxstack = BoxStack::getInstance();\r
-  video = Video::getInstance();\r
-  \r
-  vas = NULL;\r
-\r
-  chanList = tchanList;\r
-  vchannelList = tvchannelList;\r
-  numberWidth = (int)VDR::getInstance()->getChannelNumberWidth();\r
-\r
-  currentChannelIndex = 0;\r
-  previousChannelIndex = 0;\r
-  osdChannelIndex = 0;\r
-  keying = 0;\r
-  preBuffering = 0;\r
-\r
-  playing = false;\r
-\r
-  // Convert channel number to index\r
-  UINT i;\r
-  for(i = 0; i < chanList->size(); i++)\r
-  {\r
-    if ((*chanList)[i]->number == (UINT)initialChannelNumber)\r
-    {\r
-      currentChannelIndex = i;\r
-      osdChannelIndex = i;\r
-      break;\r
-    }\r
-  }\r
-\r
-  eventList = NULL;\r
-\r
-  videoMode = video->getMode();\r
-  \r
-  if ((*chanList)[currentChannelIndex]->type == VDR::VIDEO)\r
-  {\r
-    streamType = VDR::VIDEO;\r
-    player = new PlayerLiveTV(Command::getInstance(), this, this, chanList);\r
-  }\r
-  else\r
-  {\r
-    streamType = VDR::RADIO;\r
-    player = new PlayerLiveRadio(Command::getInstance(), this, chanList);\r
-  }\r
-  player->init();\r
-\r
-  setSize(video->getScreenWidth(), video->getScreenHeight());\r
-  createBuffer();\r
-  DrawStyle transparent(0, 0, 0, 0);\r
-  setBackgroundColour(transparent);\r
-#ifdef PAL_WSS\r
-  dowss = false;\r
-  char* optionWSS = vdr->configLoad("General", "WSS");\r
-  if (optionWSS)\r
-  {\r
-    if (strstr(optionWSS, "Yes")) dowss = true;\r
-    delete[] optionWSS;\r
-  }\r
-  Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Do WSS: %u", dowss);\r
-\r
-  if (dowss)\r
-  {\r
-    wss.setFormat(video->getFormat());\r
-    wss.setWide(true);\r
-    add(&wss);\r
-    \r
-    wssRegion.x = 0;\r
-    wssRegion.y = 6;\r
-    wssRegion.w = video->getScreenWidth();\r
-    wssRegion.h = 2;\r
-  }\r
-#endif\r
-  // This variable is set to true if the user pressed OK to bring the OSD on screen\r
-  // This is only used on old remotes to stop up/down buttons being used for osd-epg scrolling\r
-  okTriggeredOSD = false;\r
-  \r
-  \r
-\r
-  osd.setBackgroundColour(osdBack);\r
-  osd.setPosition(0, video->getScreenHeight() - 150);\r
-  osd.setSize(video->getScreenWidth(), 150);\r
-  osd.setVisible(false);\r
-  add(&osd);\r
-  \r
-  clock.setBackgroundColour(osdBack);\r
-  clock.setPosition(osd.getWidth() - 100, 4);\r
-  clock.setSize(90, 30);\r
-  osd.add(&clock);\r
-\r
-  osdChanNum.setBackgroundColour(osdBack);\r
-  osdChanNum.setPosition(50, 4);\r
-  osdChanNum.setSize((numberWidth*10) + 22, 30); // 10 px = width of number chars in font\r
-  osd.add(&osdChanNum);  \r
-\r
-  osdChanName.setBackgroundColour(osdBack);\r
-  osdChanName.setPosition(osdChanNum.getX2() + 10, 4);\r
-  osdChanName.setSize(300, 30);\r
-  osd.add(&osdChanName);\r
-  \r
-  boxRed.setBackgroundColour(DrawStyle::RED);\r
-  boxRed.setPosition(54, 104);\r
-  boxRed.setSize(18, 16);\r
-  osd.add(&boxRed);\r
-\r
-  boxGreen.setBackgroundColour(DrawStyle::GREEN);\r
-  boxGreen.setPosition(220, 104);\r
-  boxGreen.setSize(18, 16);\r
-  osd.add(&boxGreen);\r
-\r
-  boxYellow.setBackgroundColour(DrawStyle::YELLOW);\r
-  boxYellow.setPosition(390, 104);\r
-  boxYellow.setSize(18, 16);\r
-  osd.add(&boxYellow);\r
-\r
-  boxBlue.setBackgroundColour(DrawStyle::BLUE);\r
-  boxBlue.setPosition(560, 104);\r
-  boxBlue.setSize(18, 16);\r
-  osd.add(&boxBlue);  \r
-  \r
-  textRed.setBackgroundColour(osdBack);\r
-  textRed.setPosition(boxRed.getX2(), 98);\r
-  textRed.setSize(boxGreen.getX() - boxRed.getX2(), 30);\r
-  textRed.setText(tr("Summary"));\r
-  osd.add(&textRed);  \r
-    \r
-  if (streamType == VDR::VIDEO)\r
-  {\r
-    textGreen.setBackgroundColour(osdBack);\r
-    textGreen.setPosition(boxGreen.getX2(), 98);\r
-    textGreen.setSize(boxYellow.getX() - boxGreen.getX2(), 30);\r
-    textGreen.setText(tr("Audio"));\r
-    osd.add(&textGreen);  \r
-  }\r
-    \r
-  textYellow.setBackgroundColour(osdBack);\r
-  textYellow.setPosition(boxYellow.getX2(), 98);\r
-  textYellow.setSize(boxBlue.getX() - boxYellow.getX2(), 30);\r
-  textYellow.setText(tr("Teletext"));\r
-  osd.add(&textYellow);  \r
-    \r
-  textBlue.setBackgroundColour(osdBack);\r
-  textBlue.setPosition(boxBlue.getX2(), 98);\r
-  textBlue.setSize(osd.getX2() - boxBlue.getX2(), 30);\r
-  textBlue.setText(tr("EPG"));\r
-  osd.add(&textBlue);  \r
-    \r
-  sl.setBackgroundColour(osdBack);\r
-  sl.setPosition(70, 36);\r
-  sl.setSize(500, 58);\r
-  sl.setNoLoop();\r
-  osd.add(&sl);\r
-  \r
-  // Summary Box\r
-  summary.setBackgroundColour(osdBack);\r
-  summary.setPosition(0, video->getScreenHeight() - 300);\r
-  summary.setSize(video->getScreenWidth(), 150);\r
-  summary.setVisible(false);\r
-  add(&summary);  \r
-  \r
-  textSummary.setBackgroundColour(osdBack);\r
-  textSummary.setPosition(40, 10);\r
-  textSummary.setSize(video->getScreenWidth() - 80, 130);\r
-  textSummary.setParaMode(true);\r
-  summary.add(&textSummary);\r
-  \r
-  summaryBlackLine.setBackgroundColour(DrawStyle::BLACK);\r
-  summaryBlackLine.setPosition(0, summary.getHeight() - 4);\r
-  summaryBlackLine.setSize(summary.getWidth(), 4);\r
-  summary.add(&summaryBlackLine);\r
-  \r
-  sAspectRatio.setPosition(osd.getWidth() - 90, 40);\r
-  sAspectRatio.nextColour = DrawStyle::SELECTHIGHLIGHT;\r
-  sAspectRatio.setVisible(false);\r
-  osd.add(&sAspectRatio);\r
-  \r
-  bufferBar.setPosition(osd.getWidth() - 90, 70);\r
-  bufferBar.setSize(40, 20);\r
-  bufferBar.setVisible(true);\r
-  osd.add(&bufferBar);\r
-  \r
-  sAudioChannels.setPosition(osd.getWidth() - 130, 40);\r
-  sAudioChannels.nextColour = DrawStyle::SELECTHIGHLIGHT;\r
-  sAudioChannels.setVisible(false);\r
-  osd.add(&sAudioChannels);\r
-  \r
-  textUnavailable.setBackgroundColour(osdBack);\r
-  textUnavailable.setPosition(60, 30);\r
-  textUnavailable.setSize(osd.getWidth() - 120, 30);\r
-  textUnavailable.setText(tr("Channel Unavailable"));\r
-  textUnavailable.setVisible(false);\r
-  add(&textUnavailable);\r
-  \r
-  // FIXME painful\r
-  Region r1 = summary.getRegionR();\r
-  Region r2 = osd.getRegionR();\r
-  osdSummaryRegion = r1 + r2;\r
-}\r
-\r
-void VVideoLiveTV::preDelete()\r
-{\r
-  if (playing) stop();\r
-}\r
-\r
-VVideoLiveTV::~VVideoLiveTV()\r
-{\r
-  delete player;\r
-  video->setDefaultAspect();\r
-  delData();\r
-}\r
-\r
-void VVideoLiveTV::delData()\r
-{\r
-  if (eventList)\r
-  {\r
-    int eventListSize = eventList->size();\r
-    for(int i = 0; i < eventListSize; i++)\r
-    {\r
-      delete (*eventList)[i];\r
-    }\r
-    eventList->clear();\r
-    delete eventList;\r
-\r
-  }\r
-  sl.clear();\r
-}\r
-\r
-int VVideoLiveTV::handleCommand(int command)\r
-{\r
-  switch(command)\r
-  {\r
-    case Remote::BACK:\r
-    {\r
-      if (osd.getVisible() && !textUnavailable.getVisible())\r
-      {\r
-        clearScreen();\r
-        return 2;\r
-      }\r
-      // else drop through to stop\r
-    }\r
-    case Remote::STOP:\r
-    {\r
-      stop();\r
-      vchannelList->highlightChannel((*chanList)[currentChannelIndex]);\r
-      return 4;\r
-    }\r
-    \r
-    // NEW REMOTE ONLY - navigate EPG, bring it onscreen if it's not there\r
-    case Remote::UP:\r
-    {\r
-       if (Remote::getInstance()->mayHaveFewButtons()) {\r
-             if (okTriggeredOSD) doUpDown(false);\r
-             else doChanUpDown(UP);\r
-       } else {\r
-               doUpDown(false);\r
-       }\r
-      return 2;\r
-    }\r
-    case Remote::DOWN:\r
-    {\r
-      if (Remote::getInstance()->mayHaveFewButtons()) {\r
-          if (okTriggeredOSD) doUpDown(true);\r
-          else doChanUpDown(DOWN);\r
-      } else {\r
-         doUpDown(true);\r
-      }\r
-      return 2;\r
-    }\r
-    case Remote::LEFT:\r
-    {\r
-      doLeftRight(false);\r
-      return 2;\r
-    }\r
-    case Remote::RIGHT:\r
-    {\r
-      doLeftRight(true);\r
-      return 2;\r
-    }\r
-    // Continue new remote only...\r
-    case Remote::CHANNELUP:\r
-    {\r
-      doChanUpDown(UP);\r
-      return 2;\r
-    }\r
-    case Remote::CHANNELDOWN:\r
-    {\r
-      doChanUpDown(DOWN);\r
-      return 2;\r
-    }\r
-\r
-    // END NEW REMOTE ONLY, START OLD REMOTE ONLY\r
-    \r
-    // DF_LEFT and DF_RIGHT never get here because they are stolen\r
-    // by command as vol- and vol+\r
-    \r
-    // Old remote. Decide what to do based on whether\r
-    // OK was pressed - osd shown manually, use up/down for epg nav\r
-    // UP/DOWN was pressed to change channel, osd was shown auto, use up/down for ch+/ch-\r
-    \r
-    case Remote::DF_UP:\r
-    {\r
-      // Old remote, decide what to do based on okTriggeredOSD\r
-      if (okTriggeredOSD) doUpDown(false);\r
-      else doChanUpDown(UP);\r
-      return 2;\r
-    }\r
-    case Remote::DF_DOWN:\r
-    {\r
-      // Old remote, decide what to do based on okTriggeredOSD\r
-      if (okTriggeredOSD) doUpDown(true);\r
-      else doChanUpDown(DOWN);\r
-      return 2;\r
-    }\r
-\r
-    // END NEW/OLD REMOTE STUFF\r
-\r
-    case Remote::PREVCHANNEL:\r
-    {\r
-      channelChange(PREVIOUS, 0);\r
-      osdChannelIndex = currentChannelIndex;\r
-      displayOSD(true);\r
-      return 2;\r
-    }\r
-    case Remote::OK:\r
-    {\r
-      doOK();\r
-      return 2;\r
-    }\r
-    case Remote::RED:\r
-    case Remote::MENU:\r
-    {\r
-      doSummary();\r
-      return 2;\r
-    }\r
-    case Remote::FULL:\r
-    case Remote::TV:\r
-    {\r
-      toggleChopSides();\r
-      return 2;\r
-    }\r
-\r
-    case Remote::ZERO:\r
-    case Remote::ONE:\r
-    case Remote::TWO:\r
-    case Remote::THREE:\r
-    case Remote::FOUR:\r
-    case Remote::FIVE:\r
-    case Remote::SIX:\r
-    case Remote::SEVEN:\r
-    case Remote::EIGHT:\r
-    case Remote::NINE:\r
-    {\r
-      // key in channel number\r
-      doKey(command);\r
-      return 2;\r
-    }\r
-\r
-    case Remote::GREEN:\r
-    {\r
-      if (streamType == VDR::VIDEO) doAudioSelector();\r
-      return 2;   \r
-    }\r
-    case Remote::YELLOW:\r
-    {\r
-      if (streamType ==VDR::VIDEO) doTeletext(); //TODO: Add a selector for subtitles or teletext\r
-      return 2;\r
-    }\r
-    case Remote::GUIDE:\r
-    case Remote::BLUE:\r
-    {\r
-      doEPG();\r
-      return 2;\r
-    }\r
-    case Remote::RECORD:\r
-      if (streamType == VDR::VIDEO)\r
-        (static_cast<PlayerLiveTV*>(player))->toggleSubtitles();\r
-      return 2;\r
-  }\r
-\r
-  return 1;\r
-}\r
-\r
-void VVideoLiveTV::go()\r
-{\r
-  playing = true;\r
-  draw();\r
-  boxstack->update(this);\r
-\r
-  setClock();\r
-  displayOSD(true);\r
-  \r
-  player->go(currentChannelIndex);\r
-}\r
-\r
-void VVideoLiveTV::stop()\r
-{\r
-  Timers::getInstance()->cancelTimer(this, 1);\r
-  Timers::getInstance()->cancelTimer(this, 2);\r
-  player->stop();\r
-  playing = false;\r
-}\r
-\r
-void VVideoLiveTV::doLeftRight(bool right)\r
-{\r
-  if (osd.getVisible())\r
-  {\r
-    if (right) osdChannelIndex = upChannel(osdChannelIndex);\r
-    else       osdChannelIndex = downChannel(osdChannelIndex);\r
-  }\r
-  else\r
-  {\r
-    osdChannelIndex = currentChannelIndex;\r
-  }\r
-  displayOSD(true);\r
-}\r
-\r
-void VVideoLiveTV::doUpDown(bool down)\r
-{\r
-  if (osd.getVisible())\r
-  {\r
-    if (down) sl.down();\r
-    else      sl.up();\r
-    sl.draw();\r
-    \r
-    displayOSD(false);\r
-  }\r
-  else\r
-  {\r
-    displayOSD(true);\r
-  }\r
-}\r
-\r
-void VVideoLiveTV::doChanUpDown(int which)\r
-{\r
-  channelChange(OFFSET, which);\r
-  osdChannelIndex = currentChannelIndex;\r
-  displayOSD(true);\r
-}\r
-\r
-void VVideoLiveTV::doOK()\r
-{\r
-  if (osd.getVisible())\r
-  {\r
-    if (keying)\r
-    {\r
-      UINT newChannel = 0;\r
-      for(int i = keying - 1; i >= 0; i--) newChannel += keyingInput[i] * (ULONG)pow(10., i);\r
-      \r
-      channelChange(NUMBER, newChannel);\r
-      osdChannelIndex = currentChannelIndex;\r
-      displayOSD(true);\r
-    }\r
-    else if (osdChannelIndex == currentChannelIndex)\r
-    {\r
-      clearScreen();\r
-    }\r
-    else\r
-    {\r
-      channelChange(INDEX, osdChannelIndex);\r
-      displayOSD(true);\r
-    }\r
-  }\r
-  else\r
-  {\r
-    osdChannelIndex = currentChannelIndex;\r
-    displayOSD(true);\r
-    okTriggeredOSD = true;\r
-  }\r
-}\r
-\r
-void VVideoLiveTV::doSummary()\r
-{\r
-  if (summary.getVisible())\r
-  {\r
-    summary.setVisible(false);\r
-    draw();\r
-    boxstack->update(this, summary.getRegion());\r
-    Timers::getInstance()->setTimerD(this, 1, 8); // Restart a timer to get rid of osd\r
-    return;\r
-  }\r
-\r
-  summary.setVisible(true);\r
-\r
-  if (osd.getVisible())\r
-  {\r
-    Timers::getInstance()->cancelTimer(this, 1);\r
-    displayOSD(false);\r
-  }\r
-  else\r
-  {\r
-    displayOSD(true);\r
-  }\r
-}\r
-\r
-void VVideoLiveTV::doKey(int command)\r
-{\r
-  if (!osd.getVisible()) // First key. prep the data\r
-  {\r
-    setNowNextData();\r
-    keying = 0;    \r
-  }\r
-\r
-  int i;\r
-  for (i = keying - 1; i >= 0; i--) keyingInput[i+1] = keyingInput[i];\r
-  keyingInput[0] = command;\r
-  keying++;\r
-\r
-  char* keyingString = new char[numberWidth + 1];\r
-  for (i = 0; i < numberWidth; i++) keyingString[i] = '_';\r
-  keyingString[numberWidth] = '\0';\r
-\r
-  for (i = 0; i < keying; i++) keyingString[i] = keyingInput[keying - 1 - i] + 48;\r
-  \r
-  if (keying == numberWidth)\r
-  {\r
-    UINT newChannel = 0;\r
-    for(i = keying - 1; i >= 0; i--) newChannel += keyingInput[i] * (ULONG)pow(10., i);\r
-    \r
-    channelChange(NUMBER, newChannel);\r
-    osdChannelIndex = currentChannelIndex;\r
-    Timers::getInstance()->cancelTimer(this, 1); // cancel the timer to react to keying input,\r
-    displayOSD(true); // this will put one back if required\r
-  }\r
-  else\r
-  {\r
-    osdChanNum.setText(keyingString);\r
-\r
-    if (!osd.getVisible())\r
-    {\r
-      osd.setVisible(true);\r
-      draw();\r
-    }\r
-    else\r
-    {\r
-      osdChanNum.draw();\r
-    }\r
-    boxstack->update(this, osd.getRegion());\r
-    Timers::getInstance()->setTimerD(this, 1, 3);  // 3s for keying input\r
-  }\r
-  delete[] keyingString;\r
-}\r
-\r
-void VVideoLiveTV::doTeletext(bool subtitlemode)\r
-{\r
-  if (streamType !=VDR::VIDEO) return;\r
-  bool exists=true;\r
-\r
-  // Cancel keying\r
-  if (keying)\r
-  {\r
-    keying = 0;\r
-    // and reset the display - this is a copy from setNowNextData\r
-    char formatChanNum[20];\r
-    SNPRINTF(formatChanNum, 19, "%0*lu", numberWidth, (*chanList)[osdChannelIndex]->number);\r
-    osdChanNum.setText(formatChanNum);\r
-    osdChanName.setText((*chanList)[osdChannelIndex]->name);\r
-  }\r
-  if (osd.getVisible()) clearScreen();\r
-  // Draw the teletxt\r
-  VTeletextView *vtxv=((PlayerLiveTV*)player)->getTeletextDecoder()->getTeletxtView();\r
-  if (vtxv==NULL) {\r
-       vtxv= new VTeletextView(((PlayerLiveTV*)player)->getTeletextDecoder(),this);\r
-      ((PlayerLiveTV*)player)->getTeletextDecoder()->registerTeletextView(vtxv);\r
-      exists=false;\r
-  }\r
-  vtxv->setSubtitleMode(subtitlemode);\r
-  vtxv->draw();\r
-  draw();\r
-  \r
-  if (!exists) {\r
-      BoxStack::getInstance()->add(vtxv);\r
-  }\r
-  BoxStack::getInstance()->update(this);\r
-  BoxStack::getInstance()->update(vtxv); \r
-}\r
-\r
-void VVideoLiveTV::doAudioSelector()\r
-{\r
-  // If the osd is already visisble there might be a timer for it\r
-  Timers::getInstance()->cancelTimer(this, 1);\r
-  //This causes a deadlock with the timertrhread itself is locked\r
-\r
-\r
-  // Cancel keying\r
-  if (keying)\r
-  {\r
-    keying = 0;\r
-    // and reset the display - this is a copy from setNowNextData\r
-    char formatChanNum[20];\r
-    SNPRINTF(formatChanNum, 19, "%0*lu", numberWidth, (*chanList)[osdChannelIndex]->number);\r
-    osdChanNum.setText(formatChanNum);\r
-    osdChanName.setText((*chanList)[osdChannelIndex]->name);\r
-  }\r
-  int subtitleChannel=((PlayerLiveTV*)player)->getCurrentSubtitleChannel();\r
-  int subtitleType=0x10;\r
-  if (!(static_cast<PlayerLiveTV*>(player))->isSubtitlesOn()) {\r
-      if (((PlayerLiveTV*)player)->getTeletextDecoder()->getTeletxtView() &&\r
-          ((PlayerLiveTV*)player)->getTeletextDecoder()->getTeletxtView()->isInSubtitleMode() \r
-          ) {\r
-              subtitleChannel=((PlayerLiveTV*)player)->getTeletextDecoder()->getPage();\r
-              subtitleType=0x11;\r
-          \r
-      } else {\r
-          subtitleType=0xFF; //turnedOff\r
-          subtitleChannel=0;\r
-      }\r
-  }\r
-\r
-  // Draw the selector\r
-  vas = new VAudioSelector(this, (*chanList)[currentChannelIndex], ((PlayerLiveTV*)player)->getCurrentAudioChannel(),\r
-      subtitleType,subtitleChannel,NULL);\r
-\r
-  vas->setBackgroundColour(osdBack);\r
-  vas->setPosition(0, osd.getScreenY() - vas->getHeight());\r
-  vas->draw();\r
-\r
-  // make vas != null and displayOSD will not set a timer or do any boxstack update\r
-  summary.setVisible(false);\r
-  if (osd.getVisible()) displayOSD(false);\r
-  else displayOSD(true);\r
-  draw();\r
-\r
-  BoxStack::getInstance()->add(vas);\r
-  BoxStack::getInstance()->update(this);        \r
-  BoxStack::getInstance()->update(vas);     \r
-}      \r
-      \r
-void VVideoLiveTV::doEPG()\r
-{\r
-  if (osd.getVisible()) clearScreen();\r
-\r
-  video->setMode(Video::QUARTER);\r
-  video->setPosition(170, 5); //TODO need to deal with 4:3 switching\r
-\r
-  VEpg* vepg = new VEpg(this, currentChannelIndex, streamType);\r
-  vepg->draw();\r
-  boxstack->add(vepg);\r
-  boxstack->update(vepg);\r
-}\r
-\r
-void VVideoLiveTV::setNowNextData()\r
-{\r
-  delData();\r
-  \r
-  Channel* currentChannel = (*chanList)[osdChannelIndex];\r
-\r
-  char formatChanNum[20];\r
-  SNPRINTF(formatChanNum, 19, "%0*lu", numberWidth, currentChannel->number);\r
-  osdChanNum.setText(formatChanNum);\r
-  osdChanName.setText(currentChannel->name);\r
-\r
-  eventList = VDR::getInstance()->getChannelSchedule(currentChannel->number);\r
-\r
-  if (!eventList)\r
-  {\r
-    sl.addOption(tr("No channel data available"), 0, 1);\r
-  }\r
-  else\r
-  {\r
-    sort(eventList->begin(), eventList->end(), EventSorter());\r
-\r
-    char tempString[300];\r
-    char tempString2[300];\r
-    struct tm* btime;\r
-    Event* event;\r
-    int eventListSize = eventList->size();\r
-    for(int i = 0; i < eventListSize; i++)\r
-    {\r
-      event = (*eventList)[i];\r
-\r
-      //btime = localtime((time_t*)&event->time);\r
-      time_t etime = event->time;\r
-      btime = localtime(&etime);\r
-#ifndef _MSC_VER\r
-      strftime(tempString2, 299, "%0H:%0M ", btime);\r
-#else\r
-      strftime(tempString2, 299, "%H:%M ", btime);\r
-#endif\r
-      SNPRINTF(tempString, 299, "%s %s", tempString2, event->title);\r
-      \r
-      sl.addOption(tempString, (ULONG)event, (i==0));\r
-    }\r
-  }\r
-}\r
-\r
-void VVideoLiveTV::setSummaryData()\r
-{\r
-  // If osd is not being displayed, sl will be filled with now, current channel\r
-  // If the display was already on, sl will have programme to show summary for, not necessarily current channel and now\r
-  Event* selectedEvent = (Event*)sl.getCurrentOptionData();\r
-  \r
-  if (!selectedEvent)\r
-  {\r
-    Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "No summary");  \r
-    textSummary.setText(tr("No summary available"));\r
-  }\r
-  else\r
-  {\r
-    Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Summary: %s", selectedEvent->description);  \r
-    textSummary.setText(selectedEvent->description);\r
-  }\r
-}\r
-\r
-void VVideoLiveTV::displayOSD(bool newNowNextData)\r
-{\r
-  osd.setVisible(true);\r
-  if (newNowNextData)\r
-  {\r
-    setNowNextData();\r
-    keying = 0;\r
-  }\r
-  osd.draw();\r
-  \r
-  if (summary.getVisible())\r
-  {\r
-    setSummaryData();\r
-    summary.draw();\r
-    boxstack->update(this, &osdSummaryRegion);\r
-  }\r
-  else\r
-  {\r
-    boxstack->update(this, osd.getRegion());\r
-  }\r
-  \r
-  bool setTimer = true;\r
-  if (vas) setTimer = false;\r
-  if (summary.getVisible()) setTimer = false;\r
-  if (textUnavailable.getVisible()) setTimer = false;\r
-\r
-  if (setTimer) Timers::getInstance()->setTimerD(this, 1, 4);\r
-}\r
-\r
-void VVideoLiveTV::clearScreen()\r
-{  \r
-  if (!summary.getVisible()) Timers::getInstance()->cancelTimer(this, 1);\r
-\r
-  textUnavailable.setVisible(false);\r
-  osd.setVisible(false);\r
-  summary.setVisible(false);\r
-\r
-  okTriggeredOSD = false;\r
-\r
-  draw();\r
-  boxstack->update(this);\r
-}\r
-\r
-void VVideoLiveTV::showUnavailable()\r
-{\r
-  Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Show unavailable called");  \r
-  textUnavailable.setVisible(true);\r
-  textUnavailable.draw();\r
-  \r
-  if (!osd.getVisible()) displayOSD(true);\r
-\r
-  boxstack->update(this, textUnavailable.getRegion());  \r
-}\r
-\r
-void VVideoLiveTV::setClock()\r
-{\r
-  char timeString[20];\r
-  time_t t;\r
-  time(&t);\r
-  struct tm* tms = localtime(&t);\r
-  strftime(timeString, 19, "%H:%M", tms);\r
-  clock.setText(timeString);\r
-\r
-  time_t dt = 60 - (t % 60);  // seconds to the next minute\r
-  if (dt == 0) dt = 60; // advance a whole minute if necessary\r
-  dt += t;  // get a time_t value for it rather than using duration\r
-  // (so it will occur at the actual second and not second and a half)\r
-\r
-  Timers::getInstance()->setTimerT(this, 2, dt);\r
-}\r
-\r
-void VVideoLiveTV::timercall(int ref)\r
-{\r
-  if (ref == 1)\r
-  {\r
-    if (keying)\r
-    {\r
-         Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Timer Call 1 key start."); \r
-      UINT newChannel = 0;\r
-      for(int i = keying - 1; i >= 0; i--) newChannel += keyingInput[i] * (ULONG)pow(10., i);\r
-      \r
-      Message* m = new Message();\r
-      m->message = Message::CHANNEL_CHANGE;\r
-      m->to = this;\r
-      m->parameter = newChannel;\r
-      m->tag = 1; // signal to call displayOSD();\r
-      Command::getInstance()->postMessageFromOuterSpace(m);\r
-      Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Timer Call 1 key end."); \r
-    }\r
-    else\r
-    {\r
-        Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Timer Call 1 not key start."); \r
-      // We have received a timer, we are not keying. If still prebuffering, don't remove the bar\r
-      if (preBuffering < 100)\r
-      {\r
-        Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Still prebuffering, not removing osd...");  \r
-        Timers::getInstance()->setTimerD(this, 1, 2); // reset timer for another 2s\r
-        return;\r
-      }\r
-      Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Timer Call 1 notkey 1."); \r
-      osd.setVisible(false);\r
-      okTriggeredOSD = false;\r
-      Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Timer Call 1 notkey 2."); \r
-      draw();\r
-      Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Timer Call 1 notkey 4."); \r
-      boxstack->update(this, osd.getRegion());\r
-\r
-      Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Timer Call 1 notkey 3."); \r
-      Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Timer Call 1 notkey end."); \r
-    }\r
-  }\r
-  else if (ref == 2)\r
-  {\r
-      Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Timer Call 2  start."); \r
-    setClock();\r
-    if (osd.getVisible())\r
-    {\r
-      clock.draw();\r
-      boxstack->update(this, osd.getRegion());\r
-    }\r
-    Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Timer Call 2 end."); \r
-  }\r
-}\r
-\r
-bool VVideoLiveTV::channelChange(UCHAR changeType, UINT newData)\r
-{\r
-  UINT newChannel = 0;\r
-  if (streamType ==VDR::VIDEO) {\r
-  VTeletextView *vtxt=((PlayerLiveTV*)player)->getTeletextDecoder()->getTeletxtView();\r
-    if (vtxt ) {\r
-         BoxStack::getInstance()->remove(vtxt);\r
-\r
-    }\r
-  }\r
-  if (changeType == INDEX)\r
-  {\r
-    newChannel = newData;\r
-  }\r
-  else if (changeType == NUMBER)\r
-  {\r
-    UINT i;\r
-    for(i = 0; i < chanList->size(); i++)\r
-    {\r
-      if ((*chanList)[i]->number == (UINT)newData)\r
-      {\r
-        newChannel = i;\r
-        break;\r
-      }\r
-    }\r
-\r
-    if (i == chanList->size())\r
-    {\r
-      // no such channel\r
-      return false;\r
-    }\r
-  }\r
-  else if (changeType == OFFSET)\r
-  {\r
-    if (newData == UP) newChannel = upChannel(currentChannelIndex);\r
-    else newChannel = downChannel(currentChannelIndex);\r
-  }\r
-  else if (changeType == PREVIOUS)\r
-  {\r
-    newChannel = previousChannelIndex;\r
-  }\r
-  else\r
-  {\r
-    return false; // bad input\r
-  }\r
-\r
-  if (newChannel == currentChannelIndex) return true;\r
-\r
-  previousChannelIndex = currentChannelIndex;\r
-  currentChannelIndex = newChannel;\r
-  \r
-  preBuffering = 0;\r
-  \r
-  Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Set player to channel %u", currentChannelIndex);\r
-  player->setChannel(currentChannelIndex);\r
-  Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Done Set player to channel %u", currentChannelIndex);\r
-\r
-  // Blank out the symbols\r
-  sAspectRatio.setVisible(false);\r
-  bufferBar.setPercent(0);\r
-  sAudioChannels.setVisible(false);\r
-  \r
-  // Remove other stuff\r
-  if (textUnavailable.getVisible())\r
-  {\r
-    textUnavailable.setVisible(false);\r
-    \r
-  }\r
-\r
-    draw();\r
-    BoxStack::getInstance()->update(this);\r
-  \r
-  return true;\r
-}\r
-\r
-void VVideoLiveTV::processMessage(Message* m)\r
-{\r
-  if (m->message == Message::MOUSE_LBDOWN)\r
-  {\r
-    //check if press is outside this view! then simulate cancel\r
-    int x=(m->parameter>>16)-osd.getScreenX();\r
-    int y=(m->parameter&0xFFFF)-osd.getScreenY();\r
-    if (osd.getVisible()) {\r
-    \r
-        if ((boxRed.getX()<=x) && (boxRed.getX()+(int)boxRed.getWidth()>=x ) &&\r
-            (boxRed.getY()<=y) && (boxRed.getY()+(int)boxRed.getHeight()>=y )) {\r
-            BoxStack::getInstance()->handleCommand(Remote::RED);\r
-        } else if ((boxGreen.getX()<=x) && (boxGreen.getX()+(int)boxGreen.getWidth()>=x ) &&\r
-            (boxGreen.getY()<=y) && (boxGreen.getY()+(int)boxGreen.getHeight()>=y)){\r
-            BoxStack::getInstance()->handleCommand(Remote::GREEN);\r
-        } else if ((boxYellow.getX()<=x) && (boxYellow.getX()+(int)boxYellow.getWidth()>=x ) &&\r
-            (boxYellow.getY()<=y) && (boxYellow.getY()+(int)boxYellow.getHeight()>=y )){\r
-            BoxStack::getInstance()->handleCommand(Remote::YELLOW);\r
-        } else if ((boxBlue.getX()<=x) && (boxBlue.getX()+(int)boxBlue.getWidth()>=x ) &&\r
-            (boxBlue.getY()<=y) && (boxBlue.getY()+(int)boxBlue.getHeight()>=y )){\r
-            BoxStack::getInstance()->handleCommand(Remote::BLUE);\r
-        } else {\r
-            BoxStack::getInstance()->handleCommand(Remote::OK); //simulate rok press\r
-        }\r
-\r
-    } else {\r
-        BoxStack::getInstance()->handleCommand(Remote::OK); //simulate rok press\r
-    }\r
-  }\r
-  else if (m->message == Message::CHANNEL_CHANGE)\r
-  {\r
-    channelChange(NUMBER, m->parameter);\r
-    osdChannelIndex = currentChannelIndex;\r
-    if (m->tag == 1) displayOSD(true);\r
-  }\r
-  else if (m->message == Message::EPG_CLOSE)\r
-  {\r
-    video->setMode(videoMode);\r
-  }\r
-  else if (m->message == Message::CHILD_CLOSE)\r
-  {\r
-    if (m->from == vas)\r
-    {\r
-      vas = NULL;\r
-      displayOSD(false);\r
-    }\r
-  }\r
-  else if (m->message == Message::AUDIO_CHANGE_CHANNEL)\r
-  {\r
-    Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Received change audio channel to %i", m->parameter);\r
-    player->setAudioChannel((m->parameter & 0xFFFF),(m->parameter & 0xFF0000)>>16,(m->parameter & 0xFF000000)>>24);\r
-  } \r
-  else if (m->message == Message::SUBTITLE_CHANGE_CHANNEL)\r
-  {\r
-    if (streamType !=VDR::VIDEO) return;\r
-      Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Received change subtitle channel to %i", m->parameter);\r
-      int type=((m->parameter & 0xFF0000)>>16);\r
-      switch (type) {\r
-      case 0x10: { //dvbsubtitle\r
-          if (streamType == VDR::VIDEO){\r
-              player->setSubtitleChannel((m->parameter & 0xFFFF));\r
-              (static_cast<PlayerLiveTV*>(player))->turnSubtitlesOn(true);\r
-              VTeletextView *vtxt=((PlayerLiveTV*)player)->getTeletextDecoder()->getTeletxtView();\r
-              if (vtxt && vtxt->isInSubtitleMode()) {\r
-                  BoxStack::getInstance()->remove(vtxt);\r
-              }\r
-          }\r
-                 } break;\r
-      case 0xFF: { //nosubtitles\r
-          if (streamType == VDR::VIDEO){\r
-              (static_cast<PlayerLiveTV*>(player))->turnSubtitlesOn(false);\r
-              VTeletextView *vtxt=((PlayerLiveTV*)player)->getTeletextDecoder()->getTeletxtView();\r
-              if (vtxt && vtxt->isInSubtitleMode()) {\r
-                  BoxStack::getInstance()->remove(vtxt);\r
-              }  \r
-          }\r
-                 } break;\r
-      case 0x11: { //videotext\r
-          (static_cast<PlayerLiveTV*>(player))->turnSubtitlesOn(false);\r
-          doTeletext(true);\r
-          ((PlayerLiveTV*)player)->getTeletextDecoder()->setPage((m->parameter & 0xFFFF));\r
-                 } break;\r
-      };\r
-      if (vas) {\r
-        BoxStack::getInstance()->update(vas);\r
-        //BoxStack::getInstance()->update(&osd); //eveil error\r
-      }\r
-      BoxStack::getInstance()->update(this, osd.getRegion());\r
-\r
-      \r
-  }\r
-  else if (m->message == Message::PLAYER_EVENT)\r
-  {\r
-    switch(m->parameter)\r
-    {\r
-      case PlayerLiveTV::CONNECTION_LOST: // connection lost detected\r
-      {\r
-        Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Received connection lost from player");\r
-        Command::getInstance()->connectionLost();\r
-        break;\r
-      }\r
-      \r
-      case PlayerLiveTV::STREAM_END:\r
-      {\r
-        // Message comes from playerlivetv through master mutex, so can do anything here\r
-        showUnavailable();        \r
-        break;\r
-      }\r
-      \r
-      case PlayerLiveTV::ASPECT43:\r
-      {\r
-#ifdef PAL_WSS\r
-        if ((video->getTVsize() == Video::ASPECT16X9) && dowss)\r
-        {\r
-          Log::getInstance()->log("VVideoRec", Log::DEBUG, "Received do WSS 43");\r
-          wss.setWide(false);\r
-          wss.draw();\r
-          BoxStack::getInstance()->update(this, &wssRegion);\r
-        }\r
-#endif\r
-        \r
-        sAspectRatio.nextSymbol = WSymbol::VIDEOASPECT43;\r
-        sAspectRatio.setVisible(true);\r
-        \r
-        if (osd.getVisible()) // don't wake up the whole osd just for a aspect change\r
-        {\r
-          osd.draw();\r
-          BoxStack::getInstance()->update(this, osd.getRegion());\r
-        }\r
-        \r
-        break;\r
-      }\r
-      case PlayerLiveTV::ASPECT169:\r
-      {\r
-#ifdef PAL_WSS\r
-        if ((video->getTVsize() == Video::ASPECT16X9) && dowss)\r
-        {\r
-          Log::getInstance()->log("VVideoRec", Log::DEBUG, "Received do WSS 169");\r
-          wss.setWide(true);\r
-          wss.draw();\r
-          BoxStack::getInstance()->update(this, &wssRegion);\r
-        }\r
-#endif\r
-        \r
-        sAspectRatio.nextSymbol = WSymbol::VIDEOASPECT169;\r
-        sAspectRatio.setVisible(true);\r
-\r
-        if (osd.getVisible()) // don't wake up the whole osd just for a aspect change\r
-        {\r
-          osd.draw();\r
-          BoxStack::getInstance()->update(this, osd.getRegion());\r
-        }\r
-                \r
-        break;\r
-      }\r
-      case PlayerLiveTV::PREBUFFERING:\r
-      {\r
-        preBuffering = m->tag;\r
-        Log::getInstance()->log("VVideoRec", Log::DEBUG, "Prebuffering - %u", preBuffering);\r
-        bufferBar.setPercent(preBuffering);\r
-\r
-        if (osd.getVisible())\r
-        {\r
-          bufferBar.setVisible(true);\r
-          bufferBar.draw();\r
-          Region r;\r
-          bufferBar.getRootBoxRegion(&r);                       ///////// FIXME !!!\r
-          BoxStack::getInstance()->update(this, &r);\r
-\r
-          if (preBuffering == 100)\r
-          {\r
-            doAudioChannelSymbol();\r
-          }\r
-        }\r
-      }\r
-    }\r
-  }\r
-}\r
-\r
-void VVideoLiveTV::doAudioChannelSymbol()\r
-{\r
-  // get the doobery\r
-  Channel* currentChannel = (*chanList)[osdChannelIndex];\r
-    \r
-  bool multiAudio = false;\r
-  if (Audio::getInstance()->supportsAc3()) {\r
-         if ((currentChannel->numDPids+currentChannel->numAPids) > 1) multiAudio = true;\r
-  }\r
-  if (currentChannel->numAPids > 1) multiAudio = true;\r
-  \r
-  // draw the doobery\r
-  \r
-  if (multiAudio) sAudioChannels.nextSymbol = WSymbol::MULTIAUDIO;\r
-  else            sAudioChannels.nextSymbol = WSymbol::SINGLEAUDIO;\r
-  sAudioChannels.setVisible(true);\r
-  \r
-  if (osd.getVisible())\r
-  {\r
-    sAudioChannels.draw();\r
-    Region r;\r
-    sAudioChannels.getRootBoxRegion(&r);                       ///////// FIXME !!!\r
-    // Fix this n'all.\r
-    r.w = 32;\r
-    r.h = 16;\r
-    BoxStack::getInstance()->update(this, &r);\r
-  }\r
-}\r
-\r
-UINT VVideoLiveTV::upChannel(UINT index)\r
-{\r
-  if (index == (chanList->size() - 1)) // at the end\r
-    return 0; // so go to start\r
-  else\r
-    return index + 1;\r
-}\r
-\r
-UINT VVideoLiveTV::downChannel(UINT index)\r
-{\r
-  if (index == 0) // at the start\r
-    return chanList->size() - 1; // so go to end\r
-  else\r
-    return index - 1;\r
-}\r
-\r
-void VVideoLiveTV::toggleChopSides()\r
-{\r
-  if (video->getTVsize() == Video::ASPECT16X9) return; // Means nothing for 16:9 TVs\r
-\r
-  if (videoMode == Video::NORMAL)\r
-  {\r
-    videoMode = Video::LETTERBOX;\r
-    video->setMode(Video::LETTERBOX);\r
-  }\r
-  else\r
-  {\r
-    videoMode = Video::NORMAL;\r
-    video->setMode(Video::NORMAL);\r
-  }\r
-}\r
-\r
-void VVideoLiveTV::drawOSDBitmap(UINT posX, UINT posY, const Bitmap& bm, const DisplayRegion& region)\r
-{\r
-  drawBitmap(posX, posY, bm,region);\r
-  Region r;\r
-  r.x = posX; r.y = posY; r.w = bm.getWidth(); r.h = bm.getHeight();\r
-  boxstack->update(this, &r);\r
-}\r
-\r
-void VVideoLiveTV::clearOSD()\r
-{\r
-  rectangle(area, DrawStyle(0,0,0,0));\r
-  boxstack->update(this, &area);\r
-}\r
-\r
-void VVideoLiveTV::clearOSDArea(UINT posX, UINT posY, UINT width, UINT height, const DisplayRegion& region)\r
-{\r
-  Region r;\r
-  r.x = posX+region.windowx; r.y = posY+region.windowy; r.w = width; r.h = height;\r
-  //now convert to our display\r
-  float scalex=720.f/((float) (region.framewidth+1));\r
-  float scaley=576.f/((float) (region.frameheight+1));\r
-  r.x=floor(scalex*((float)r.x));\r
-  r.y=floor(scaley*((float)r.y));\r
-  r.w=ceil(scalex*((float)r.w));\r
-  r.h=ceil(scaley*((float)r.h));\r
-  rectangle(r, DrawStyle(0,0,0,0));\r
-  boxstack->update(this, &r);\r
-}\r
+/*
+    Copyright 2007-2008 Chris Tallon
+
+    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 "vvideolivetv.h"
+
+#include "vchannellist.h"
+#include "video.h"
+#include "audio.h"
+#include "playerlive.h"
+#include "playerlivetv.h"
+#include "playerliveradio.h"
+#include "channel.h"
+#include "boxstack.h"
+#include "colour.h"
+#include "osd.h"
+#include "command.h"
+#include "i18n.h"
+#include "wtextbox.h"
+#include "remote.h"
+#include "vaudioselector.h"
+#include "colour.h"
+#include "event.h"
+#include "timers.h"
+#include "vepg.h"
+#include "bitmap.h"
+#include "log.h"
+#include "vteletextview.h"
+
+VVideoLiveTV::VVideoLiveTV(ChannelList* tchanList, ULONG initialChannelNumber, VChannelList* tvchannelList)
+: osdBack(0, 0, 0, 128)
+{
+  vdr = VDR::getInstance();
+  boxstack = BoxStack::getInstance();
+  video = Video::getInstance();
+  
+  vas = NULL;
+
+  chanList = tchanList;
+  vchannelList = tvchannelList;
+  numberWidth = (int)VDR::getInstance()->getChannelNumberWidth();
+
+  currentChannelIndex = 0;
+  previousChannelIndex = 0;
+  osdChannelIndex = 0;
+  keying = 0;
+  preBuffering = 0;
+
+  playing = false;
+
+  // Convert channel number to index
+  UINT i;
+  for(i = 0; i < chanList->size(); i++)
+  {
+    if ((*chanList)[i]->number == (UINT)initialChannelNumber)
+    {
+      currentChannelIndex = i;
+      osdChannelIndex = i;
+      break;
+    }
+  }
+
+  eventList = NULL;
+
+  videoMode = video->getMode();
+  
+  if ((*chanList)[currentChannelIndex]->type == VDR::VIDEO)
+  {
+    streamType = VDR::VIDEO;
+    player = new PlayerLiveTV(Command::getInstance(), this, this, chanList);
+  }
+  else
+  {
+    streamType = VDR::RADIO;
+    player = new PlayerLiveRadio(Command::getInstance(), this, chanList);
+  }
+  player->init();
+
+  setSize(video->getScreenWidth(), video->getScreenHeight());
+  createBuffer();
+  DrawStyle transparent(0, 0, 0, 0);
+  setBackgroundColour(transparent);
+#ifdef PAL_WSS
+  dowss = false;
+  char* optionWSS = vdr->configLoad("General", "WSS");
+  if (optionWSS)
+  {
+    if (strstr(optionWSS, "Yes")) dowss = true;
+    delete[] optionWSS;
+  }
+  Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Do WSS: %u", dowss);
+
+  if (dowss)
+  {
+    wss.setFormat(video->getFormat());
+    wss.setWide(true);
+    add(&wss);
+    
+    wssRegion.x = 0;
+    wssRegion.y = 6;
+    wssRegion.w = video->getScreenWidth();
+    wssRegion.h = 2;
+  }
+#endif
+  // This variable is set to true if the user pressed OK to bring the OSD on screen
+  // This is only used on old remotes to stop up/down buttons being used for osd-epg scrolling
+  okTriggeredOSD = false;
+  
+  
+
+  osd.setBackgroundColour(osdBack);
+  osd.setPosition(0, video->getScreenHeight() - 150);
+  osd.setSize(video->getScreenWidth(), 150);
+  osd.setVisible(false);
+  add(&osd);
+  
+  clock.setBackgroundColour(osdBack);
+  clock.setPosition(osd.getWidth() - 100, 4);
+  clock.setSize(90, 30);
+  osd.add(&clock);
+
+  osdChanNum.setBackgroundColour(osdBack);
+  osdChanNum.setPosition(50, 4);
+  osdChanNum.setSize((numberWidth*10) + 22, 30); // 10 px = width of number chars in font
+  osd.add(&osdChanNum);  
+
+  osdChanName.setBackgroundColour(osdBack);
+  osdChanName.setPosition(osdChanNum.getX2() + 10, 4);
+  osdChanName.setSize(300, 30);
+  osd.add(&osdChanName);
+  
+  boxRed.setBackgroundColour(DrawStyle::RED);
+  boxRed.setPosition(54, 104);
+  boxRed.setSize(18, 16);
+  osd.add(&boxRed);
+
+  boxGreen.setBackgroundColour(DrawStyle::GREEN);
+  boxGreen.setPosition(220, 104);
+  boxGreen.setSize(18, 16);
+  osd.add(&boxGreen);
+
+  boxYellow.setBackgroundColour(DrawStyle::YELLOW);
+  boxYellow.setPosition(390, 104);
+  boxYellow.setSize(18, 16);
+  osd.add(&boxYellow);
+
+  boxBlue.setBackgroundColour(DrawStyle::BLUE);
+  boxBlue.setPosition(560, 104);
+  boxBlue.setSize(18, 16);
+  osd.add(&boxBlue);  
+  
+  textRed.setBackgroundColour(osdBack);
+  textRed.setPosition(boxRed.getX2(), 98);
+  textRed.setSize(boxGreen.getX() - boxRed.getX2(), 30);
+  textRed.setText(tr("Summary"));
+  osd.add(&textRed);  
+    
+  if (streamType == VDR::VIDEO)
+  {
+    textGreen.setBackgroundColour(osdBack);
+    textGreen.setPosition(boxGreen.getX2(), 98);
+    textGreen.setSize(boxYellow.getX() - boxGreen.getX2(), 30);
+    textGreen.setText(tr("Audio"));
+    osd.add(&textGreen);  
+  }
+    
+  textYellow.setBackgroundColour(osdBack);
+  textYellow.setPosition(boxYellow.getX2(), 98);
+  textYellow.setSize(boxBlue.getX() - boxYellow.getX2(), 30);
+  textYellow.setText(tr("Teletext"));
+  osd.add(&textYellow);  
+    
+  textBlue.setBackgroundColour(osdBack);
+  textBlue.setPosition(boxBlue.getX2(), 98);
+  textBlue.setSize(osd.getX2() - boxBlue.getX2(), 30);
+  textBlue.setText(tr("EPG"));
+  osd.add(&textBlue);  
+    
+  sl.setBackgroundColour(osdBack);
+  sl.setPosition(70, 36);
+  sl.setSize(500, 58);
+  sl.setNoLoop();
+  osd.add(&sl);
+  
+  // Summary Box
+  summary.setBackgroundColour(osdBack);
+  summary.setPosition(0, video->getScreenHeight() - 300);
+  summary.setSize(video->getScreenWidth(), 150);
+  summary.setVisible(false);
+  add(&summary);  
+  
+  textSummary.setBackgroundColour(osdBack);
+  textSummary.setPosition(40, 10);
+  textSummary.setSize(video->getScreenWidth() - 80, 130);
+  textSummary.setParaMode(true);
+  summary.add(&textSummary);
+  
+  summaryBlackLine.setBackgroundColour(DrawStyle::BLACK);
+  summaryBlackLine.setPosition(0, summary.getHeight() - 4);
+  summaryBlackLine.setSize(summary.getWidth(), 4);
+  summary.add(&summaryBlackLine);
+  
+  sAspectRatio.setPosition(osd.getWidth() - 90, 40);
+  sAspectRatio.nextColour = DrawStyle::SELECTHIGHLIGHT;
+  sAspectRatio.setVisible(false);
+  osd.add(&sAspectRatio);
+  
+  bufferBar.setPosition(osd.getWidth() - 90, 70);
+  bufferBar.setSize(40, 20);
+  bufferBar.setVisible(true);
+  osd.add(&bufferBar);
+  
+  sAudioChannels.setPosition(osd.getWidth() - 130, 40);
+  sAudioChannels.nextColour = DrawStyle::SELECTHIGHLIGHT;
+  sAudioChannels.setVisible(false);
+  osd.add(&sAudioChannels);
+  
+  textUnavailable.setBackgroundColour(osdBack);
+  textUnavailable.setPosition(60, 30);
+  textUnavailable.setSize(osd.getWidth() - 120, 30);
+  textUnavailable.setText(tr("Channel Unavailable"));
+  textUnavailable.setVisible(false);
+  add(&textUnavailable);
+  
+  // FIXME painful
+  Region r1 = summary.getRegionR();
+  Region r2 = osd.getRegionR();
+  osdSummaryRegion = r1 + r2;
+}
+
+void VVideoLiveTV::preDelete()
+{
+  if (playing) stop();
+}
+
+VVideoLiveTV::~VVideoLiveTV()
+{
+  delete player;
+  video->setDefaultAspect();
+  delData();
+}
+
+void VVideoLiveTV::delData()
+{
+  if (eventList)
+  {
+    int eventListSize = eventList->size();
+    for(int i = 0; i < eventListSize; i++)
+    {
+      delete (*eventList)[i];
+    }
+    eventList->clear();
+    delete eventList;
+
+  }
+  sl.clear();
+}
+
+int VVideoLiveTV::handleCommand(int command)
+{
+  switch(command)
+  {
+    case Remote::BACK:
+    {
+      if (osd.getVisible() && !textUnavailable.getVisible())
+      {
+        clearScreen();
+        return 2;
+      }
+      // else drop through to stop
+    }
+    case Remote::STOP:
+    {
+      stop();
+      vchannelList->highlightChannel((*chanList)[currentChannelIndex]);
+      return 4;
+    }
+    
+    // NEW REMOTE ONLY - navigate EPG, bring it onscreen if it's not there
+    case Remote::UP:
+    {
+       if (Remote::getInstance()->mayHaveFewButtons()) {
+             if (okTriggeredOSD) doUpDown(false);
+             else doChanUpDown(UP);
+       } else {
+               doUpDown(false);
+       }
+      return 2;
+    }
+    case Remote::DOWN:
+    {
+      if (Remote::getInstance()->mayHaveFewButtons()) {
+          if (okTriggeredOSD) doUpDown(true);
+          else doChanUpDown(DOWN);
+      } else {
+         doUpDown(true);
+      }
+      return 2;
+    }
+    case Remote::LEFT:
+    {
+      doLeftRight(false);
+      return 2;
+    }
+    case Remote::RIGHT:
+    {
+      doLeftRight(true);
+      return 2;
+    }
+    // Continue new remote only...
+    case Remote::CHANNELUP:
+    {
+      doChanUpDown(UP);
+      return 2;
+    }
+    case Remote::CHANNELDOWN:
+    {
+      doChanUpDown(DOWN);
+      return 2;
+    }
+
+    // END NEW REMOTE ONLY, START OLD REMOTE ONLY
+    
+    // DF_LEFT and DF_RIGHT never get here because they are stolen
+    // by command as vol- and vol+
+    
+    // Old remote. Decide what to do based on whether
+    // OK was pressed - osd shown manually, use up/down for epg nav
+    // UP/DOWN was pressed to change channel, osd was shown auto, use up/down for ch+/ch-
+    
+    case Remote::DF_UP:
+    {
+      // Old remote, decide what to do based on okTriggeredOSD
+      if (okTriggeredOSD) doUpDown(false);
+      else doChanUpDown(UP);
+      return 2;
+    }
+    case Remote::DF_DOWN:
+    {
+      // Old remote, decide what to do based on okTriggeredOSD
+      if (okTriggeredOSD) doUpDown(true);
+      else doChanUpDown(DOWN);
+      return 2;
+    }
+
+    // END NEW/OLD REMOTE STUFF
+
+    case Remote::PREVCHANNEL:
+    {
+      channelChange(PREVIOUS, 0);
+      osdChannelIndex = currentChannelIndex;
+      displayOSD(true);
+      return 2;
+    }
+    case Remote::OK:
+    {
+      doOK();
+      return 2;
+    }
+    case Remote::RED:
+    case Remote::MENU:
+    {
+      doSummary();
+      return 2;
+    }
+    case Remote::FULL:
+    case Remote::TV:
+    {
+      toggleChopSides();
+      return 2;
+    }
+
+    case Remote::ZERO:
+    case Remote::ONE:
+    case Remote::TWO:
+    case Remote::THREE:
+    case Remote::FOUR:
+    case Remote::FIVE:
+    case Remote::SIX:
+    case Remote::SEVEN:
+    case Remote::EIGHT:
+    case Remote::NINE:
+    {
+      // key in channel number
+      doKey(command);
+      return 2;
+    }
+
+    case Remote::GREEN:
+    {
+      if (streamType == VDR::VIDEO) doAudioSelector();
+      return 2;   
+    }
+    case Remote::YELLOW:
+    {
+      if (streamType ==VDR::VIDEO) doTeletext(); //TODO: Add a selector for subtitles or teletext
+      return 2;
+    }
+    case Remote::GUIDE:
+    case Remote::BLUE:
+    {
+      doEPG();
+      return 2;
+    }
+    case Remote::RECORD:
+      if (streamType == VDR::VIDEO)
+        (static_cast<PlayerLiveTV*>(player))->toggleSubtitles();
+      return 2;
+  }
+
+  return 1;
+}
+
+void VVideoLiveTV::go()
+{
+  playing = true;
+  draw();
+  boxstack->update(this);
+
+  setClock();
+  displayOSD(true);
+  
+  player->go(currentChannelIndex);
+}
+
+void VVideoLiveTV::stop()
+{
+  Timers::getInstance()->cancelTimer(this, 1);
+  Timers::getInstance()->cancelTimer(this, 2);
+  player->stop();
+  playing = false;
+}
+
+void VVideoLiveTV::doLeftRight(bool right)
+{
+  if (osd.getVisible())
+  {
+    if (right) osdChannelIndex = upChannel(osdChannelIndex);
+    else       osdChannelIndex = downChannel(osdChannelIndex);
+  }
+  else
+  {
+    osdChannelIndex = currentChannelIndex;
+  }
+  displayOSD(true);
+}
+
+void VVideoLiveTV::doUpDown(bool down)
+{
+  if (osd.getVisible())
+  {
+    if (down) sl.down();
+    else      sl.up();
+    sl.draw();
+    
+    displayOSD(false);
+  }
+  else
+  {
+    displayOSD(true);
+  }
+}
+
+void VVideoLiveTV::doChanUpDown(int which)
+{
+  channelChange(OFFSET, which);
+  osdChannelIndex = currentChannelIndex;
+  displayOSD(true);
+}
+
+void VVideoLiveTV::doOK()
+{
+  if (osd.getVisible())
+  {
+    if (keying)
+    {
+      UINT newChannel = 0;
+      for(int i = keying - 1; i >= 0; i--) newChannel += keyingInput[i] * (ULONG)pow(10., i);
+      
+      channelChange(NUMBER, newChannel);
+      osdChannelIndex = currentChannelIndex;
+      displayOSD(true);
+    }
+    else if (osdChannelIndex == currentChannelIndex)
+    {
+      clearScreen();
+    }
+    else
+    {
+      channelChange(INDEX, osdChannelIndex);
+      displayOSD(true);
+    }
+  }
+  else
+  {
+    osdChannelIndex = currentChannelIndex;
+    displayOSD(true);
+    okTriggeredOSD = true;
+  }
+}
+
+void VVideoLiveTV::doSummary()
+{
+  if (summary.getVisible())
+  {
+    summary.setVisible(false);
+    draw();
+    boxstack->update(this, summary.getRegion());
+    Timers::getInstance()->setTimerD(this, 1, 8); // Restart a timer to get rid of osd
+    return;
+  }
+
+  summary.setVisible(true);
+
+  if (osd.getVisible())
+  {
+    Timers::getInstance()->cancelTimer(this, 1);
+    displayOSD(false);
+  }
+  else
+  {
+    displayOSD(true);
+  }
+}
+
+void VVideoLiveTV::doKey(int command)
+{
+  if (!osd.getVisible()) // First key. prep the data
+  {
+    setNowNextData();
+    keying = 0;    
+  }
+
+  int i;
+  for (i = keying - 1; i >= 0; i--) keyingInput[i+1] = keyingInput[i];
+  keyingInput[0] = command;
+  keying++;
+
+  char* keyingString = new char[numberWidth + 1];
+  for (i = 0; i < numberWidth; i++) keyingString[i] = '_';
+  keyingString[numberWidth] = '\0';
+
+  for (i = 0; i < keying; i++) keyingString[i] = keyingInput[keying - 1 - i] + 48;
+  
+  if (keying == numberWidth)
+  {
+    UINT newChannel = 0;
+    for(i = keying - 1; i >= 0; i--) newChannel += keyingInput[i] * (ULONG)pow(10., i);
+    
+    channelChange(NUMBER, newChannel);
+    osdChannelIndex = currentChannelIndex;
+    Timers::getInstance()->cancelTimer(this, 1); // cancel the timer to react to keying input,
+    displayOSD(true); // this will put one back if required
+  }
+  else
+  {
+    osdChanNum.setText(keyingString);
+
+    if (!osd.getVisible())
+    {
+      osd.setVisible(true);
+      draw();
+    }
+    else
+    {
+      osdChanNum.draw();
+    }
+    boxstack->update(this, osd.getRegion());
+    Timers::getInstance()->setTimerD(this, 1, 3);  // 3s for keying input
+  }
+  delete[] keyingString;
+}
+
+void VVideoLiveTV::doTeletext(bool subtitlemode)
+{
+  if (streamType !=VDR::VIDEO) return;
+  bool exists=true;
+
+  // Cancel keying
+  if (keying)
+  {
+    keying = 0;
+    // and reset the display - this is a copy from setNowNextData
+    char formatChanNum[20];
+    SNPRINTF(formatChanNum, 19, "%0*lu", numberWidth, (*chanList)[osdChannelIndex]->number);
+    osdChanNum.setText(formatChanNum);
+    osdChanName.setText((*chanList)[osdChannelIndex]->name);
+  }
+  if (osd.getVisible()) clearScreen();
+  // Draw the teletxt
+  VTeletextView *vtxv=((PlayerLiveTV*)player)->getTeletextDecoder()->getTeletxtView();
+  if (vtxv==NULL) {
+       vtxv= new VTeletextView(((PlayerLiveTV*)player)->getTeletextDecoder(),this);
+      ((PlayerLiveTV*)player)->getTeletextDecoder()->registerTeletextView(vtxv);
+      exists=false;
+  }
+  vtxv->setSubtitleMode(subtitlemode);
+  vtxv->draw();
+  draw();
+  
+  if (!exists) {
+      BoxStack::getInstance()->add(vtxv);
+  }
+  BoxStack::getInstance()->update(this);
+  BoxStack::getInstance()->update(vtxv); 
+}
+
+void VVideoLiveTV::doAudioSelector()
+{
+  // If the osd is already visisble there might be a timer for it
+  Timers::getInstance()->cancelTimer(this, 1);
+  //This causes a deadlock with the timertrhread itself is locked
+
+
+  // Cancel keying
+  if (keying)
+  {
+    keying = 0;
+    // and reset the display - this is a copy from setNowNextData
+    char formatChanNum[20];
+    SNPRINTF(formatChanNum, 19, "%0*lu", numberWidth, (*chanList)[osdChannelIndex]->number);
+    osdChanNum.setText(formatChanNum);
+    osdChanName.setText((*chanList)[osdChannelIndex]->name);
+  }
+  int subtitleChannel=((PlayerLiveTV*)player)->getCurrentSubtitleChannel();
+  int subtitleType=0x10;
+  if (!(static_cast<PlayerLiveTV*>(player))->isSubtitlesOn()) {
+      if (((PlayerLiveTV*)player)->getTeletextDecoder()->getTeletxtView() &&
+          ((PlayerLiveTV*)player)->getTeletextDecoder()->getTeletxtView()->isInSubtitleMode() 
+          ) {
+              subtitleChannel=((PlayerLiveTV*)player)->getTeletextDecoder()->getPage();
+              subtitleType=0x11;
+          
+      } else {
+          subtitleType=0xFF; //turnedOff
+          subtitleChannel=0;
+      }
+  }
+
+  // Draw the selector
+  vas = new VAudioSelector(this, (*chanList)[currentChannelIndex], ((PlayerLiveTV*)player)->getCurrentAudioChannel(),
+      subtitleType,subtitleChannel,NULL);
+
+  vas->setBackgroundColour(osdBack);
+  vas->setPosition(0, osd.getScreenY() - vas->getHeight());
+  vas->draw();
+
+  // make vas != null and displayOSD will not set a timer or do any boxstack update
+  summary.setVisible(false);
+  if (osd.getVisible()) displayOSD(false);
+  else displayOSD(true);
+  draw();
+
+  BoxStack::getInstance()->add(vas);
+  BoxStack::getInstance()->update(this);        
+  BoxStack::getInstance()->update(vas);     
+}      
+      
+void VVideoLiveTV::doEPG()
+{
+  if (osd.getVisible()) clearScreen();
+
+  video->setMode(Video::QUARTER);
+  video->setPosition(170, 5); //TODO need to deal with 4:3 switching
+
+  VEpg* vepg = new VEpg(this, currentChannelIndex, streamType);
+  vepg->draw();
+  boxstack->add(vepg);
+  boxstack->update(vepg);
+}
+
+void VVideoLiveTV::setNowNextData()
+{
+  delData();
+  
+  Channel* currentChannel = (*chanList)[osdChannelIndex];
+
+  char formatChanNum[20];
+  SNPRINTF(formatChanNum, 19, "%0*lu", numberWidth, currentChannel->number);
+  osdChanNum.setText(formatChanNum);
+  osdChanName.setText(currentChannel->name);
+
+  eventList = VDR::getInstance()->getChannelSchedule(currentChannel->number);
+
+  if (!eventList)
+  {
+    sl.addOption(tr("No channel data available"), 0, 1);
+  }
+  else
+  {
+    sort(eventList->begin(), eventList->end(), EventSorter());
+
+    char tempString[300];
+    char tempString2[300];
+    struct tm* btime;
+    Event* event;
+    int eventListSize = eventList->size();
+    for(int i = 0; i < eventListSize; i++)
+    {
+      event = (*eventList)[i];
+
+      //btime = localtime((time_t*)&event->time);
+      time_t etime = event->time;
+      btime = localtime(&etime);
+#ifndef _MSC_VER
+      strftime(tempString2, 299, "%0H:%0M ", btime);
+#else
+      strftime(tempString2, 299, "%H:%M ", btime);
+#endif
+      SNPRINTF(tempString, 299, "%s %s", tempString2, event->title);
+      
+      sl.addOption(tempString, (ULONG)event, (i==0));
+    }
+  }
+}
+
+void VVideoLiveTV::setSummaryData()
+{
+  // If osd is not being displayed, sl will be filled with now, current channel
+  // If the display was already on, sl will have programme to show summary for, not necessarily current channel and now
+  Event* selectedEvent = (Event*)sl.getCurrentOptionData();
+  
+  if (!selectedEvent)
+  {
+    Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "No summary");  
+    textSummary.setText(tr("No summary available"));
+  }
+  else
+  {
+    Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Summary: %s", selectedEvent->description);  
+    textSummary.setText(selectedEvent->description);
+  }
+}
+
+void VVideoLiveTV::displayOSD(bool newNowNextData)
+{
+  osd.setVisible(true);
+  if (newNowNextData)
+  {
+    setNowNextData();
+    keying = 0;
+  }
+  osd.draw();
+  
+  if (summary.getVisible())
+  {
+    setSummaryData();
+    summary.draw();
+    boxstack->update(this, &osdSummaryRegion);
+  }
+  else
+  {
+    boxstack->update(this, osd.getRegion());
+  }
+  
+  bool setTimer = true;
+  if (vas) setTimer = false;
+  if (summary.getVisible()) setTimer = false;
+  if (textUnavailable.getVisible()) setTimer = false;
+
+  if (setTimer) Timers::getInstance()->setTimerD(this, 1, 4);
+}
+
+void VVideoLiveTV::clearScreen()
+{  
+  if (!summary.getVisible()) Timers::getInstance()->cancelTimer(this, 1);
+
+  textUnavailable.setVisible(false);
+  osd.setVisible(false);
+  summary.setVisible(false);
+
+  okTriggeredOSD = false;
+
+  draw();
+  boxstack->update(this);
+}
+
+void VVideoLiveTV::showUnavailable()
+{
+  Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Show unavailable called");  
+  textUnavailable.setVisible(true);
+  textUnavailable.draw();
+  
+  if (!osd.getVisible()) displayOSD(true);
+
+  boxstack->update(this, textUnavailable.getRegion());  
+}
+
+void VVideoLiveTV::setClock()
+{
+  char timeString[20];
+  time_t t;
+  time(&t);
+  struct tm* tms = localtime(&t);
+  strftime(timeString, 19, "%H:%M", tms);
+  clock.setText(timeString);
+
+  time_t dt = 60 - (t % 60);  // seconds to the next minute
+  if (dt == 0) dt = 60; // advance a whole minute if necessary
+  dt += t;  // get a time_t value for it rather than using duration
+  // (so it will occur at the actual second and not second and a half)
+
+  Timers::getInstance()->setTimerT(this, 2, dt);
+}
+
+void VVideoLiveTV::timercall(int ref)
+{
+  if (ref == 1)
+  {
+    if (keying)
+    {
+         Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Timer Call 1 key start."); 
+      UINT newChannel = 0;
+      for(int i = keying - 1; i >= 0; i--) newChannel += keyingInput[i] * (ULONG)pow(10., i);
+      
+      Message* m = new Message();
+      m->message = Message::CHANNEL_CHANGE;
+      m->to = this;
+      m->parameter = newChannel;
+      m->tag = 1; // signal to call displayOSD();
+      Command::getInstance()->postMessageFromOuterSpace(m);
+      Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Timer Call 1 key end."); 
+    }
+    else
+    {
+        Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Timer Call 1 not key start."); 
+      // We have received a timer, we are not keying. If still prebuffering, don't remove the bar
+      if (preBuffering < 100)
+      {
+        Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Still prebuffering, not removing osd...");  
+        Timers::getInstance()->setTimerD(this, 1, 2); // reset timer for another 2s
+        return;
+      }
+      Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Timer Call 1 notkey 1."); 
+      osd.setVisible(false);
+      okTriggeredOSD = false;
+      Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Timer Call 1 notkey 2."); 
+      draw();
+      Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Timer Call 1 notkey 4."); 
+      boxstack->update(this, osd.getRegion());
+
+      Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Timer Call 1 notkey 3."); 
+      Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Timer Call 1 notkey end."); 
+    }
+  }
+  else if (ref == 2)
+  {
+      Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Timer Call 2  start."); 
+    setClock();
+    if (osd.getVisible())
+    {
+      clock.draw();
+      boxstack->update(this, osd.getRegion());
+    }
+    Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Timer Call 2 end."); 
+  }
+}
+
+bool VVideoLiveTV::channelChange(UCHAR changeType, UINT newData)
+{
+  UINT newChannel = 0;
+  if (streamType ==VDR::VIDEO) {
+  VTeletextView *vtxt=((PlayerLiveTV*)player)->getTeletextDecoder()->getTeletxtView();
+    if (vtxt ) {
+         BoxStack::getInstance()->remove(vtxt);
+
+    }
+  }
+  if (changeType == INDEX)
+  {
+    newChannel = newData;
+  }
+  else if (changeType == NUMBER)
+  {
+    UINT i;
+    for(i = 0; i < chanList->size(); i++)
+    {
+      if ((*chanList)[i]->number == (UINT)newData)
+      {
+        newChannel = i;
+        break;
+      }
+    }
+
+    if (i == chanList->size())
+    {
+      // no such channel
+      return false;
+    }
+  }
+  else if (changeType == OFFSET)
+  {
+    if (newData == UP) newChannel = upChannel(currentChannelIndex);
+    else newChannel = downChannel(currentChannelIndex);
+  }
+  else if (changeType == PREVIOUS)
+  {
+    newChannel = previousChannelIndex;
+  }
+  else
+  {
+    return false; // bad input
+  }
+
+  if (newChannel == currentChannelIndex) return true;
+
+  previousChannelIndex = currentChannelIndex;
+  currentChannelIndex = newChannel;
+  
+  preBuffering = 0;
+  
+  Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Set player to channel %u", currentChannelIndex);
+  player->setChannel(currentChannelIndex);
+  Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Done Set player to channel %u", currentChannelIndex);
+
+  // Blank out the symbols
+  sAspectRatio.setVisible(false);
+  bufferBar.setPercent(0);
+  sAudioChannels.setVisible(false);
+  
+  // Remove other stuff
+  if (textUnavailable.getVisible())
+  {
+    textUnavailable.setVisible(false);
+    
+  }
+
+    draw();
+    BoxStack::getInstance()->update(this);
+  
+  return true;
+}
+
+void VVideoLiveTV::processMessage(Message* m)
+{
+  if (m->message == Message::MOUSE_LBDOWN)
+  {
+    //check if press is outside this view! then simulate cancel
+    int x=(m->parameter>>16)-osd.getScreenX();
+    int y=(m->parameter&0xFFFF)-osd.getScreenY();
+    if (osd.getVisible()) {
+    
+        if ((boxRed.getX()<=x) && (boxRed.getX()+(int)boxRed.getWidth()>=x ) &&
+            (boxRed.getY()<=y) && (boxRed.getY()+(int)boxRed.getHeight()>=y )) {
+            BoxStack::getInstance()->handleCommand(Remote::RED);
+        } else if ((boxGreen.getX()<=x) && (boxGreen.getX()+(int)boxGreen.getWidth()>=x ) &&
+            (boxGreen.getY()<=y) && (boxGreen.getY()+(int)boxGreen.getHeight()>=y)){
+            BoxStack::getInstance()->handleCommand(Remote::GREEN);
+        } else if ((boxYellow.getX()<=x) && (boxYellow.getX()+(int)boxYellow.getWidth()>=x ) &&
+            (boxYellow.getY()<=y) && (boxYellow.getY()+(int)boxYellow.getHeight()>=y )){
+            BoxStack::getInstance()->handleCommand(Remote::YELLOW);
+        } else if ((boxBlue.getX()<=x) && (boxBlue.getX()+(int)boxBlue.getWidth()>=x ) &&
+            (boxBlue.getY()<=y) && (boxBlue.getY()+(int)boxBlue.getHeight()>=y )){
+            BoxStack::getInstance()->handleCommand(Remote::BLUE);
+        } else {
+            BoxStack::getInstance()->handleCommand(Remote::OK); //simulate rok press
+        }
+
+    } else {
+        BoxStack::getInstance()->handleCommand(Remote::OK); //simulate rok press
+    }
+  }
+  else if (m->message == Message::CHANNEL_CHANGE)
+  {
+    channelChange(NUMBER, m->parameter);
+    osdChannelIndex = currentChannelIndex;
+    if (m->tag == 1) displayOSD(true);
+  }
+  else if (m->message == Message::EPG_CLOSE)
+  {
+    video->setMode(videoMode);
+  }
+  else if (m->message == Message::CHILD_CLOSE)
+  {
+    if (m->from == vas)
+    {
+      vas = NULL;
+      displayOSD(false);
+    }
+  }
+  else if (m->message == Message::AUDIO_CHANGE_CHANNEL)
+  {
+    Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Received change audio channel to %i", m->parameter);
+    player->setAudioChannel((m->parameter & 0xFFFF),(m->parameter & 0xFF0000)>>16,(m->parameter & 0xFF000000)>>24);
+  } 
+  else if (m->message == Message::SUBTITLE_CHANGE_CHANNEL)
+  {
+    if (streamType !=VDR::VIDEO) return;
+      Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Received change subtitle channel to %i", m->parameter);
+      int type=((m->parameter & 0xFF0000)>>16);
+      switch (type) {
+      case 0x10: { //dvbsubtitle
+          if (streamType == VDR::VIDEO){
+              player->setSubtitleChannel((m->parameter & 0xFFFF));
+              (static_cast<PlayerLiveTV*>(player))->turnSubtitlesOn(true);
+              VTeletextView *vtxt=((PlayerLiveTV*)player)->getTeletextDecoder()->getTeletxtView();
+              if (vtxt && vtxt->isInSubtitleMode()) {
+                  BoxStack::getInstance()->remove(vtxt);
+              }
+          }
+                 } break;
+      case 0xFF: { //nosubtitles
+          if (streamType == VDR::VIDEO){
+              (static_cast<PlayerLiveTV*>(player))->turnSubtitlesOn(false);
+              VTeletextView *vtxt=((PlayerLiveTV*)player)->getTeletextDecoder()->getTeletxtView();
+              if (vtxt && vtxt->isInSubtitleMode()) {
+                  BoxStack::getInstance()->remove(vtxt);
+              }  
+          }
+                 } break;
+      case 0x11: { //videotext
+          (static_cast<PlayerLiveTV*>(player))->turnSubtitlesOn(false);
+          doTeletext(true);
+          ((PlayerLiveTV*)player)->getTeletextDecoder()->setPage((m->parameter & 0xFFFF));
+                 } break;
+      };
+      if (vas) {
+        BoxStack::getInstance()->update(vas);
+        //BoxStack::getInstance()->update(&osd); //eveil error
+      }
+      BoxStack::getInstance()->update(this, osd.getRegion());
+
+      
+  }
+  else if (m->message == Message::PLAYER_EVENT)
+  {
+    switch(m->parameter)
+    {
+      case PlayerLiveTV::CONNECTION_LOST: // connection lost detected
+      {
+        Log::getInstance()->log("VVideoLiveTV", Log::DEBUG, "Received connection lost from player");
+        Command::getInstance()->connectionLost();
+        break;
+      }
+      
+      case PlayerLiveTV::STREAM_END:
+      {
+        // Message comes from playerlivetv through master mutex, so can do anything here
+        showUnavailable();        
+        break;
+      }
+      
+      case PlayerLiveTV::ASPECT43:
+      {
+#ifdef PAL_WSS
+        if ((video->getTVsize() == Video::ASPECT16X9) && dowss)
+        {
+          Log::getInstance()->log("VVideoRec", Log::DEBUG, "Received do WSS 43");
+          wss.setWide(false);
+          wss.draw();
+          BoxStack::getInstance()->update(this, &wssRegion);
+        }
+#endif
+        
+        sAspectRatio.nextSymbol = WSymbol::VIDEOASPECT43;
+        sAspectRatio.setVisible(true);
+        
+        if (osd.getVisible()) // don't wake up the whole osd just for a aspect change
+        {
+          osd.draw();
+          BoxStack::getInstance()->update(this, osd.getRegion());
+        }
+        
+        break;
+      }
+      case PlayerLiveTV::ASPECT169:
+      {
+#ifdef PAL_WSS
+        if ((video->getTVsize() == Video::ASPECT16X9) && dowss)
+        {
+          Log::getInstance()->log("VVideoRec", Log::DEBUG, "Received do WSS 169");
+          wss.setWide(true);
+          wss.draw();
+          BoxStack::getInstance()->update(this, &wssRegion);
+        }
+#endif
+        
+        sAspectRatio.nextSymbol = WSymbol::VIDEOASPECT169;
+        sAspectRatio.setVisible(true);
+
+        if (osd.getVisible()) // don't wake up the whole osd just for a aspect change
+        {
+          osd.draw();
+          BoxStack::getInstance()->update(this, osd.getRegion());
+        }
+                
+        break;
+      }
+      case PlayerLiveTV::PREBUFFERING:
+      {
+        preBuffering = m->tag;
+        Log::getInstance()->log("VVideoRec", Log::DEBUG, "Prebuffering - %u", preBuffering);
+        bufferBar.setPercent(preBuffering);
+
+        if (osd.getVisible())
+        {
+          bufferBar.setVisible(true);
+          bufferBar.draw();
+          Region r;
+          bufferBar.getRootBoxRegion(&r);                       ///////// FIXME !!!
+          BoxStack::getInstance()->update(this, &r);
+
+          if (preBuffering == 100)
+          {
+            doAudioChannelSymbol();
+          }
+        }
+      }
+    }
+  }
+}
+
+void VVideoLiveTV::doAudioChannelSymbol()
+{
+  // get the doobery
+  Channel* currentChannel = (*chanList)[osdChannelIndex];
+    
+  bool multiAudio = false;
+  if (Audio::getInstance()->supportsAc3()) {
+         if ((currentChannel->numDPids+currentChannel->numAPids) > 1) multiAudio = true;
+  }
+  if (currentChannel->numAPids > 1) multiAudio = true;
+  
+  // draw the doobery
+  
+  if (multiAudio) sAudioChannels.nextSymbol = WSymbol::MULTIAUDIO;
+  else            sAudioChannels.nextSymbol = WSymbol::SINGLEAUDIO;
+  sAudioChannels.setVisible(true);
+  
+  if (osd.getVisible())
+  {
+    sAudioChannels.draw();
+    Region r;
+    sAudioChannels.getRootBoxRegion(&r);                       ///////// FIXME !!!
+    // Fix this n'all.
+    r.w = 32;
+    r.h = 16;
+    BoxStack::getInstance()->update(this, &r);
+  }
+}
+
+UINT VVideoLiveTV::upChannel(UINT index)
+{
+  if (index == (chanList->size() - 1)) // at the end
+    return 0; // so go to start
+  else
+    return index + 1;
+}
+
+UINT VVideoLiveTV::downChannel(UINT index)
+{
+  if (index == 0) // at the start
+    return chanList->size() - 1; // so go to end
+  else
+    return index - 1;
+}
+
+void VVideoLiveTV::toggleChopSides()
+{
+  if (video->getTVsize() == Video::ASPECT16X9) return; // Means nothing for 16:9 TVs
+
+  if (videoMode == Video::NORMAL)
+  {
+    videoMode = Video::LETTERBOX;
+    video->setMode(Video::LETTERBOX);
+  }
+  else
+  {
+    videoMode = Video::NORMAL;
+    video->setMode(Video::NORMAL);
+  }
+}
+
+void VVideoLiveTV::drawOSDBitmap(UINT posX, UINT posY, const Bitmap& bm, const DisplayRegion& region)
+{
+  drawBitmap(posX, posY, bm,region);
+  Region r;
+  r.x = posX; r.y = posY; r.w = bm.getWidth(); r.h = bm.getHeight();
+  boxstack->update(this, &r);
+}
+
+void VVideoLiveTV::clearOSD()
+{
+  rectangle(area, DrawStyle(0,0,0,0));
+  boxstack->update(this, &area);
+}
+
+void VVideoLiveTV::clearOSDArea(UINT posX, UINT posY, UINT width, UINT height, const DisplayRegion& region)
+{
+  Region r;
+  r.x = posX+region.windowx; r.y = posY+region.windowy; r.w = width; r.h = height;
+  //now convert to our display
+  float scalex=720.f/((float) (region.framewidth+1));
+  float scaley=576.f/((float) (region.frameheight+1));
+  r.x=floor(scalex*((float)r.x));
+  r.y=floor(scaley*((float)r.y));
+  r.w=ceil(scalex*((float)r.w));
+  r.h=ceil(scaley*((float)r.h));
+  rectangle(r, DrawStyle(0,0,0,0));
+  boxstack->update(this, &r);
+}
index f4b069edfee99b071f2101904116cae08370ec03..6f97b59ee81fcd51e5c9cfd804359df78a310f8a 100644 (file)
-/*\r
-    Copyright 2004-2005 Chris Tallon\r
-\r
-    This file is part of VOMP.\r
-\r
-    VOMP is free software; you can redistribute it and/or modify\r
-    it under the terms of the GNU General Public License as published by\r
-    the Free Software Foundation; either version 2 of the License, or\r
-    (at your option) any later version.\r
-\r
-    VOMP is distributed in the hope that it will be useful,\r
-    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-    GNU General Public License for more details.\r
-\r
-    You should have received a copy of the GNU General Public License\r
-    along with VOMP; if not, write to the Free Software\r
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
-*/\r
-\r
-#include "vvideomedia.h"\r
-#include "vmedialist.h"\r
-#include "media.h"\r
-#include "mediaplayer.h"\r
-\r
-#include "command.h"\r
-#include "osd.h"\r
-#include "wsymbol.h"\r
-#include "audio.h"\r
-#include "video.h"\r
-#include "timers.h"\r
-#include "playermedia.h"\r
-#include "recording.h"\r
-#include "vaudioselector.h"\r
-#include "message.h"\r
-#include "remote.h"\r
-#include "boxstack.h"\r
-#include "vinfo.h"\r
-#include "i18n.h"\r
-#include "log.h"\r
-#include "recinfo.h"\r
-\r
-//use the picture channel\r
-#define MEDIACHANNEL 1\r
-\r
-//we misuse PLAYER_EVENTS for timer messages\r
-//this should be larger then any player message\r
-#define PLAYER_TIMER_BASE 100\r
-\r
-VVideoMedia::VVideoMedia(Media* media, VMediaList *p)\r
-{\r
-  lparent=p;\r
-  boxstack = BoxStack::getInstance();\r
-  video = Video::getInstance();\r
-  timers = Timers::getInstance();\r
-  vas = NULL;\r
-  vsummary = NULL;\r
-  lengthBytes=0;\r
-  myMedia = new Media(media);\r
-\r
-  player = new PlayerMedia(this);\r
-  player->run();\r
-\r
-  videoMode = video->getMode();\r
-\r
-  playing = false;\r
-\r
-\r
-  setSize(video->getScreenWidth(), video->getScreenHeight());\r
-  createBuffer();\r
-  transparent.set(0, 0, 0, 0);\r
-  setBackgroundColour(transparent);\r
-\r
-  barRegion.x = 0;\r
-  barRegion.y = video->getScreenHeight() - 58;   // FIXME, need to be - 1? and below?\r
-  barRegion.w = video->getScreenWidth();\r
-  barRegion.h = 58;\r
-\r
-  clocksRegion.x = barRegion.x + 140;\r
-  clocksRegion.y = barRegion.y + 12;\r
-  clocksRegion.w = 170;\r
-  clocksRegion.h = getFontHeight();\r
-\r
-\r
-  barBlue.set(0, 0, 150, 150);\r
-\r
-  barShowing = false;\r
-  barGenHold = false;\r
-  barScanHold = false;\r
-  barVasHold = false;\r
-\r
-  dowss = false;\r
-  char* optionWSS = VDR::getInstance()->configLoad("General", "WSS");\r
-  if (optionWSS)\r
-  {\r
-    if (strstr(optionWSS, "Yes")) dowss = true;\r
-    delete[] optionWSS;\r
-  }\r
-  Log::getInstance()->log("VVideoMedia", Log::DEBUG, "Do WSS: %u", dowss);\r
-\r
-  if (dowss)\r
-  {\r
-    wss.setFormat(video->getFormat());\r
-    wss.setWide(true);\r
-    add(&wss);\r
-\r
-    wssRegion.x = 0;\r
-    wssRegion.y = 0;\r
-    wssRegion.w = video->getScreenWidth();\r
-    wssRegion.h = 300;\r
-  }\r
-}\r
-\r
-VVideoMedia::~VVideoMedia()\r
-{\r
-  Log::getInstance()->log("VVideoMedia", Log::DEBUG, "Entering  destructor");\r
-\r
-  if (vas)\r
-  {\r
-    boxstack->remove(vas);\r
-    vas = NULL;\r
-  }\r
-\r
-  if (vsummary) {\r
-    remove(vsummary);\r
-    delete vsummary;\r
-  }\r
-\r
-  if (playing) stopPlay();\r
-  video->setDefaultAspect();\r
-\r
-  timers->cancelTimer(this, 1);\r
-  timers->cancelTimer(this, 2);\r
-\r
-  delete myMedia;\r
-  Log::getInstance()->log("VVideoMedia", Log::DEBUG, "shutting down player");\r
-  player->shutdown();\r
-  delete player;\r
-  Log::getInstance()->log("VVideoMedia", Log::DEBUG, "deleted");\r
-}\r
-\r
-void VVideoMedia::go(bool resume)\r
-{\r
-  ULONG startFrameNum=0;\r
-\r
-  Log::getInstance()->log("VVideoMedia", Log::DEBUG, "Starting stream: %s at frame: %lu", myMedia->getFileName(), startFrameNum);\r
-\r
-  lengthBytes = 0;\r
-\r
-  int rt=0;\r
-  const MediaURI *u=myMedia->getURI();\r
-  if (!u) {\r
-    Log::getInstance()->log("VVideoMedia", Log::ERR, "stream: %s has no URI", myMedia->getFileName());\r
-    rt=-1;\r
-  }\r
-  else {\r
-    rt=MediaPlayer::getInstance()->openMedium(MEDIACHANNEL,u,&lengthBytes,area.w,area.h);\r
-  }\r
-  if (rt==0)\r
-  {\r
-    //TODO: figure out len in frames\r
-    int seq=player->playNew(MEDIACHANNEL,lengthBytes,0);\r
-    int ok=player->waitForSequence(2,seq);\r
-    if (ok < 0) rt=-1; \r
-    else {\r
-      playing = true;\r
-      doBar(0);\r
-    }\r
-  }\r
-  if (rt != 0)\r
-  {\r
-    stopPlay(); // clean up\r
-\r
-    Message* m = new Message();\r
-    m->message = Message::CLOSE_ME;\r
-    m->from = this;\r
-    m->to = boxstack;\r
-    Command::getInstance()->postMessageNoLock(m);\r
-\r
-    VInfo* vi = new VInfo();\r
-    vi->setSize(400, 150);\r
-    vi->createBuffer();\r
-    if (video->getFormat() == Video::PAL)\r
-      vi->setPosition(170, 200);\r
-    else\r
-      vi->setPosition(160, 150);\r
-    vi->setExitable();\r
-    vi->setBorderOn(1);\r
-    vi->setTitleBarOn(0);\r
-    vi->setOneLiner(tr("Error playing media"));\r
-    vi->draw();\r
-\r
-    m = new Message();\r
-    m->message = Message::ADD_VIEW;\r
-    m->to = boxstack;\r
-    m->parameter = (ULONG)vi;\r
-    Command::getInstance()->postMessageNoLock(m);\r
-  }\r
-}\r
-\r
-int VVideoMedia::handleCommand(int command)\r
-{\r
-  switch(command)\r
-  {\r
-    case Remote::PLAY:\r
-    {\r
-      player->play();\r
-      doBar(0);\r
-      return 2;\r
-    }\r
-\r
-    case Remote::BACK:\r
-    {\r
-      if (vsummary)\r
-      {\r
-        removeSummary();\r
-        return 2;\r
-      }\r
-    } // DROP THROUGH\r
-    case Remote::STOP:\r
-    case Remote::MENU:\r
-    {\r
-      if (playing) stopPlay();\r
-\r
-      return 4;\r
-    }\r
-    case Remote::PAUSE:\r
-    {\r
-      player->pause();\r
-      doBar(0);\r
-      return 2;\r
-    }\r
-    case Remote::SKIPFORWARD:\r
-    {\r
-      doBar(3);\r
-      player->skipForward(60);\r
-      return 2;\r
-    }\r
-    case Remote::SKIPBACK:\r
-    {\r
-      doBar(4);\r
-      player->skipBackward(60);\r
-      return 2;\r
-    }\r
-    case Remote::FORWARD:\r
-    {\r
-      player->fastForward();\r
-      doBar(0);\r
-      return 2;\r
-    }\r
-    case Remote::REVERSE:\r
-    {\r
-      player->fastBackward();\r
-      doBar(0);\r
-      return 2;\r
-    }\r
-    case Remote::RED:\r
-    {\r
-      if (vsummary) removeSummary();\r
-      else doSummary();\r
-      return 2;\r
-    }\r
-    case Remote::GREEN:\r
-    {\r
-      doAudioSelector();\r
-      return 2;\r
-    }\r
-    case Remote::YELLOW:\r
-    {\r
-      doBar(2);\r
-      player->skipBackward(10);\r
-      return 2;\r
-    }\r
-    case Remote::BLUE:\r
-    {\r
-      doBar(1);\r
-      player->skipForward(10);\r
-      return 2;\r
-    }\r
-    case Remote::STAR:\r
-    {\r
-      doBar(2);\r
-      player->skipBackward(10);\r
-      return 2;\r
-    }\r
-    case Remote::HASH:\r
-    {\r
-      doBar(1);\r
-      player->skipForward(10);\r
-      return 2;\r
-    }\r
-    case Remote::FULL:\r
-    case Remote::TV:\r
-    {\r
-      toggleChopSides();\r
-      return 2;\r
-    }\r
-\r
-    case Remote::OK:\r
-    {\r
-      if (vsummary)\r
-      {\r
-        removeSummary();\r
-        return 2;\r
-      }\r
-      \r
-      if (barShowing) removeBar();\r
-      else {\r
-        doBar(0);\r
-        barGenHold=true;\r
-      }\r
-      return 2;\r
-    }\r
-\r
-    case Remote::ZERO:  player->jumpToPercent(0);  doBar(0);  return 2;\r
-    case Remote::ONE:   player->jumpToPercent(10); doBar(0);  return 2;\r
-    case Remote::TWO:   player->jumpToPercent(20); doBar(0);  return 2;\r
-    case Remote::THREE: player->jumpToPercent(30); doBar(0);  return 2;\r
-    case Remote::FOUR:  player->jumpToPercent(40); doBar(0);  return 2;\r
-    case Remote::FIVE:  player->jumpToPercent(50); doBar(0);  return 2;\r
-    case Remote::SIX:   player->jumpToPercent(60); doBar(0);  return 2;\r
-    case Remote::SEVEN: player->jumpToPercent(70); doBar(0);  return 2;\r
-    case Remote::EIGHT: player->jumpToPercent(80); doBar(0);  return 2;\r
-    case Remote::NINE:  player->jumpToPercent(90); doBar(0);  return 2;\r
-\r
-\r
-  }\r
-\r
-  return 1;\r
-}\r
-\r
-void VVideoMedia::processMessage(Message* m)\r
-{\r
-  Log::getInstance()->log("VVideoMedia", Log::DEBUG, "Message received");\r
-\r
-  if (m->message == Message::MOUSE_LBDOWN)\r
-  {\r
-    UINT x = (m->parameter>>16) - getScreenX();\r
-    UINT y = (m->parameter&0xFFFF) - getScreenY();\r
-\r
-    if (!barShowing)\r
-    {\r
-      BoxStack::getInstance()->handleCommand(Remote::OK); //simulate rok press\r
-    }\r
-    else if (barRegion.x<=x && barRegion.y<=y && (barRegion.x+barRegion.w)>=x && (barRegion.y+barRegion.h)>=y)\r
-    {\r
-      int progBarXbase = barRegion.x + 300;\r
-      if (x>=barRegion.x + progBarXbase + 24\r
-          && x<=barRegion.x + progBarXbase + 4 + 302\r
-          && y>=barRegion.y + 12 - 2\r
-          && y<=barRegion.y + 12 - 2+28)\r
-      {\r
-        int cx=x-(barRegion.x + progBarXbase + 4);\r
-        double percent=((double)cx)/302.*100.;\r
-        player->jumpToPercent(percent);\r
-        doBar(3);\r
-        return;\r
-        //  int progressWidth = 302 * currentFrameNum / lengthFrames;\r
-        //  rectangle(barRegion.x + progBarXbase + 4, barRegion.y + 16, progressWidth, 16, DrawStyle::SELECTHIGHLIGHT);\r
-      }\r
-    }\r
-    else\r
-    {\r
-      BoxStack::getInstance()->handleCommand(Remote::OK); //simulate rok press\r
-    }\r
-  }\r
-  else if (m->message == Message::PLAYER_EVENT)\r
-  {\r
-    switch(m->parameter)\r
-    {\r
-      case PlayerMedia::CONNECTION_LOST: // connection lost detected\r
-      {\r
-        // I can't handle this, send it to command\r
-        Message* m2 = new Message();\r
-        m2->to = Command::getInstance();\r
-        m2->message = Message::CONNECTION_LOST;\r
-        Command::getInstance()->postMessageNoLock(m2);\r
-        break;\r
-      }\r
-      case PlayerMedia::STREAM_END:\r
-      {\r
-        Message* m2 = new Message(); // Must be done after this thread finishes, and must break into master mutex\r
-        m2->to = BoxStack::getInstance();\r
-        m2->message = Message::CLOSE_ME;\r
-        Command::getInstance()->postMessageNoLock(m2);\r
-        break;\r
-      }\r
-      case PlayerMedia::STATUS_CHANGE:\r
-        doBar(0);\r
-        break;\r
-      case PlayerMedia::ASPECT43:\r
-      {\r
-        if (dowss)\r
-        {\r
-          Log::getInstance()->log("VVideoMedia", Log::DEBUG, "Received do WSS 43");\r
-          wss.setWide(false);\r
-          wss.draw();\r
-          boxstack->update(this, &wssRegion);\r
-        }\r
-        break;\r
-      }\r
-      case PlayerMedia::ASPECT169:\r
-      {\r
-        if (dowss)\r
-        {\r
-          Log::getInstance()->log("VVideoMedia", Log::DEBUG, "Received do WSS 169");\r
-          wss.setWide(true);\r
-          wss.draw();\r
-          boxstack->update(this, &wssRegion);\r
-        }\r
-        break;\r
-      }\r
-      case (PLAYER_TIMER_BASE+1) :\r
-        //timer1:\r
-        // Remove bar\r
-        removeBar();\r
-        break;\r
-      case (PLAYER_TIMER_BASE+2) :\r
-        //timer2:\r
-        // Update clock\r
-        if (!barShowing) break;\r
-        drawBarClocks();\r
-        BoxStack::getInstance()->update(this,&barRegion);\r
-        if (player->getLengthFrames() != 0)   timers->setTimerD(this, 2, 0, 200000000);\r
-        else   timers->setTimerD(this, 2, 1);\r
-        break;\r
-    }\r
-  }\r
-  else if (m->message == Message::AUDIO_CHANGE_CHANNEL)\r
-  {\r
-    Log::getInstance()->log("VVideoMedia", Log::DEBUG, "Received change audio channel to %i", m->parameter);\r
-    player->setAudioChannel(m->parameter);\r
-  }\r
-  else if (m->message == Message::CHILD_CLOSE)\r
-  {\r
-    if (m->from == vas)\r
-    {\r
-      vas = NULL;\r
-      barVasHold = false;\r
-      if (!barGenHold && !barScanHold && !barVasHold) removeBar();\r
-    }\r
-  }\r
-}\r
-\r
-void VVideoMedia::stopPlay()\r
-{\r
-  Log::getInstance()->log("VVideoMedia", Log::DEBUG, "Pre stopPlay");\r
-\r
-  removeBar();\r
-\r
-  player->stop();\r
-\r
-  playing = false;\r
-  MediaPlayer::getInstance()->closeMediaChannel(MEDIACHANNEL);\r
-\r
-  Log::getInstance()->log("VVideoMedia", Log::DEBUG, "Post stopPlay");\r
-}\r
-\r
-void VVideoMedia::toggleChopSides()\r
-{\r
-  if (video->getTVsize() == Video::ASPECT16X9) return; // Means nothing for 16:9 TVs\r
-\r
-  if (videoMode == Video::NORMAL)\r
-  {\r
-    videoMode = Video::LETTERBOX;\r
-    video->setMode(Video::LETTERBOX);\r
-  }\r
-  else\r
-  {\r
-    videoMode = Video::NORMAL;\r
-    video->setMode(Video::NORMAL);\r
-  }\r
-}\r
-\r
-void VVideoMedia::doAudioSelector()\r
-{\r
-  bool* availableMpegAudioChannels = player->getDemuxerMpegAudioChannels();\r
-  bool* availableAc3AudioChannels = 0;\r
-  int currentAudioChannel = player->getCurrentAudioChannel();\r
-  if (Audio::getInstance()->supportsAc3())\r
-  {\r
-      availableAc3AudioChannels = player->getDemuxerAc3AudioChannels();\r
-  }\r
-\r
-\r
-  RecInfo ri;\r
-  ri.summary=new char[strlen(myMedia->getDisplayName())+1];\r
-  strcpy(ri.summary,myMedia->getDisplayName());\r
-  vas = new VAudioSelector(this, availableMpegAudioChannels, availableAc3AudioChannels, currentAudioChannel, NULL,NULL,0,0, &ri);\r
\r
-  vas->setBackgroundColour(barBlue);\r
-  vas->setPosition(0, barRegion.y - 120);\r
-\r
-// pal 62, ntsc 57\r
-\r
-  barVasHold = true;\r
-  doBar(0);\r
-\r
-  vas->draw();\r
-  boxstack->add(vas);\r
-  boxstack->update(vas);\r
-}\r
-\r
-void VVideoMedia::doBar(int action)\r
-{\r
-  Log::getInstance()->log("VVideoMedia",Log::DEBUG,"doBar %d",action);\r
-  barShowing = true;\r
-\r
-  rectangle(barRegion, barBlue);\r
-\r
-  /* Work out what to display - choices:\r
-\r
-  Playing  >\r
-  Paused   ||\r
-  FFwd     >>\r
-  FBwd     <<\r
-\r
-  Specials, informed by parameter\r
-\r
-  Skip forward 10s    >|\r
-  Skip backward 10s   |<\r
-  Skip forward 1m     >>|\r
-  Skip backward 1m    |<<\r
-\r
-  */\r
-\r
-  WSymbol w;\r
-  TEMPADD(&w);\r
-  w.nextSymbol = 0;\r
-  w.setPosition(barRegion.x + 66, barRegion.y + 16);\r
-\r
-  UCHAR playerState = 0;\r
-\r
-  if (action)\r
-  {\r
-    if (action == 1)       w.nextSymbol = WSymbol::SKIPFORWARD;\r
-    else if (action == 2)  w.nextSymbol = WSymbol::SKIPBACK;\r
-    else if (action == 3)  w.nextSymbol = WSymbol::SKIPFORWARD2;\r
-    else if (action == 4)  w.nextSymbol = WSymbol::SKIPBACK2;\r
-  }\r
-  else\r
-  {\r
-    playerState = player->getState();\r
-    if (playerState == PlayerMedia::S_PLAY)      w.nextSymbol = WSymbol::PLAY;\r
-    else if (playerState == PlayerMedia::S_FF)    w.nextSymbol = WSymbol::FFWD;\r
-    else if (playerState == PlayerMedia::S_BACK)    w.nextSymbol = WSymbol::FBWD;\r
-    else if (playerState == PlayerMedia::S_SEEK)    w.nextSymbol = WSymbol::RIGHTARROW;\r
-    else if (playerState == PlayerMedia::S_STOP)    w.nextSymbol = WSymbol::PAUSE;\r
-    else                                       w.nextSymbol = WSymbol::PAUSE;\r
-  }\r
-\r
-  w.draw();\r
-\r
-  if ((playerState == PlayerMedia::S_FF) || (playerState == PlayerMedia::S_BACK))\r
-  {\r
-    // draw blips to show how fast the scan is\r
-    UCHAR scanrate = 2;//player->getIScanRate();\r
-    if (scanrate >= 2)\r
-    {\r
-      char text[5];\r
-      SNPRINTF(text, 5, "%ux", scanrate);\r
-      drawText(text, barRegion.x + 102, barRegion.y + 12, DrawStyle::LIGHTTEXT);\r
-    }\r
-  }\r
-\r
-  drawBarClocks();\r
-  boxstack->update(this, &barRegion);\r
-\r
-  timers->cancelTimer(this, 1);\r
-\r
-\r
-  if ((playerState == PlayerMedia::S_FF) || (playerState == PlayerMedia::S_BACK)) barScanHold = true;\r
-  else barScanHold = false;\r
-\r
-  if (!barGenHold && !barScanHold && !barVasHold) timers->setTimerD(this, 1, 4);\r
-\r
-  if (player->getLengthFrames() != 0) timers->setTimerD(this, 2, 0, 200000000);\r
-  else timers->setTimerD(this, 2, 1);\r
-}\r
-\r
-void VVideoMedia::timercall(int clientReference)\r
-{\r
-  Message *m=new Message();\r
-  m->message=Message::PLAYER_EVENT;\r
-  m->to=this;\r
-  m->from=this;\r
-  m->parameter=PLAYER_TIMER_BASE+clientReference;\r
-  Command::getInstance()->postMessageFromOuterSpace(m);\r
-}\r
-\r
-void VVideoMedia::drawBarClocks()\r
-{\r
-  if (barScanHold)\r
-  {\r
-    UCHAR playerState = player->getState();\r
-    // sticky bar is set if we are in ffwd/fbwd mode\r
-    // if player has gone to S_PLAY then kill stickyBar, and run doBar(0) which\r
-    // will repaint all the bar (it will call this function again, but\r
-    // this section won't run because stickyBarF will then == false)\r
-\r
-    if ((playerState != PlayerMedia::S_FF) && (playerState != PlayerMedia::S_BACK))\r
-    {\r
-      barScanHold = false;\r
-      doBar(0);\r
-      return; \r
-    }\r
-  }\r
-\r
-  Log* logger = Log::getInstance();\r
-  logger->log("VVideoMedia", Log::DEBUG, "Draw bar clocks");\r
-\r
-  // Draw RTC\r
-  // Blank the area first\r
-  rectangle(barRegion.x + 624, barRegion.y + 12, 60, 30, barBlue);\r
-  char timeString[20];\r
-  time_t t;\r
-  time(&t);\r
-  struct tm* tms = localtime(&t);\r
-  strftime(timeString, 19, "%H:%M", tms);\r
-  drawText(timeString, barRegion.x + 624, barRegion.y + 12, DrawStyle::LIGHTTEXT);\r
-\r
-  ULLONG lenPTS=player->getLenPTS();\r
-  // Draw clocks\r
-\r
-  rectangle(clocksRegion, barBlue);\r
-\r
-  ULLONG currentPTS = player->getCurrentPTS();\r
-\r
-  hmsf currentFrameHMSF = ptsToHMS(currentPTS);\r
-  hmsf lengthHMSF = ptsToHMS(lenPTS);\r
-\r
-  char buffer[100];\r
-  if (currentPTS > lenPTS && lenPTS != 0)\r
-  {\r
-    strcpy(buffer, "-:--:-- / -:--:--");\r
-  }\r
-  else\r
-  {\r
-    SNPRINTF(buffer, 99, "%01i:%02i:%02i / %01i:%02i:%02i", currentFrameHMSF.hours, currentFrameHMSF.minutes, currentFrameHMSF.seconds, lengthHMSF.hours, lengthHMSF.minutes, lengthHMSF.seconds);\r
-  }\r
-    logger->log("VVideoMedia", Log::DEBUG, "cur %llu,len %llu, txt %s",currentPTS,lenPTS,buffer);\r
-\r
-  drawText(buffer, clocksRegion.x, clocksRegion.y, DrawStyle::LIGHTTEXT);\r
-\r
-\r
-\r
-\r
-\r
-\r
-\r
-  // Draw progress bar\r
-  int progBarXbase = barRegion.x + 300;\r
-\r
-  if (lenPTS == 0) return;\r
-  rectangle(barRegion.x + progBarXbase, barRegion.y + 12, 310, 24, DrawStyle::LIGHTTEXT);\r
-  rectangle(barRegion.x + progBarXbase + 2, barRegion.y + 14, 306, 20, barBlue);\r
-\r
-  if (currentPTS > lenPTS) return;\r
-\r
-  // Draw yellow portion\r
-  int progressWidth = 302 * currentPTS / lenPTS;\r
-  rectangle(barRegion.x + progBarXbase + 4, barRegion.y + 16, progressWidth, 16, DrawStyle::SELECTHIGHLIGHT);\r
-\r
-}\r
-\r
-void VVideoMedia::removeBar()\r
-{\r
-  if (!barShowing) return;\r
-  timers->cancelTimer(this, 2);\r
-  barShowing = false;\r
-  barGenHold = false;\r
-  barScanHold = false;\r
-  barVasHold = false;\r
-  rectangle(barRegion, transparent);\r
-  BoxStack::getInstance()->update(this, &barRegion);\r
-}\r
-\r
-void VVideoMedia::doSummary()\r
-{\r
-  vsummary = new VInfo();\r
-  vsummary->setTitleText(myMedia->getDisplayName());\r
-  vsummary->setBorderOn(1);\r
-  vsummary->setExitable();\r
-  const MediaURI *u=myMedia->getURI();\r
-  int stlen=0;\r
-  if (u) {\r
-    stlen+=strlen(myMedia->getFileName());\r
-    stlen+=strlen(tr("FileName"))+10;\r
-  }\r
-  stlen+=strlen(tr("Size"))+50;\r
-  stlen+=strlen(tr("Directory"))+500;\r
-  stlen+=strlen(tr("Time"))+50;\r
-  char *pinfo=player->getInfo();\r
-  stlen+=strlen(pinfo)+10;\r
-  char *buf=new char [stlen];\r
-  char *tsbuf=new char [stlen];\r
-  char *tsbuf2=new char [stlen];\r
-  char *tbuf=new char[Media::TIMEBUFLEN];\r
-  SNPRINTF(buf,stlen,"%s\n" \r
-                   "%s: %llu Bytes\n"\r
-                   "%s\n"\r
-                   "%s: %s\n"\r
-                   "%s",\r
-      shortendedText(tr("FileName"),": ",myMedia->getFileName(),tsbuf,vsummary->getWidth()),\r
-      tr("Size"),\r
-      lengthBytes,\r
-      shortendedText(tr("Directory"),": ",lparent->getDirname(MEDIA_TYPE_VIDEO),tsbuf2,vsummary->getWidth()),\r
-      tr("Time"),\r
-      myMedia->getTimeString(tbuf),\r
-      pinfo\r
-      );\r
-  //TODO more info\r
-  if (u) {\r
-      Log::getInstance()->log("VVideoMedia",Log::DEBUG,"info %s",buf);\r
-      vsummary->setMainText(buf);\r
-  }\r
-  else vsummary->setMainText(tr("Info unavailable"));\r
-  delete pinfo;\r
-  if (Video::getInstance()->getFormat() == Video::PAL)\r
-  {\r
-    vsummary->setPosition(70, 100);\r
-  }\r
-  else\r
-  {\r
-    vsummary->setPosition(40, 70);\r
-  }\r
-  vsummary->setSize(580, 350);\r
-  add(vsummary);\r
-  vsummary->draw();\r
-\r
-  BoxStack::getInstance()->update(this);\r
-   delete [] buf;\r
-  delete []  tsbuf;\r
-  delete [] tsbuf2;\r
-  delete []  tbuf;\r
-}\r
-\r
-void VVideoMedia::removeSummary()\r
-{\r
-  if (vsummary)\r
-  {\r
-    remove(vsummary);\r
-    delete vsummary;\r
-    vsummary = NULL;\r
-    draw();\r
-    BoxStack::getInstance()->update(this);\r
-  }\r
-}\r
-\r
-\r
-hmsf VVideoMedia::ptsToHMS(ULLONG pts) {\r
-  ULLONG secs=pts/90000;\r
-  hmsf rt;\r
-  rt.frames=0;\r
-  rt.seconds=secs%60;\r
-  secs=secs/60;\r
-  rt.minutes=secs%60;\r
-  secs=secs/60;\r
-  rt.hours=secs;\r
-  return rt;\r
-}\r
-  \r
-char * VVideoMedia::shortendedText(const char * title, const char * title2,const char * intext,char *buffer,UINT width) {\r
-  if (! intext) {\r
-    intext="";\r
-  }\r
-  UINT twidth=0;\r
-  for (const char *p=title;*p!=0;p++) twidth+=charWidth(*p);\r
-  for (const char *p=title2;*p!=0;p++) twidth+=charWidth(*p);\r
-  const char *prfx="...";\r
-  UINT prfwidth=3*charWidth('.');\r
-  const char *istart=intext+strlen(intext);\r
-  UINT iwidth=0;\r
-  while (twidth+iwidth+prfwidth < width-2*paraMargin && istart> intext) {\r
-    istart--;\r
-    iwidth+=charWidth(*istart);\r
-  }\r
-  if (twidth+iwidth+prfwidth >= width-2*paraMargin && istart < intext+strlen(intext)) istart++;\r
-  if (istart == intext) prfx="";\r
-  sprintf(buffer,"%s%s%s%s",title,title2,prfx,intext);\r
-  return buffer;\r
-}\r
-\r
-\r
+/*
+    Copyright 2004-2005 Chris Tallon
+
+    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 "vvideomedia.h"
+#include "vmedialist.h"
+#include "media.h"
+#include "mediaplayer.h"
+
+#include "command.h"
+#include "osd.h"
+#include "wsymbol.h"
+#include "audio.h"
+#include "video.h"
+#include "timers.h"
+#include "playermedia.h"
+#include "recording.h"
+#include "vaudioselector.h"
+#include "message.h"
+#include "remote.h"
+#include "boxstack.h"
+#include "vinfo.h"
+#include "i18n.h"
+#include "log.h"
+#include "recinfo.h"
+
+//use the picture channel
+#define MEDIACHANNEL 1
+
+//we misuse PLAYER_EVENTS for timer messages
+//this should be larger then any player message
+#define PLAYER_TIMER_BASE 100
+
+VVideoMedia::VVideoMedia(Media* media, VMediaList *p)
+{
+  lparent=p;
+  boxstack = BoxStack::getInstance();
+  video = Video::getInstance();
+  timers = Timers::getInstance();
+  vas = NULL;
+  vsummary = NULL;
+  lengthBytes=0;
+  myMedia = new Media(media);
+
+  player = new PlayerMedia(this);
+  player->run();
+
+  videoMode = video->getMode();
+
+  playing = false;
+
+
+  setSize(video->getScreenWidth(), video->getScreenHeight());
+  createBuffer();
+  transparent.set(0, 0, 0, 0);
+  setBackgroundColour(transparent);
+
+  barRegion.x = 0;
+  barRegion.y = video->getScreenHeight() - 58;   // FIXME, need to be - 1? and below?
+  barRegion.w = video->getScreenWidth();
+  barRegion.h = 58;
+
+  clocksRegion.x = barRegion.x + 140;
+  clocksRegion.y = barRegion.y + 12;
+  clocksRegion.w = 170;
+  clocksRegion.h = getFontHeight();
+
+
+  barBlue.set(0, 0, 150, 150);
+
+  barShowing = false;
+  barGenHold = false;
+  barScanHold = false;
+  barVasHold = false;
+
+  dowss = false;
+  char* optionWSS = VDR::getInstance()->configLoad("General", "WSS");
+  if (optionWSS)
+  {
+    if (strstr(optionWSS, "Yes")) dowss = true;
+    delete[] optionWSS;
+  }
+  Log::getInstance()->log("VVideoMedia", Log::DEBUG, "Do WSS: %u", dowss);
+
+  if (dowss)
+  {
+    wss.setFormat(video->getFormat());
+    wss.setWide(true);
+    add(&wss);
+
+    wssRegion.x = 0;
+    wssRegion.y = 0;
+    wssRegion.w = video->getScreenWidth();
+    wssRegion.h = 300;
+  }
+}
+
+VVideoMedia::~VVideoMedia()
+{
+  Log::getInstance()->log("VVideoMedia", Log::DEBUG, "Entering  destructor");
+
+  if (vas)
+  {
+    boxstack->remove(vas);
+    vas = NULL;
+  }
+
+  if (vsummary) {
+    remove(vsummary);
+    delete vsummary;
+  }
+
+  if (playing) stopPlay();
+  video->setDefaultAspect();
+
+  timers->cancelTimer(this, 1);
+  timers->cancelTimer(this, 2);
+
+  delete myMedia;
+  Log::getInstance()->log("VVideoMedia", Log::DEBUG, "shutting down player");
+  player->shutdown();
+  delete player;
+  Log::getInstance()->log("VVideoMedia", Log::DEBUG, "deleted");
+}
+
+void VVideoMedia::go(bool resume)
+{
+  ULONG startFrameNum=0;
+
+  Log::getInstance()->log("VVideoMedia", Log::DEBUG, "Starting stream: %s at frame: %lu", myMedia->getFileName(), startFrameNum);
+
+  lengthBytes = 0;
+
+  int rt=0;
+  const MediaURI *u=myMedia->getURI();
+  if (!u) {
+    Log::getInstance()->log("VVideoMedia", Log::ERR, "stream: %s has no URI", myMedia->getFileName());
+    rt=-1;
+  }
+  else {
+    rt=MediaPlayer::getInstance()->openMedium(MEDIACHANNEL,u,&lengthBytes,area.w,area.h);
+  }
+  if (rt==0)
+  {
+    //TODO: figure out len in frames
+    int seq=player->playNew(MEDIACHANNEL,lengthBytes,0);
+    int ok=player->waitForSequence(2,seq);
+    if (ok < 0) rt=-1; 
+    else {
+      playing = true;
+      doBar(0);
+    }
+  }
+  if (rt != 0)
+  {
+    stopPlay(); // clean up
+
+    Message* m = new Message();
+    m->message = Message::CLOSE_ME;
+    m->from = this;
+    m->to = boxstack;
+    Command::getInstance()->postMessageNoLock(m);
+
+    VInfo* vi = new VInfo();
+    vi->setSize(400, 150);
+    vi->createBuffer();
+    if (video->getFormat() == Video::PAL)
+      vi->setPosition(170, 200);
+    else
+      vi->setPosition(160, 150);
+    vi->setExitable();
+    vi->setBorderOn(1);
+    vi->setTitleBarOn(0);
+    vi->setOneLiner(tr("Error playing media"));
+    vi->draw();
+
+    m = new Message();
+    m->message = Message::ADD_VIEW;
+    m->to = boxstack;
+    m->parameter = (ULONG)vi;
+    Command::getInstance()->postMessageNoLock(m);
+  }
+}
+
+int VVideoMedia::handleCommand(int command)
+{
+  switch(command)
+  {
+    case Remote::PLAY:
+    {
+      player->play();
+      doBar(0);
+      return 2;
+    }
+
+    case Remote::BACK:
+    {
+      if (vsummary)
+      {
+        removeSummary();
+        return 2;
+      }
+    } // DROP THROUGH
+    case Remote::STOP:
+    case Remote::MENU:
+    {
+      if (playing) stopPlay();
+
+      return 4;
+    }
+    case Remote::PAUSE:
+    {
+      player->pause();
+      doBar(0);
+      return 2;
+    }
+    case Remote::SKIPFORWARD:
+    {
+      doBar(3);
+      player->skipForward(60);
+      return 2;
+    }
+    case Remote::SKIPBACK:
+    {
+      doBar(4);
+      player->skipBackward(60);
+      return 2;
+    }
+    case Remote::FORWARD:
+    {
+      player->fastForward();
+      doBar(0);
+      return 2;
+    }
+    case Remote::REVERSE:
+    {
+      player->fastBackward();
+      doBar(0);
+      return 2;
+    }
+    case Remote::RED:
+    {
+      if (vsummary) removeSummary();
+      else doSummary();
+      return 2;
+    }
+    case Remote::GREEN:
+    {
+      doAudioSelector();
+      return 2;
+    }
+    case Remote::YELLOW:
+    {
+      doBar(2);
+      player->skipBackward(10);
+      return 2;
+    }
+    case Remote::BLUE:
+    {
+      doBar(1);
+      player->skipForward(10);
+      return 2;
+    }
+    case Remote::STAR:
+    {
+      doBar(2);
+      player->skipBackward(10);
+      return 2;
+    }
+    case Remote::HASH:
+    {
+      doBar(1);
+      player->skipForward(10);
+      return 2;
+    }
+    case Remote::FULL:
+    case Remote::TV:
+    {
+      toggleChopSides();
+      return 2;
+    }
+
+    case Remote::OK:
+    {
+      if (vsummary)
+      {
+        removeSummary();
+        return 2;
+      }
+      
+      if (barShowing) removeBar();
+      else {
+        doBar(0);
+        barGenHold=true;
+      }
+      return 2;
+    }
+
+    case Remote::ZERO:  player->jumpToPercent(0);  doBar(0);  return 2;
+    case Remote::ONE:   player->jumpToPercent(10); doBar(0);  return 2;
+    case Remote::TWO:   player->jumpToPercent(20); doBar(0);  return 2;
+    case Remote::THREE: player->jumpToPercent(30); doBar(0);  return 2;
+    case Remote::FOUR:  player->jumpToPercent(40); doBar(0);  return 2;
+    case Remote::FIVE:  player->jumpToPercent(50); doBar(0);  return 2;
+    case Remote::SIX:   player->jumpToPercent(60); doBar(0);  return 2;
+    case Remote::SEVEN: player->jumpToPercent(70); doBar(0);  return 2;
+    case Remote::EIGHT: player->jumpToPercent(80); doBar(0);  return 2;
+    case Remote::NINE:  player->jumpToPercent(90); doBar(0);  return 2;
+
+
+  }
+
+  return 1;
+}
+
+void VVideoMedia::processMessage(Message* m)
+{
+  Log::getInstance()->log("VVideoMedia", Log::DEBUG, "Message received");
+
+  if (m->message == Message::MOUSE_LBDOWN)
+  {
+    UINT x = (m->parameter>>16) - getScreenX();
+    UINT y = (m->parameter&0xFFFF) - getScreenY();
+
+    if (!barShowing)
+    {
+      BoxStack::getInstance()->handleCommand(Remote::OK); //simulate rok press
+    }
+    else if (barRegion.x<=x && barRegion.y<=y && (barRegion.x+barRegion.w)>=x && (barRegion.y+barRegion.h)>=y)
+    {
+      int progBarXbase = barRegion.x + 300;
+      if (x>=barRegion.x + progBarXbase + 24
+          && x<=barRegion.x + progBarXbase + 4 + 302
+          && y>=barRegion.y + 12 - 2
+          && y<=barRegion.y + 12 - 2+28)
+      {
+        int cx=x-(barRegion.x + progBarXbase + 4);
+        double percent=((double)cx)/302.*100.;
+        player->jumpToPercent(percent);
+        doBar(3);
+        return;
+        //  int progressWidth = 302 * currentFrameNum / lengthFrames;
+        //  rectangle(barRegion.x + progBarXbase + 4, barRegion.y + 16, progressWidth, 16, DrawStyle::SELECTHIGHLIGHT);
+      }
+    }
+    else
+    {
+      BoxStack::getInstance()->handleCommand(Remote::OK); //simulate rok press
+    }
+  }
+  else if (m->message == Message::PLAYER_EVENT)
+  {
+    switch(m->parameter)
+    {
+      case PlayerMedia::CONNECTION_LOST: // connection lost detected
+      {
+        // I can't handle this, send it to command
+        Message* m2 = new Message();
+        m2->to = Command::getInstance();
+        m2->message = Message::CONNECTION_LOST;
+        Command::getInstance()->postMessageNoLock(m2);
+        break;
+      }
+      case PlayerMedia::STREAM_END:
+      {
+        Message* m2 = new Message(); // Must be done after this thread finishes, and must break into master mutex
+        m2->to = BoxStack::getInstance();
+        m2->message = Message::CLOSE_ME;
+        Command::getInstance()->postMessageNoLock(m2);
+        break;
+      }
+      case PlayerMedia::STATUS_CHANGE:
+        doBar(0);
+        break;
+      case PlayerMedia::ASPECT43:
+      {
+        if (dowss)
+        {
+          Log::getInstance()->log("VVideoMedia", Log::DEBUG, "Received do WSS 43");
+          wss.setWide(false);
+          wss.draw();
+          boxstack->update(this, &wssRegion);
+        }
+        break;
+      }
+      case PlayerMedia::ASPECT169:
+      {
+        if (dowss)
+        {
+          Log::getInstance()->log("VVideoMedia", Log::DEBUG, "Received do WSS 169");
+          wss.setWide(true);
+          wss.draw();
+          boxstack->update(this, &wssRegion);
+        }
+        break;
+      }
+      case (PLAYER_TIMER_BASE+1) :
+        //timer1:
+        // Remove bar
+        removeBar();
+        break;
+      case (PLAYER_TIMER_BASE+2) :
+        //timer2:
+        // Update clock
+        if (!barShowing) break;
+        drawBarClocks();
+        BoxStack::getInstance()->update(this,&barRegion);
+        if (player->getLengthFrames() != 0)   timers->setTimerD(this, 2, 0, 200000000);
+        else   timers->setTimerD(this, 2, 1);
+        break;
+    }
+  }
+  else if (m->message == Message::AUDIO_CHANGE_CHANNEL)
+  {
+    Log::getInstance()->log("VVideoMedia", Log::DEBUG, "Received change audio channel to %i", m->parameter);
+    player->setAudioChannel(m->parameter);
+  }
+  else if (m->message == Message::CHILD_CLOSE)
+  {
+    if (m->from == vas)
+    {
+      vas = NULL;
+      barVasHold = false;
+      if (!barGenHold && !barScanHold && !barVasHold) removeBar();
+    }
+  }
+}
+
+void VVideoMedia::stopPlay()
+{
+  Log::getInstance()->log("VVideoMedia", Log::DEBUG, "Pre stopPlay");
+
+  removeBar();
+
+  player->stop();
+
+  playing = false;
+  MediaPlayer::getInstance()->closeMediaChannel(MEDIACHANNEL);
+
+  Log::getInstance()->log("VVideoMedia", Log::DEBUG, "Post stopPlay");
+}
+
+void VVideoMedia::toggleChopSides()
+{
+  if (video->getTVsize() == Video::ASPECT16X9) return; // Means nothing for 16:9 TVs
+
+  if (videoMode == Video::NORMAL)
+  {
+    videoMode = Video::LETTERBOX;
+    video->setMode(Video::LETTERBOX);
+  }
+  else
+  {
+    videoMode = Video::NORMAL;
+    video->setMode(Video::NORMAL);
+  }
+}
+
+void VVideoMedia::doAudioSelector()
+{
+  bool* availableMpegAudioChannels = player->getDemuxerMpegAudioChannels();
+  bool* availableAc3AudioChannels = 0;
+  int currentAudioChannel = player->getCurrentAudioChannel();
+  if (Audio::getInstance()->supportsAc3())
+  {
+      availableAc3AudioChannels = player->getDemuxerAc3AudioChannels();
+  }
+
+
+  RecInfo ri;
+  ri.summary=new char[strlen(myMedia->getDisplayName())+1];
+  strcpy(ri.summary,myMedia->getDisplayName());
+  vas = new VAudioSelector(this, availableMpegAudioChannels, availableAc3AudioChannels, currentAudioChannel, NULL,NULL,0,0, &ri);
+  vas->setBackgroundColour(barBlue);
+  vas->setPosition(0, barRegion.y - 120);
+
+// pal 62, ntsc 57
+
+  barVasHold = true;
+  doBar(0);
+
+  vas->draw();
+  boxstack->add(vas);
+  boxstack->update(vas);
+}
+
+void VVideoMedia::doBar(int action)
+{
+  Log::getInstance()->log("VVideoMedia",Log::DEBUG,"doBar %d",action);
+  barShowing = true;
+
+  rectangle(barRegion, barBlue);
+
+  /* Work out what to display - choices:
+
+  Playing  >
+  Paused   ||
+  FFwd     >>
+  FBwd     <<
+
+  Specials, informed by parameter
+
+  Skip forward 10s    >|
+  Skip backward 10s   |<
+  Skip forward 1m     >>|
+  Skip backward 1m    |<<
+
+  */
+
+  WSymbol w;
+  TEMPADD(&w);
+  w.nextSymbol = 0;
+  w.setPosition(barRegion.x + 66, barRegion.y + 16);
+
+  UCHAR playerState = 0;
+
+  if (action)
+  {
+    if (action == 1)       w.nextSymbol = WSymbol::SKIPFORWARD;
+    else if (action == 2)  w.nextSymbol = WSymbol::SKIPBACK;
+    else if (action == 3)  w.nextSymbol = WSymbol::SKIPFORWARD2;
+    else if (action == 4)  w.nextSymbol = WSymbol::SKIPBACK2;
+  }
+  else
+  {
+    playerState = player->getState();
+    if (playerState == PlayerMedia::S_PLAY)      w.nextSymbol = WSymbol::PLAY;
+    else if (playerState == PlayerMedia::S_FF)    w.nextSymbol = WSymbol::FFWD;
+    else if (playerState == PlayerMedia::S_BACK)    w.nextSymbol = WSymbol::FBWD;
+    else if (playerState == PlayerMedia::S_SEEK)    w.nextSymbol = WSymbol::RIGHTARROW;
+    else if (playerState == PlayerMedia::S_STOP)    w.nextSymbol = WSymbol::PAUSE;
+    else                                       w.nextSymbol = WSymbol::PAUSE;
+  }
+
+  w.draw();
+
+  if ((playerState == PlayerMedia::S_FF) || (playerState == PlayerMedia::S_BACK))
+  {
+    // draw blips to show how fast the scan is
+    UCHAR scanrate = 2;//player->getIScanRate();
+    if (scanrate >= 2)
+    {
+      char text[5];
+      SNPRINTF(text, 5, "%ux", scanrate);
+      drawText(text, barRegion.x + 102, barRegion.y + 12, DrawStyle::LIGHTTEXT);
+    }
+  }
+
+  drawBarClocks();
+  boxstack->update(this, &barRegion);
+
+  timers->cancelTimer(this, 1);
+
+
+  if ((playerState == PlayerMedia::S_FF) || (playerState == PlayerMedia::S_BACK)) barScanHold = true;
+  else barScanHold = false;
+
+  if (!barGenHold && !barScanHold && !barVasHold) timers->setTimerD(this, 1, 4);
+
+  if (player->getLengthFrames() != 0) timers->setTimerD(this, 2, 0, 200000000);
+  else timers->setTimerD(this, 2, 1);
+}
+
+void VVideoMedia::timercall(int clientReference)
+{
+  Message *m=new Message();
+  m->message=Message::PLAYER_EVENT;
+  m->to=this;
+  m->from=this;
+  m->parameter=PLAYER_TIMER_BASE+clientReference;
+  Command::getInstance()->postMessageFromOuterSpace(m);
+}
+
+void VVideoMedia::drawBarClocks()
+{
+  if (barScanHold)
+  {
+    UCHAR playerState = player->getState();
+    // sticky bar is set if we are in ffwd/fbwd mode
+    // if player has gone to S_PLAY then kill stickyBar, and run doBar(0) which
+    // will repaint all the bar (it will call this function again, but
+    // this section won't run because stickyBarF will then == false)
+
+    if ((playerState != PlayerMedia::S_FF) && (playerState != PlayerMedia::S_BACK))
+    {
+      barScanHold = false;
+      doBar(0);
+      return; 
+    }
+  }
+
+  Log* logger = Log::getInstance();
+  logger->log("VVideoMedia", Log::DEBUG, "Draw bar clocks");
+
+  // Draw RTC
+  // Blank the area first
+  rectangle(barRegion.x + 624, barRegion.y + 12, 60, 30, barBlue);
+  char timeString[20];
+  time_t t;
+  time(&t);
+  struct tm* tms = localtime(&t);
+  strftime(timeString, 19, "%H:%M", tms);
+  drawText(timeString, barRegion.x + 624, barRegion.y + 12, DrawStyle::LIGHTTEXT);
+
+  ULLONG lenPTS=player->getLenPTS();
+  // Draw clocks
+
+  rectangle(clocksRegion, barBlue);
+
+  ULLONG currentPTS = player->getCurrentPTS();
+
+  hmsf currentFrameHMSF = ptsToHMS(currentPTS);
+  hmsf lengthHMSF = ptsToHMS(lenPTS);
+
+  char buffer[100];
+  if (currentPTS > lenPTS && lenPTS != 0)
+  {
+    strcpy(buffer, "-:--:-- / -:--:--");
+  }
+  else
+  {
+    SNPRINTF(buffer, 99, "%01i:%02i:%02i / %01i:%02i:%02i", currentFrameHMSF.hours, currentFrameHMSF.minutes, currentFrameHMSF.seconds, lengthHMSF.hours, lengthHMSF.minutes, lengthHMSF.seconds);
+  }
+    logger->log("VVideoMedia", Log::DEBUG, "cur %llu,len %llu, txt %s",currentPTS,lenPTS,buffer);
+
+  drawText(buffer, clocksRegion.x, clocksRegion.y, DrawStyle::LIGHTTEXT);
+
+
+
+
+
+
+
+  // Draw progress bar
+  int progBarXbase = barRegion.x + 300;
+
+  if (lenPTS == 0) return;
+  rectangle(barRegion.x + progBarXbase, barRegion.y + 12, 310, 24, DrawStyle::LIGHTTEXT);
+  rectangle(barRegion.x + progBarXbase + 2, barRegion.y + 14, 306, 20, barBlue);
+
+  if (currentPTS > lenPTS) return;
+
+  // Draw yellow portion
+  int progressWidth = 302 * currentPTS / lenPTS;
+  rectangle(barRegion.x + progBarXbase + 4, barRegion.y + 16, progressWidth, 16, DrawStyle::SELECTHIGHLIGHT);
+
+}
+
+void VVideoMedia::removeBar()
+{
+  if (!barShowing) return;
+  timers->cancelTimer(this, 2);
+  barShowing = false;
+  barGenHold = false;
+  barScanHold = false;
+  barVasHold = false;
+  rectangle(barRegion, transparent);
+  BoxStack::getInstance()->update(this, &barRegion);
+}
+
+void VVideoMedia::doSummary()
+{
+  vsummary = new VInfo();
+  vsummary->setTitleText(myMedia->getDisplayName());
+  vsummary->setBorderOn(1);
+  vsummary->setExitable();
+  const MediaURI *u=myMedia->getURI();
+  int stlen=0;
+  if (u) {
+    stlen+=strlen(myMedia->getFileName());
+    stlen+=strlen(tr("FileName"))+10;
+  }
+  stlen+=strlen(tr("Size"))+50;
+  stlen+=strlen(tr("Directory"))+500;
+  stlen+=strlen(tr("Time"))+50;
+  char *pinfo=player->getInfo();
+  stlen+=strlen(pinfo)+10;
+  char *buf=new char [stlen];
+  char *tsbuf=new char [stlen];
+  char *tsbuf2=new char [stlen];
+  char *tbuf=new char[Media::TIMEBUFLEN];
+  SNPRINTF(buf,stlen,"%s\n" 
+                   "%s: %llu Bytes\n"
+                   "%s\n"
+                   "%s: %s\n"
+                   "%s",
+      shortendedText(tr("FileName"),": ",myMedia->getFileName(),tsbuf,vsummary->getWidth()),
+      tr("Size"),
+      lengthBytes,
+      shortendedText(tr("Directory"),": ",lparent->getDirname(MEDIA_TYPE_VIDEO),tsbuf2,vsummary->getWidth()),
+      tr("Time"),
+      myMedia->getTimeString(tbuf),
+      pinfo
+      );
+  //TODO more info
+  if (u) {
+      Log::getInstance()->log("VVideoMedia",Log::DEBUG,"info %s",buf);
+      vsummary->setMainText(buf);
+  }
+  else vsummary->setMainText(tr("Info unavailable"));
+  delete pinfo;
+  if (Video::getInstance()->getFormat() == Video::PAL)
+  {
+    vsummary->setPosition(70, 100);
+  }
+  else
+  {
+    vsummary->setPosition(40, 70);
+  }
+  vsummary->setSize(580, 350);
+  add(vsummary);
+  vsummary->draw();
+
+  BoxStack::getInstance()->update(this);
+   delete [] buf;
+  delete []  tsbuf;
+  delete [] tsbuf2;
+  delete []  tbuf;
+}
+
+void VVideoMedia::removeSummary()
+{
+  if (vsummary)
+  {
+    remove(vsummary);
+    delete vsummary;
+    vsummary = NULL;
+    draw();
+    BoxStack::getInstance()->update(this);
+  }
+}
+
+
+hmsf VVideoMedia::ptsToHMS(ULLONG pts) {
+  ULLONG secs=pts/90000;
+  hmsf rt;
+  rt.frames=0;
+  rt.seconds=secs%60;
+  secs=secs/60;
+  rt.minutes=secs%60;
+  secs=secs/60;
+  rt.hours=secs;
+  return rt;
+}
+  
+char * VVideoMedia::shortendedText(const char * title, const char * title2,const char * intext,char *buffer,UINT width) {
+  if (! intext) {
+    intext="";
+  }
+  UINT twidth=0;
+  for (const char *p=title;*p!=0;p++) twidth+=charWidth(*p);
+  for (const char *p=title2;*p!=0;p++) twidth+=charWidth(*p);
+  const char *prfx="...";
+  UINT prfwidth=3*charWidth('.');
+  const char *istart=intext+strlen(intext);
+  UINT iwidth=0;
+  while (twidth+iwidth+prfwidth < width-2*paraMargin && istart> intext) {
+    istart--;
+    iwidth+=charWidth(*istart);
+  }
+  if (twidth+iwidth+prfwidth >= width-2*paraMargin && istart < intext+strlen(intext)) istart++;
+  if (istart == intext) prfx="";
+  sprintf(buffer,"%s%s%s%s",title,title2,prfx,intext);
+  return buffer;
+}
+
+
index 56142bb8ae31ee3b1d0d89b8eb33ac555fbe5863..654bc7785ac8254749dc5c8627c48f6164f52a46 100644 (file)
-/*\r
-    Copyright 2004-2005 Chris Tallon\r
-\r
-    This file is part of VOMP.\r
-\r
-    VOMP is free software; you can redistribute it and/or modify\r
-    it under the terms of the GNU General Public License as published by\r
-    the Free Software Foundation; either version 2 of the License, or\r
-    (at your option) any later version.\r
-\r
-    VOMP is distributed in the hope that it will be useful,\r
-    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-    GNU General Public License for more details.\r
-\r
-    You should have received a copy of the GNU General Public License\r
-    along with VOMP; if not, write to the Free Software\r
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
-*/\r
-\r
-#include <math.h>\r
-\r
-#include "vvideorec.h"\r
-#include "vteletextview.h"\r
-\r
-#include "command.h"\r
-#include "osd.h"\r
-#include "wsymbol.h"\r
-#include "audio.h"\r
-#include "vdr.h"\r
-#include "video.h"\r
-#include "timers.h"\r
-#include "player.h"\r
-#include "recording.h"\r
-#include "vaudioselector.h"\r
-#include "message.h"\r
-#include "remote.h"\r
-#include "boxstack.h"\r
-#include "vinfo.h"\r
-#include "i18n.h"\r
-#include "bitmap.h"\r
-#include "recinfo.h"\r
-#include "log.h"\r
-#include "channel.h"\r
\r
-VVideoRec::VVideoRec(Recording* rec, bool ish264)\r
-{\r
-  boxstack = BoxStack::getInstance();\r
-  vdr = VDR::getInstance();\r
-  video = Video::getInstance();\r
-  timers = Timers::getInstance();\r
-  vas = NULL;\r
-  vsummary = NULL;\r
-\r
-  videoMode = video->getMode();\r
-  myRec = rec;\r
-\r
-  video->seth264mode(ish264);\r
-\r
-  player = new Player(Command::getInstance(), this, this);\r
-  player->init(myRec->IsPesRecording,myRec->recInfo->fps);\r
-\r
-  playing = false;\r
-\r
-  startMargin = 0;\r
-  endMargin = 0;\r
-  char* cstartMargin = vdr->configLoad("Timers", "Start margin");\r
-  char* cendMargin = vdr->configLoad("Timers", "End margin");\r
-  if (!cstartMargin)\r
-  {\r
-    startMargin = 300; // 5 mins default\r
-  }\r
-  else\r
-  {\r
-    startMargin = atoi(cstartMargin) * 60;\r
-    delete[] cstartMargin;\r
-  }\r
-\r
-  if (!cendMargin)\r
-  {\r
-    endMargin = 300; // 5 mins default\r
-  }\r
-  else\r
-  {\r
-    endMargin = atoi(cendMargin) * 60;\r
-    delete[] cendMargin;\r
-  }\r
-\r
-  Log::getInstance()->log("VVideoRec", Log::DEBUG, "SM: %u EM: %u", startMargin, endMargin);\r
-\r
-  setSize(video->getScreenWidth(), video->getScreenHeight());\r
-  createBuffer();\r
-  transparent.set(0, 0, 0, 0);\r
-  setBackgroundColour(transparent);\r
-\r
-  barRegion.x = 0;\r
-  barRegion.y = video->getScreenHeight() - 58;   // FIXME, need to be - 1? and below?\r
-  barRegion.w = video->getScreenWidth();\r
-  barRegion.h = 58;\r
-\r
-  clocksRegion.x = barRegion.x + 140;\r
-  clocksRegion.y = barRegion.y + 12;\r
-  clocksRegion.w = 170;\r
-  clocksRegion.h = getFontHeight();\r
-//  barBlue.set(0, 0, 150, 150);\r
-  barBlue.set(0, 0, 0, 128);\r
-\r
-  barShowing = false;\r
-  barGenHold = false;\r
-  barScanHold = false;\r
-  barVasHold = false;\r
-#ifdef PAL_WSS\r
-  dowss = false;\r
-  char* optionWSS = vdr->configLoad("General", "WSS");\r
-  if (optionWSS)\r
-  {\r
-    if (strstr(optionWSS, "Yes")) dowss = true;\r
-    delete[] optionWSS;\r
-  }\r
-  Log::getInstance()->log("VVideoRec", Log::DEBUG, "Do WSS: %u", dowss);\r
-\r
-  if (dowss)\r
-  {\r
-    wss.setFormat(video->getFormat());\r
-    wss.setWide(true);\r
-    add(&wss);\r
-\r
-    wssRegion.x = 0;\r
-    wssRegion.y = 0;\r
-    wssRegion.w = video->getScreenWidth();\r
-    wssRegion.h = 300;\r
-  }\r
-#endif\r
-}\r
-\r
-void VVideoRec::preDelete()\r
-{\r
-  timers->cancelTimer(this, 1);\r
-  timers->cancelTimer(this, 2);\r
-\r
-  if (vas)\r
-  {\r
-    boxstack->remove(vas);\r
-    vas = NULL;\r
-  }\r
-\r
-  if (vsummary) delete vsummary;\r
-\r
-  if (playing) stopPlay();\r
-}\r
-\r
-VVideoRec::~VVideoRec()\r
-{\r
-  Log::getInstance()->log("VVideoRec", Log::DEBUG, "Entering vvideorec destructor");\r
-\r
-  video->setDefaultAspect();\r
-\r
-  // kill recInfo in case resumePoint has changed (likely)\r
-  myRec->dropRecInfo();\r
-  // FIXME - do this properly - save the resume point back to the server manually and update\r
-  // rec->recInfo->resumePoint - this will fix the ~10s offset problem as well\r
-}\r
-\r
-void VVideoRec::go(bool resume)\r
-{\r
-  ULONG startFrameNum;\r
-  if (resume)\r
-    startFrameNum = myRec->recInfo->resumePoint;\r
-  else\r
-    startFrameNum = 0;\r
-\r
-  Log::getInstance()->log("VVideoRec", Log::DEBUG, "Starting stream: %s at frame: %lu", myRec->getFileName(), startFrameNum);\r
-  ULONG lengthFrames = 0;\r
-  bool isPesRecording;\r
-  ULLONG lengthBytes = vdr->streamRecording(myRec->getFileName(), &lengthFrames, &isPesRecording);\r
-  myRec->IsPesRecording = isPesRecording;\r
-  if (lengthBytes)\r
-  {\r
-    player->setLengthBytes(lengthBytes);\r
-    player->setLengthFrames(lengthFrames);\r
-    player->setStartFrame(startFrameNum);\r
-    player->play();\r
-    playing = true;\r
-    doBar(0);\r
-  }\r
-  else\r
-  {\r
-    stopPlay(); // clean up\r
-\r
-    if (!vdr->isConnected())\r
-    {\r
-      Command::getInstance()->connectionLost();\r
-      return;\r
-    }\r
-\r
-    Message* m = new Message();\r
-    m->message = Message::CLOSE_ME;\r
-    m->from = this;\r
-    m->to = boxstack;\r
-    Command::getInstance()->postMessageNoLock(m);\r
-\r
-    VInfo* vi = new VInfo();\r
-    vi->setSize(400, 150);\r
-    vi->createBuffer();\r
-    if (video->getFormat() == Video::PAL)\r
-      vi->setPosition(170, 200);\r
-    else\r
-      vi->setPosition(160, 150);\r
-    vi->setExitable();\r
-    vi->setBorderOn(1);\r
-    vi->setTitleBarOn(0);\r
-    vi->setOneLiner(tr("Error playing recording"));\r
-    vi->draw();\r
-\r
-    m = new Message();\r
-    m->message = Message::ADD_VIEW;\r
-    m->to = boxstack;\r
-    m->parameter = (ULONG)vi;\r
-    Command::getInstance()->postMessageNoLock(m);\r
-  }\r
-}\r
-\r
-int VVideoRec::handleCommand(int command)\r
-{\r
-  switch(command)\r
-  {\r
+/*
+    Copyright 2004-2005 Chris Tallon
+
+    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 <math.h>
+
+#include "vvideorec.h"
+#include "vteletextview.h"
+
+#include "command.h"
+#include "osd.h"
+#include "wsymbol.h"
+#include "audio.h"
+#include "vdr.h"
+#include "video.h"
+#include "timers.h"
+#include "player.h"
+#include "recording.h"
+#include "vaudioselector.h"
+#include "message.h"
+#include "remote.h"
+#include "boxstack.h"
+#include "vinfo.h"
+#include "i18n.h"
+#include "bitmap.h"
+#include "recinfo.h"
+#include "log.h"
+#include "channel.h"
+VVideoRec::VVideoRec(Recording* rec, bool ish264)
+{
+  boxstack = BoxStack::getInstance();
+  vdr = VDR::getInstance();
+  video = Video::getInstance();
+  timers = Timers::getInstance();
+  vas = NULL;
+  vsummary = NULL;
+
+  videoMode = video->getMode();
+  myRec = rec;
+
+  video->seth264mode(ish264);
+
+  player = new Player(Command::getInstance(), this, this);
+  player->init(myRec->IsPesRecording,myRec->recInfo->fps);
+
+  playing = false;
+
+  startMargin = 0;
+  endMargin = 0;
+  char* cstartMargin = vdr->configLoad("Timers", "Start margin");
+  char* cendMargin = vdr->configLoad("Timers", "End margin");
+  if (!cstartMargin)
+  {
+    startMargin = 300; // 5 mins default
+  }
+  else
+  {
+    startMargin = atoi(cstartMargin) * 60;
+    delete[] cstartMargin;
+  }
+
+  if (!cendMargin)
+  {
+    endMargin = 300; // 5 mins default
+  }
+  else
+  {
+    endMargin = atoi(cendMargin) * 60;
+    delete[] cendMargin;
+  }
+
+  Log::getInstance()->log("VVideoRec", Log::DEBUG, "SM: %u EM: %u", startMargin, endMargin);
+
+  setSize(video->getScreenWidth(), video->getScreenHeight());
+  createBuffer();
+  transparent.set(0, 0, 0, 0);
+  setBackgroundColour(transparent);
+
+  barRegion.x = 0;
+  barRegion.y = video->getScreenHeight() - 58;   // FIXME, need to be - 1? and below?
+  barRegion.w = video->getScreenWidth();
+  barRegion.h = 58;
+
+  clocksRegion.x = barRegion.x + 140;
+  clocksRegion.y = barRegion.y + 12;
+  clocksRegion.w = 170;
+  clocksRegion.h = getFontHeight();
+//  barBlue.set(0, 0, 150, 150);
+  barBlue.set(0, 0, 0, 128);
+
+  barShowing = false;
+  barGenHold = false;
+  barScanHold = false;
+  barVasHold = false;
+#ifdef PAL_WSS
+  dowss = false;
+  char* optionWSS = vdr->configLoad("General", "WSS");
+  if (optionWSS)
+  {
+    if (strstr(optionWSS, "Yes")) dowss = true;
+    delete[] optionWSS;
+  }
+  Log::getInstance()->log("VVideoRec", Log::DEBUG, "Do WSS: %u", dowss);
+
+  if (dowss)
+  {
+    wss.setFormat(video->getFormat());
+    wss.setWide(true);
+    add(&wss);
+
+    wssRegion.x = 0;
+    wssRegion.y = 0;
+    wssRegion.w = video->getScreenWidth();
+    wssRegion.h = 300;
+  }
+#endif
+}
+
+void VVideoRec::preDelete()
+{
+  timers->cancelTimer(this, 1);
+  timers->cancelTimer(this, 2);
+
+  if (vas)
+  {
+    boxstack->remove(vas);
+    vas = NULL;
+  }
+
+  if (vsummary) delete vsummary;
+
+  if (playing) stopPlay();
+}
+
+VVideoRec::~VVideoRec()
+{
+  Log::getInstance()->log("VVideoRec", Log::DEBUG, "Entering vvideorec destructor");
+
+  video->setDefaultAspect();
+
+  // kill recInfo in case resumePoint has changed (likely)
+  myRec->dropRecInfo();
+  // FIXME - do this properly - save the resume point back to the server manually and update
+  // rec->recInfo->resumePoint - this will fix the ~10s offset problem as well
+}
+
+void VVideoRec::go(bool resume)
+{
+  ULONG startFrameNum;
+  if (resume)
+    startFrameNum = myRec->recInfo->resumePoint;
+  else
+    startFrameNum = 0;
+
+  Log::getInstance()->log("VVideoRec", Log::DEBUG, "Starting stream: %s at frame: %lu", myRec->getFileName(), startFrameNum);
+  ULONG lengthFrames = 0;
+  bool isPesRecording;
+  ULLONG lengthBytes = vdr->streamRecording(myRec->getFileName(), &lengthFrames, &isPesRecording);
+  myRec->IsPesRecording = isPesRecording;
+  if (lengthBytes)
+  {
+    player->setLengthBytes(lengthBytes);
+    player->setLengthFrames(lengthFrames);
+    player->setStartFrame(startFrameNum);
+    player->play();
+    playing = true;
+    doBar(0);
+  }
+  else
+  {
+    stopPlay(); // clean up
+
+    if (!vdr->isConnected())
+    {
+      Command::getInstance()->connectionLost();
+      return;
+    }
+
+    Message* m = new Message();
+    m->message = Message::CLOSE_ME;
+    m->from = this;
+    m->to = boxstack;
+    Command::getInstance()->postMessageNoLock(m);
+
+    VInfo* vi = new VInfo();
+    vi->setSize(400, 150);
+    vi->createBuffer();
+    if (video->getFormat() == Video::PAL)
+      vi->setPosition(170, 200);
+    else
+      vi->setPosition(160, 150);
+    vi->setExitable();
+    vi->setBorderOn(1);
+    vi->setTitleBarOn(0);
+    vi->setOneLiner(tr("Error playing recording"));
+    vi->draw();
+
+    m = new Message();
+    m->message = Message::ADD_VIEW;
+    m->to = boxstack;
+    m->parameter = (ULONG)vi;
+    Command::getInstance()->postMessageNoLock(m);
+  }
+}
+
+int VVideoRec::handleCommand(int command)
+{
+  switch(command)
+  {
     case Remote::UP:
-    case Remote::PLAY:\r
-    {\r
-      player->play();\r
-      doBar(0);\r
-      return 2;\r
-    }\r
-\r
-    case Remote::PLAYPAUSE:\r
-    {\r
-       player->playpause();\r
-        doBar(0);\r
-        return 2;\r
-    }\r
-\r
-    case Remote::BACK:\r
-    {\r
-      if (vsummary)\r
-      {\r
-        removeSummary();\r
-        return 2;\r
-      }\r
-    } // DROP THROUGH\r
-    case Remote::STOP:\r
-    case Remote::MENU:\r
-    {\r
-      if (playing) stopPlay();\r
-\r
-      return 4;\r
-    }\r
+    case Remote::PLAY:
+    {
+      player->play();
+      doBar(0);
+      return 2;
+    }
+
+    case Remote::PLAYPAUSE:
+    {
+       player->playpause();
+        doBar(0);
+        return 2;
+    }
+
+    case Remote::BACK:
+    {
+      if (vsummary)
+      {
+        removeSummary();
+        return 2;
+      }
+    } // DROP THROUGH
+    case Remote::STOP:
+    case Remote::MENU:
+    {
+      if (playing) stopPlay();
+
+      return 4;
+    }
     case Remote::DOWN:
-    case Remote::PAUSE:\r
-    {\r
-      player->pause();\r
-      doBar(0);\r
-      return 2;\r
-    }\r
-    case Remote::SKIPFORWARD:\r
-    {\r
-      doBar(3);\r
-      player->skipForward(60);\r
-      return 2;\r
-    }\r
-    case Remote::SKIPBACK:\r
-    {\r
-      doBar(4);\r
-      player->skipBackward(60);\r
-      return 2;\r
-    }\r
+    case Remote::PAUSE:
+    {
+      player->pause();
+      doBar(0);
+      return 2;
+    }
+    case Remote::SKIPFORWARD:
+    {
+      doBar(3);
+      player->skipForward(60);
+      return 2;
+    }
+    case Remote::SKIPBACK:
+    {
+      doBar(4);
+      player->skipBackward(60);
+      return 2;
+    }
     case Remote::RIGHT:
-    case Remote::FORWARD:\r
-    {\r
-      player->fastForward();\r
-      doBar(0);\r
-      return 2;\r
-    }\r
+    case Remote::FORWARD:
+    {
+      player->fastForward();
+      doBar(0);
+      return 2;
+    }
     case Remote::LEFT:
-    case Remote::REVERSE:\r
-    {\r
-      player->fastBackward();\r
-      doBar(0);\r
-      return 2;\r
-    }\r
-    case Remote::RED:\r
-    {\r
-      if (vsummary) removeSummary();\r
-      else doSummary();\r
-      return 2;\r
-    }\r
-    case Remote::GREEN:\r
-    {\r
-      doAudioSelector();\r
-      return 2;\r
-    }\r
-    case Remote::YELLOW:\r
-    {\r
-      if (myRec->hasMarks())\r
-      {\r
-        // skip to previous mark\r
-        Log* logger = Log::getInstance();\r
-        int currentFrame = (player->getCurrentFrameNum()); // get current Frame\r
-        currentFrame -= 5. * myRec->recInfo->fps; // subtrack 5 seconds, else you cannot skip more than once back ..\r
-\r
-        int prevMark = myRec->getPrevMark(currentFrame); // find previous Frame\r
-        if (prevMark)\r
-        {\r
-          logger->log("VVideoRec", Log::NOTICE, "jump back from pos %i to mark at %i",currentFrame,prevMark);\r
-          player->jumpToMark(prevMark);\r
-        }\r
-        doBar(4);\r
-      }\r
-      else\r
-      {\r
-        doBar(2);\r
-        player->skipBackward(10);\r
-      }\r
-      return 2;\r
-    }\r
-    case Remote::BLUE:\r
-    {\r
-      if (myRec->hasMarks())\r
-      {\r
-        // skip to next mark\r
-        Log* logger = Log::getInstance();\r
-        int currentFrame = (player->getCurrentFrameNum());\r
-\r
-        int nextMark = myRec->getNextMark(currentFrame);\r
-\r
-        if (nextMark)\r
-        {\r
-          logger->log("VVideoRec", Log::NOTICE, "jump forward from pos %i to mark at %i",currentFrame,nextMark);\r
-          player->jumpToMark(nextMark);\r
-        }\r
-        doBar(3);\r
-      }\r
-      else\r
-      {\r
-        doBar(1);\r
-        player->skipForward(10);\r
-      }\r
-      return 2;\r
-    }\r
-    case Remote::STAR:\r
-    {\r
-      doBar(2);\r
-      player->skipBackward(10);\r
-      return 2;\r
-    }\r
-    case Remote::HASH:\r
-    {\r
-      doBar(1);\r
-      player->skipForward(10);\r
-      return 2;\r
-    }\r
-    case Remote::FULL:\r
-    case Remote::TV:\r
-    {\r
-      toggleChopSides();\r
-      return 2;\r
-    }\r
-\r
-    case Remote::OK:\r
-    {\r
-      if (vsummary)\r
-      {\r
-        removeSummary();\r
-        return 2;\r
-      }\r
-      \r
-      if (barShowing) removeBar();\r
-      else doBar(0);\r
-      return 2;\r
-    }\r
-\r
-    case Remote::ZERO:  player->jumpToPercent(0);  doBar(0);  return 2;\r
-    case Remote::ONE:   player->jumpToPercent(10); doBar(0);  return 2;\r
-    case Remote::TWO:   player->jumpToPercent(20); doBar(0);  return 2;\r
-    case Remote::THREE: player->jumpToPercent(30); doBar(0);  return 2;\r
-    case Remote::FOUR:  player->jumpToPercent(40); doBar(0);  return 2;\r
-    case Remote::FIVE:  player->jumpToPercent(50); doBar(0);  return 2;\r
-    case Remote::SIX:   player->jumpToPercent(60); doBar(0);  return 2;\r
-    case Remote::SEVEN: player->jumpToPercent(70); doBar(0);  return 2;\r
-    case Remote::EIGHT: player->jumpToPercent(80); doBar(0);  return 2;\r
-    case Remote::NINE:  player->jumpToPercent(90); doBar(0);  return 2;\r
-\r
-    case Remote::RECORD: player->toggleSubtitles(); return 2;\r
-#ifdef DEV\r
-//    case Remote::RED:\r
-//    {\r
-      //Don't use RED for anything. It will eventually be recording summary\r
-\r
-      //player->test1();\r
-\r
-\r
-      /*\r
-      // for testing EPG in NTSC with a NTSC test video\r
-      Video::getInstance()->setMode(Video::QUARTER);\r
-      Video::getInstance()->setPosition(170, 5);\r
-      VEpg* vepg = new VEpg(NULL, 0);\r
-      vepg->draw();\r
-      BoxStack::getInstance()->add(vepg);\r
-      BoxStack::getInstance()->update(vepg);\r
-      */\r
-\r
-//      return 2;\r
-//    }\r
-\r
-#endif\r
-\r
-  }\r
-\r
-  return 1;\r
-}\r
-\r
-void VVideoRec::doTeletext()\r
-{\r
-  \r
-  bool exists=true;\r
-\r
-  \r
-  // Draw the teletxt\r
-  VTeletextView *vtxv=player->getTeletextDecoder()->getTeletxtView();\r
-  if (vtxv==NULL) {\r
-       vtxv= new VTeletextView((player)->getTeletextDecoder(),this);\r
-      (player)->getTeletextDecoder()->registerTeletextView(vtxv);\r
-      exists=false;\r
-  }\r
-  vtxv->setSubtitleMode(true);\r
-  vtxv->draw();\r
-  draw();\r
-  \r
-  if (!exists) {\r
-      BoxStack::getInstance()->add(vtxv);\r
-  }\r
-  BoxStack::getInstance()->update(this);\r
-  BoxStack::getInstance()->update(vtxv); \r
-}\r
-\r
-void VVideoRec::processMessage(Message* m)\r
-{\r
-  Log::getInstance()->log("VVideoRec", Log::DEBUG, "Message received");\r
-\r
-  if (m->message == Message::MOUSE_LBDOWN)\r
-  {\r
-    UINT x = (m->parameter>>16) - getScreenX();\r
-    UINT y = (m->parameter&0xFFFF) - getScreenY();\r
-\r
-    if (!barShowing)\r
-    {\r
-      BoxStack::getInstance()->handleCommand(Remote::OK); //simulate rok press\r
-    }\r
-    else if (barRegion.x<=x && barRegion.y<=y && (barRegion.x+barRegion.w)>=x && (barRegion.y+barRegion.h)>=y)\r
-    {\r
-      int progBarXbase = barRegion.x + 300;\r
-      if (myRec->hasMarks())\r
-      {\r
-        MarkList* markList = myRec->getMarkList();\r
-        MarkList::iterator i;\r
-        Mark* loopMark = NULL;\r
-        int posPix;\r
-        ULONG lengthFrames;\r
-        if (myRec->recInfo->timerEnd > time(NULL))\r
-        {\r
-          // chasing playback\r
-          // Work out an approximate length in frames (good to 1s...)\r
-                       lengthFrames = (ULONG)((double)(myRec->recInfo->timerEnd - myRec->recInfo->timerStart) * myRec->recInfo->fps);\r
-        }\r
-        else\r
-        {\r
-          lengthFrames = player->getLengthFrames();\r
-        }\r
-        for(i = markList->begin(); i != markList->end(); i++)\r
-        {\r
-          loopMark = *i;\r
-          if (loopMark->pos)\r
-          {\r
-            posPix = 302 * loopMark->pos / lengthFrames;\r
-            rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 - 2, 3, 28, DrawStyle::DANGER);\r
-            if (x>=barRegion.x + progBarXbase + 2 + posPix\r
-                && x<=barRegion.x + progBarXbase + 2 + posPix+3\r
-                && y>=barRegion.y + 12 - 2\r
-                && y<=barRegion.y + 12 - 2+28)\r
-            {\r
-              player->jumpToMark(loopMark->pos);\r
-              doBar(3);\r
-              return;\r
-            }\r
-          }\r
-        }\r
-      }\r
-\r
-      if (x>=barRegion.x + progBarXbase + 24\r
-          && x<=barRegion.x + progBarXbase + 4 + 302\r
-          && y>=barRegion.y + 12 - 2\r
-          && y<=barRegion.y + 12 - 2+28)\r
-      {\r
-        int cx=x-(barRegion.x + progBarXbase + 4);\r
-        double percent=((double)cx)/302.*100.;\r
-        player->jumpToPercent(percent);\r
-        doBar(3);\r
-        return;\r
-        //  int progressWidth = 302 * currentFrameNum / lengthFrames;\r
-        //  rectangle(barRegion.x + progBarXbase + 4, barRegion.y + 16, progressWidth, 16, DrawStyle::SELECTHIGHLIGHT);\r
-      }\r
-    }\r
-    else\r
-    {\r
-      BoxStack::getInstance()->handleCommand(Remote::OK); //simulate rok press\r
-    }\r
-  }\r
-  else if (m->from == player)\r
-  {\r
-    if (m->message != Message::PLAYER_EVENT) return;\r
-    switch(m->parameter)\r
-    {\r
-      case Player::CONNECTION_LOST: // connection lost detected\r
-      {\r
-        // I can't handle this, send it to command\r
-        Message* m2 = new Message();\r
-        m2->to = Command::getInstance();\r
-        m2->message = Message::CONNECTION_LOST;\r
-        Command::getInstance()->postMessageNoLock(m2);\r
-        break;\r
-      }\r
-      case Player::STOP_PLAYBACK:\r
-      {\r
-        // FIXME Obselete ish - improve this\r
-        Message* m2 = new Message(); // Must be done after this thread finishes, and must break into master mutex\r
-        m2->to = Command::getInstance();\r
-        m2->message = Message::STOP_PLAYBACK;\r
-        Command::getInstance()->postMessageNoLock(m2);\r
-        break;\r
-      }\r
-      case Player::ASPECT43:\r
-      {\r
-#ifdef PAL_WSS\r
-        if (dowss)\r
-        {\r
-          Log::getInstance()->log("VVideoRec", Log::DEBUG, "Received do WSS 43");\r
-          wss.setWide(false);\r
-          wss.draw();\r
-          boxstack->update(this, &wssRegion);\r
-        }\r
-#endif\r
-        break;\r
-      }\r
-      case Player::ASPECT169:\r
-      {\r
-#ifdef PAL_WSS\r
-        if (dowss)\r
-        {\r
-          Log::getInstance()->log("VVideoRec", Log::DEBUG, "Received do WSS 169");\r
-          wss.setWide(true);\r
-          wss.draw();\r
-          boxstack->update(this, &wssRegion);\r
-        }\r
-#endif\r
-        break;\r
-      }\r
-    }\r
-  }\r
-  else if (m->message == Message::AUDIO_CHANGE_CHANNEL)\r
-  {\r
-    Log::getInstance()->log("VVideoRec", Log::DEBUG, "Received change audio channel to %i", m->parameter);\r
-    player->setAudioChannel(m->parameter&0xFFFF,(m->parameter&0xFF0000)>> 16,(m->parameter&0xFF000000)>> 24 );\r
-  }\r
-  else if (m->message == Message::SUBTITLE_CHANGE_CHANNEL)\r
-  {\r
-      Log::getInstance()->log("VVideoRec", Log::DEBUG, "Received change subtitle channel to %i", m->parameter);\r
-      int type=((m->parameter & 0xFF0000)>>16);\r
-      switch (type) {\r
-      case 0x10: { //dvbsubtitle\r
-          player->setSubtitleChannel((m->parameter & 0xFFFF));\r
-          player->turnSubtitlesOn(true);\r
-          VTeletextView *vtxt=((Player*)player)->getTeletextDecoder()->getTeletxtView();\r
-          if (vtxt && vtxt->isInSubtitleMode()) {\r
-              BoxStack::getInstance()->remove(vtxt);\r
-          }\r
-                 } break;\r
-      case 0xFF: { //nosubtitles\r
-          \r
-           player->turnSubtitlesOn(false);\r
-           VTeletextView *vtxt=((Player*)player)->getTeletextDecoder()->getTeletxtView();\r
-           if (vtxt && vtxt->isInSubtitleMode()) {\r
-              BoxStack::getInstance()->remove(vtxt);\r
-           }  \r
-          \r
-                 } break;\r
-      case 0x11: { //videotext\r
-          player->turnSubtitlesOn(false);\r
-          doTeletext();\r
-          ((Player*)player)->getTeletextDecoder()->setPage((m->parameter & 0xFFFF));\r
-                 } break;\r
-      };\r
-      if (vas) {\r
-        BoxStack::getInstance()->update(vas);\r
-      }\r
-      BoxStack::getInstance()->update(this);\r
-\r
-      \r
-  } \r
-  else if (m->message == Message::CHILD_CLOSE)\r
-  {\r
-    if (m->from == vas)\r
-    {\r
-      vas = NULL;\r
-      barVasHold = false;\r
-      if (!barGenHold && !barScanHold && !barVasHold) removeBar();\r
-    }\r
-  }\r
-}\r
-\r
-void VVideoRec::stopPlay()\r
-{\r
-  Log::getInstance()->log("VVideoRec", Log::DEBUG, "Pre stopPlay");\r
-\r
-  removeBar();\r
-  Log::getInstance()->log("VVideoRec", Log::DEBUG, "1");\r
-  player->stop();\r
-  Log::getInstance()->log("VVideoRec", Log::DEBUG, "2");\r
-  vdr->stopStreaming();\r
-  Log::getInstance()->log("VVideoRec", Log::DEBUG, "3");\r
-  delete player;\r
-\r
-  playing = false;\r
-\r
-  if (!vdr->isConnected()) { Command::getInstance()->connectionLost(); return; }\r
-  Log::getInstance()->log("VVideoRec", Log::DEBUG, "Post stopPlay");\r
-}\r
-\r
-void VVideoRec::toggleChopSides()\r
-{\r
-  if (video->getTVsize() == Video::ASPECT16X9) return; // Means nothing for 16:9 TVs\r
-\r
-  if (videoMode == Video::NORMAL)\r
-  {\r
-    videoMode = Video::LETTERBOX;\r
-    video->setMode(Video::LETTERBOX);\r
-  }\r
-  else\r
-  {\r
-    videoMode = Video::NORMAL;\r
-    video->setMode(Video::NORMAL);\r
-  }\r
-}\r
-\r
-void VVideoRec::doAudioSelector()\r
-{\r
-    int subtitleChannel=player->getCurrentSubtitleChannel();\r
-    int subtitleType=0x10;\r
-    if (!(player)->isSubtitlesOn()) {\r
-        if ((player)->getTeletextDecoder()->getTeletxtView() &&\r
-            (player)->getTeletextDecoder()->getTeletxtView()->isInSubtitleMode() \r
-            ) {\r
-                subtitleChannel=(player)->getTeletextDecoder()->getPage();\r
-                subtitleType=0x11;\r
-      \r
-           } else {\r
-                subtitleType=0xFF; //turnedOff\r
-                subtitleChannel=0;\r
-          }\r
-    }\r
-    if (player->isPesRecording()) {\r
-        bool* availableMpegAudioChannels = player->getDemuxerMpegAudioChannels();\r
-        bool* availableAc3AudioChannels = NULL;\r
-        bool* availableSubtitleChannels = player->getDemuxerSubtitleChannels();\r
-        int *availableTTxtpages = player->getTeletxtSubtitlePages();\r
-        int currentAudioChannel = player->getCurrentAudioChannel();\r
-        if (Audio::getInstance()->supportsAc3())\r
-        {\r
-            availableAc3AudioChannels = player->getDemuxerAc3AudioChannels();\r
-        }\r
-        \r
-        vas = new VAudioSelector(this, availableMpegAudioChannels, availableAc3AudioChannels, currentAudioChannel,availableSubtitleChannels, availableTTxtpages,\r
-            subtitleChannel, subtitleType, myRec->recInfo);\r
-    } else {\r
-        // Draw the selector\r
-        Channel *temp_channel=player->getDemuxerChannel();\r
-       // RecInfo *cur_info= myRec->recInfo;\r
-     /*   unsigned char numchan_recinfo = cur_info->numComponents;\r
-        unsigned char numchan_subtitles_siz = temp_channel.numSPids;\r
-        ULONG mp_audcounter = 0;\r
-        ULONG ac3_counter = 0;\r
-        int dvb_subcounter = 1;*/\r
-        int i;\r
-        \r
-        /*unsigned char type;\r
-        char* lang;\r
-        char* description;\r
-        for (i = 0; i < numchan_recinfo; i++)\r
-        {   \r
-            apid* ac = NULL;\r
-            type = cur_info->types[i];\r
-            lang = cur_info->languages[i];\r
-            description = cur_info->descriptions[i];\r
-            \r
-\r
-            if (cur_info->streams[i] == 2) {\r
-                switch (type)\r
-                {\r
-                case 1: //mpaudio mono\r
-                case 3: //mpaudio stereo\r
-                    if (mp_audcounter < temp_channel.numAPids) ac = &temp_channel.apids[mp_audcounter];\r
-                    \r
-                    mp_audcounter++;\r
-                    break;\r
-                case 5: //ac3\r
-                    if (ac3_counter < temp_channel.numDPids) ac = &temp_channel.dpids[ac3_counter];\r
-                    ac3_counter++;\r
-                    break;\r
-                }\r
-            } else if (cur_info->streams[i] == 3){\r
-                if (dvb_subcounter < numchan_subtitles_siz) ac = &temp_channel.spids[dvb_subcounter];\r
-            } else continue; //neither audio nor subtitle\r
-            if (ac)\r
-            {\r
-                if (description && (strlen(description) > 0))\r
-                {\r
-                    ac->name = new char[strlen(description) + 1];\r
-                    strcpy(ac->name, description);\r
-                    \r
-                } else if (lang && strlen(lang) > 0)\r
-                {\r
-                    ac->name = new char[strlen(lang) + 1];\r
-                    strcpy(ac->name, lang);\r
-                    \r
-                }\r
-            }\r
-        }*/\r
-        for (i=0;i<temp_channel->numAPids;i++) {\r
-            apid *ac=&temp_channel->apids[i];\r
-            if (ac->desc[0]==0) {\r
-                strncpy(ac->desc, tr("unknown"),9);\r
-            }\r
-        }\r
-        for (i=0;i<temp_channel->numDPids;i++) {\r
-            apid *ac=&temp_channel->dpids[i];\r
-            if (ac->desc[0]==0) {\r
-                strncpy(ac->desc, tr("unknown"),9);\r
-            }\r
-        }\r
-        for (i=0;i<temp_channel->numSPids;i++) {\r
-            apid *ac=&temp_channel->spids[i];\r
-            if (ac->desc[0]==0) {\r
-                strncpy(ac->desc, tr("unknown"),9);\r
-            }\r
-        }\r
-\r
-        vas = new VAudioSelector(this,temp_channel , (player)->getCurrentAudioChannel(),\r
-            subtitleType,subtitleChannel,player->getTeletxtSubtitlePages());  \r
-      /*   for (i=0;i<temp_channel.numAPids;i++) {\r
-            apid *ac=&temp_channel.apids[i];\r
-            delete[] ac->name;\r
-            ac->name=NULL;\r
-        }\r
-        for (i=0;i<temp_channel.numDPids;i++) {\r
-            apid *ac=&temp_channel.dpids[i];\r
-            delete[] ac->name;\r
-            ac->name=NULL;\r
-        }\r
-        for (i=0;i<temp_channel.numSPids;i++) {\r
-            apid *ac=&temp_channel.spids[i];\r
-            delete[] ac->name;\r
-            ac->name=NULL;\r
-        }*/\r
-    }\r
-\r
-\r
-  vas->setBackgroundColour(barBlue);\r
-  vas->setPosition(0, barRegion.y - 120);\r
-\r
-// pal 62, ntsc 57\r
-\r
-  barVasHold = true;\r
-  doBar(0);\r
-\r
-  vas->draw();\r
-  boxstack->add(vas);\r
-  boxstack->update(vas);\r
-}\r
-\r
-void VVideoRec::doBar(int action)\r
-{\r
-  barShowing = true;\r
-\r
-  rectangle(barRegion, barBlue);\r
-\r
-  /* Work out what to display - choices:\r
-\r
-  Playing  >\r
-  Paused   ||\r
-  FFwd     >>\r
-  FBwd     <<\r
-\r
-  Specials, informed by parameter\r
-\r
-  Skip forward 10s    >|\r
-  Skip backward 10s   |<\r
-  Skip forward 1m     >>|\r
-  Skip backward 1m    |<<\r
-\r
-  */\r
-\r
-  WSymbol w;\r
-  TEMPADD(&w);\r
-  w.nextSymbol = 0;\r
-  w.setPosition(barRegion.x + 66, barRegion.y + 16);\r
-\r
-  UCHAR playerState = 0;\r
-\r
-  if (action)\r
-  {\r
-    if (action == 1)       w.nextSymbol = WSymbol::SKIPFORWARD;\r
-    else if (action == 2)  w.nextSymbol = WSymbol::SKIPBACK;\r
-    else if (action == 3)  w.nextSymbol = WSymbol::SKIPFORWARD2;\r
-    else if (action == 4)  w.nextSymbol = WSymbol::SKIPBACK2;\r
-  }\r
-  else\r
-  {\r
-    playerState = player->getState();\r
-    if (playerState == Player::S_PAUSE_P)      w.nextSymbol = WSymbol::PAUSE;\r
-    else if (playerState == Player::S_PAUSE_I) w.nextSymbol = WSymbol::PAUSE;\r
-    else if (playerState == Player::S_FFWD)    w.nextSymbol = WSymbol::FFWD;\r
-    else if (playerState == Player::S_FBWD)    w.nextSymbol = WSymbol::FBWD;\r
-    else                                       w.nextSymbol = WSymbol::PLAY;\r
-  }\r
-\r
-  w.draw();\r
-\r
-  if ((playerState == Player::S_FFWD) || (playerState == Player::S_FBWD))\r
-  {\r
-    // draw blips to show how fast the scan is\r
-    UCHAR scanrate = player->getIScanRate();\r
-    if (scanrate >= 2)\r
-    {\r
-      char text[5];\r
-      SNPRINTF(text, 5, "%ux", scanrate);\r
-      drawText(text, barRegion.x + 102, barRegion.y + 12, DrawStyle::LIGHTTEXT);\r
-    }\r
-  }\r
-\r
-  drawBarClocks();\r
-\r
-  boxstack->update(this, &barRegion);\r
-\r
-  timers->cancelTimer(this, 1);\r
-\r
-\r
-  if ((playerState == Player::S_FFWD) || (playerState == Player::S_FBWD)) barScanHold = true;\r
-  else barScanHold = false;\r
-\r
-  if (!barGenHold && !barScanHold && !barVasHold) timers->setTimerD(this, 1, 4);\r
-\r
-  timers->setTimerD(this, 2, 0, 200000000);\r
-}\r
-\r
-void VVideoRec::timercall(int clientReference)\r
-{\r
-  switch(clientReference)\r
-  {\r
-    case 1:\r
-    {\r
-      // Remove bar\r
-      removeBar();\r
-      break;\r
-    }\r
-    case 2:\r
-    {\r
-      // Update clock\r
-      if (!barShowing) break;\r
-      drawBarClocks();\r
-      boxstack->update(this, &barRegion);\r
-      \r
-      timers->setTimerD(this, 2, 0, 200000000);\r
-      break;\r
-    }\r
-  }\r
-}\r
-\r
-hmsf VVideoRec::framesToHMSF(ULONG frames)\r
-{\r
-  hmsf ret;\r
-  /* from vdr */\r
-  double Seconds;\r
-  double fps=myRec->recInfo->fps;\r
-  ret.frames= int(modf((frames + 0.5) / fps, &Seconds) * fps + 1);\r
-  int s = int(Seconds);\r
-  ret.seconds=s % 60;\r
-  ret.minutes = s / 60 % 60;\r
-  ret.hours = s / 3600;\r
-\r
-\r
-  return ret;\r
-}\r
-\r
-void VVideoRec::drawBarClocks()\r
-{\r
-  if (barScanHold)\r
-  {\r
-    UCHAR playerState = player->getState();\r
-    // sticky bar is set if we are in ffwd/fbwd mode\r
-    // if player has gone to S_PLAY then kill stickyBar, and run doBar(0) which\r
-    // will repaint all the bar (it will call this function again, but\r
-    // this section won't run because stickyBarF will then == false)\r
-\r
-    if ((playerState != Player::S_FFWD) && (playerState != Player::S_FBWD))\r
-    {\r
-      barScanHold = false;\r
-      doBar(0);\r
-      return; // doBar will call this function and do the rest\r
-    }\r
-  }\r
-\r
-  Log* logger = Log::getInstance();\r
-  logger->log("VVideoRec", Log::DEBUG, "Draw bar clocks");\r
-\r
-  // Draw RTC\r
-  // Blank the area first\r
-  rectangle(barRegion.x + 624, barRegion.y + 12, 60, 30, barBlue);\r
-  char timeString[20];\r
-  time_t t;\r
-  time(&t);\r
-  struct tm* tms = localtime(&t);\r
-  strftime(timeString, 19, "%H:%M", tms);\r
-  drawText(timeString, barRegion.x + 624, barRegion.y + 12, DrawStyle::LIGHTTEXT);\r
-\r
-  // Draw clocks\r
-\r
-  rectangle(clocksRegion, barBlue);\r
-\r
-  ULONG currentFrameNum = player->getCurrentFrameNum();\r
-  ULONG lengthFrames;\r
-  if (myRec->recInfo->timerEnd > time(NULL))\r
-  {\r
-    // chasing playback\r
-    // Work out an approximate length in frames (good to 1s...)\r
-    lengthFrames =(ULONG) ((double)(myRec->recInfo->timerEnd - myRec->recInfo->timerStart) * myRec->recInfo->fps);\r
-  }\r
-  else\r
-  {\r
-    lengthFrames = player->getLengthFrames();\r
-  }\r
-\r
-  hmsf currentFrameHMSF = framesToHMSF(currentFrameNum);\r
-  hmsf lengthHMSF = framesToHMSF(lengthFrames);\r
-\r
-  char buffer[100];\r
-  if (currentFrameNum >= lengthFrames)\r
-  {\r
-    strcpy(buffer, "-:--:-- / -:--:--");\r
-  }\r
-  else\r
-  {\r
-    SNPRINTF(buffer, 99, "%01i:%02i:%02i / %01i:%02i:%02i", currentFrameHMSF.hours, currentFrameHMSF.minutes, currentFrameHMSF.seconds, lengthHMSF.hours, lengthHMSF.minutes, lengthHMSF.seconds);\r
-    logger->log("VVideoRec", Log::DEBUG, buffer);\r
-  }\r
-\r
-  drawText(buffer, clocksRegion.x, clocksRegion.y, DrawStyle::LIGHTTEXT);\r
-\r
-\r
-\r
-\r
-\r
-\r
-\r
-  // Draw progress bar\r
-  int progBarXbase = barRegion.x + 300;\r
-\r
-  rectangle(barRegion.x + progBarXbase, barRegion.y + 12, 310, 24, DrawStyle::LIGHTTEXT);\r
-  rectangle(barRegion.x + progBarXbase + 2, barRegion.y + 14, 306, 20, barBlue);\r
-\r
-  if (currentFrameNum > lengthFrames) return;\r
-  if (lengthFrames == 0) return;\r
-\r
-  // Draw yellow portion\r
-  int progressWidth = 302 * currentFrameNum / lengthFrames;\r
-  rectangle(barRegion.x + progBarXbase + 4, barRegion.y + 16, progressWidth, 16, DrawStyle::SELECTHIGHLIGHT);\r
-\r
-  if (myRec->recInfo->timerEnd > time(NULL)) // if chasing\r
-  {\r
-    int nrWidth = (int)(302 * ((double)(lengthFrames - player->getLengthFrames()) / lengthFrames));\r
-\r
-    Log::getInstance()->log("GVASDF", Log::DEBUG, "Length Frames: %lu", lengthFrames);\r
-    Log::getInstance()->log("GVASDF", Log::DEBUG, "Player lf: %lu", player->getLengthFrames());\r
-    Log::getInstance()->log("GVASDF", Log::DEBUG, "NR WDITH: %i", nrWidth);\r
-    rectangle(barRegion.x + progBarXbase + 4 + 302 - nrWidth, barRegion.y + 16, nrWidth, 16, DrawStyle::RED);\r
-  }\r
-\r
-  int posPix;\r
-  // Now calc position for blips\r
-\r
-  if (myRec->hasMarks())\r
-  {\r
-    // Draw blips where there are cut marks\r
-    MarkList* markList = myRec->getMarkList();\r
-    MarkList::iterator i;\r
-    Mark* loopMark = NULL;\r
-\r
-    for(i = markList->begin(); i != markList->end(); i++)\r
-    {\r
-      loopMark = *i;\r
-      if (loopMark->pos)\r
-      {\r
-        logger->log("VVideoRec", Log::DEBUG, "Drawing mark at frame %i", loopMark->pos);\r
-        posPix = 302 * loopMark->pos / lengthFrames;\r
-        rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 - 2, 3, 28, DrawStyle::DANGER);\r
-      }\r
-    }\r
-  }\r
-  else\r
-  {\r
-    // Draw blips where start and end margins probably are\r
-\r
-         posPix =(int) (302. * myRec->recInfo->fps * ((double)startMargin) /((double) lengthFrames));\r
-\r
-    rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 - 2, 2, 2, DrawStyle::LIGHTTEXT);\r
-    rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 + 24, 2, 2, DrawStyle::LIGHTTEXT);\r
-\r
-    posPix = (int)(302. * ((double)lengthFrames - ((double)endMargin) * myRec->recInfo->fps) / ((double)lengthFrames));\r
-\r
-    rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 - 2, 2, 2, DrawStyle::LIGHTTEXT);\r
-    rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 + 24, 2, 2, DrawStyle::LIGHTTEXT);\r
-  }\r
-}\r
-\r
-void VVideoRec::removeBar()\r
-{\r
-  if (!barShowing) return;\r
-  timers->cancelTimer(this, 2);\r
-  barShowing = false;\r
-  barGenHold = false;\r
-  barScanHold = false;\r
-  barVasHold = false;\r
-  rectangle(barRegion, transparent);\r
-  boxstack->update(this, &barRegion);\r
-}\r
-\r
-void VVideoRec::doSummary()\r
-{\r
-  vsummary = new VInfo();\r
-  vsummary->setTitleText(myRec->getProgName());\r
-  vsummary->setBorderOn(1);\r
-  vsummary->setExitable();\r
-  if (myRec->recInfo->summary) vsummary->setMainText(myRec->recInfo->summary);\r
-  else vsummary->setMainText(tr("Summary unavailable"));\r
-  if (Video::getInstance()->getFormat() == Video::PAL)\r
-  {\r
-    vsummary->setPosition(120, 130);\r
-  }\r
-  else\r
-  {\r
-    vsummary->setPosition(110, 90);\r
-  }\r
-  vsummary->setSize(510, 270);\r
-  add(vsummary);\r
-  vsummary->draw();\r
-\r
-  BoxStack::getInstance()->update(this);\r
-}\r
-\r
-void VVideoRec::removeSummary()\r
-{\r
-  if (vsummary)\r
-  {\r
-    remove(vsummary);\r
-    delete vsummary;\r
-    vsummary = NULL;\r
-    draw();\r
-    BoxStack::getInstance()->update(this);\r
-  }\r
-}\r
-\r
-void VVideoRec::drawOSDBitmap(UINT posX, UINT posY, const Bitmap& bm, const DisplayRegion& region)\r
-{\r
-  drawBitmap(posX, posY, bm, region);\r
-  Region r;\r
-  r.x = posX; r.y = posY; r.w = bm.getWidth(); r.h = bm.getHeight();\r
-  boxstack->update(this, &r);\r
-}\r
-\r
-void VVideoRec::clearOSD()\r
-{\r
-  rectangle(area, transparent);\r
-  boxstack->update(this, &area);\r
-}\r
-\r
-void VVideoRec::clearOSDArea(UINT posX, UINT posY, UINT width, UINT height, const DisplayRegion& region)\r
-{\r
-  Region r;\r
-  r.x = posX+region.windowx; r.y = posY+region.windowy; r.w = width; r.h = height;\r
-  //now convert to our display\r
-  float scalex=720.f/((float) (region.framewidth+1));\r
-  float scaley=576.f/((float) (region.frameheight+1));\r
-  r.x=floor(scalex*((float)r.x));\r
-  r.y=floor(scaley*((float)r.y));\r
-  r.w=ceil(scalex*((float)r.w));\r
-  r.h=ceil(scaley*((float)r.h));\r
-\r
-  rectangle(r, transparent);\r
-  boxstack->update(this, &r);\r
-}\r
+    case Remote::REVERSE:
+    {
+      player->fastBackward();
+      doBar(0);
+      return 2;
+    }
+    case Remote::RED:
+    {
+      if (vsummary) removeSummary();
+      else doSummary();
+      return 2;
+    }
+    case Remote::GREEN:
+    {
+      doAudioSelector();
+      return 2;
+    }
+    case Remote::YELLOW:
+    {
+      if (myRec->hasMarks())
+      {
+        // skip to previous mark
+        Log* logger = Log::getInstance();
+        int currentFrame = (player->getCurrentFrameNum()); // get current Frame
+        currentFrame -= 5. * myRec->recInfo->fps; // subtrack 5 seconds, else you cannot skip more than once back ..
+
+        int prevMark = myRec->getPrevMark(currentFrame); // find previous Frame
+        if (prevMark)
+        {
+          logger->log("VVideoRec", Log::NOTICE, "jump back from pos %i to mark at %i",currentFrame,prevMark);
+          player->jumpToMark(prevMark);
+        }
+        doBar(4);
+      }
+      else
+      {
+        doBar(2);
+        player->skipBackward(10);
+      }
+      return 2;
+    }
+    case Remote::BLUE:
+    {
+      if (myRec->hasMarks())
+      {
+        // skip to next mark
+        Log* logger = Log::getInstance();
+        int currentFrame = (player->getCurrentFrameNum());
+
+        int nextMark = myRec->getNextMark(currentFrame);
+
+        if (nextMark)
+        {
+          logger->log("VVideoRec", Log::NOTICE, "jump forward from pos %i to mark at %i",currentFrame,nextMark);
+          player->jumpToMark(nextMark);
+        }
+        doBar(3);
+      }
+      else
+      {
+        doBar(1);
+        player->skipForward(10);
+      }
+      return 2;
+    }
+    case Remote::STAR:
+    {
+      doBar(2);
+      player->skipBackward(10);
+      return 2;
+    }
+    case Remote::HASH:
+    {
+      doBar(1);
+      player->skipForward(10);
+      return 2;
+    }
+    case Remote::FULL:
+    case Remote::TV:
+    {
+      toggleChopSides();
+      return 2;
+    }
+
+    case Remote::OK:
+    {
+      if (vsummary)
+      {
+        removeSummary();
+        return 2;
+      }
+      
+      if (barShowing) removeBar();
+      else doBar(0);
+      return 2;
+    }
+
+    case Remote::ZERO:  player->jumpToPercent(0);  doBar(0);  return 2;
+    case Remote::ONE:   player->jumpToPercent(10); doBar(0);  return 2;
+    case Remote::TWO:   player->jumpToPercent(20); doBar(0);  return 2;
+    case Remote::THREE: player->jumpToPercent(30); doBar(0);  return 2;
+    case Remote::FOUR:  player->jumpToPercent(40); doBar(0);  return 2;
+    case Remote::FIVE:  player->jumpToPercent(50); doBar(0);  return 2;
+    case Remote::SIX:   player->jumpToPercent(60); doBar(0);  return 2;
+    case Remote::SEVEN: player->jumpToPercent(70); doBar(0);  return 2;
+    case Remote::EIGHT: player->jumpToPercent(80); doBar(0);  return 2;
+    case Remote::NINE:  player->jumpToPercent(90); doBar(0);  return 2;
+
+    case Remote::RECORD: player->toggleSubtitles(); return 2;
+#ifdef DEV
+//    case Remote::RED:
+//    {
+      //Don't use RED for anything. It will eventually be recording summary
+
+      //player->test1();
+
+
+      /*
+      // for testing EPG in NTSC with a NTSC test video
+      Video::getInstance()->setMode(Video::QUARTER);
+      Video::getInstance()->setPosition(170, 5);
+      VEpg* vepg = new VEpg(NULL, 0);
+      vepg->draw();
+      BoxStack::getInstance()->add(vepg);
+      BoxStack::getInstance()->update(vepg);
+      */
+
+//      return 2;
+//    }
+
+#endif
+
+  }
+
+  return 1;
+}
+
+void VVideoRec::doTeletext()
+{
+  
+  bool exists=true;
+
+  
+  // Draw the teletxt
+  VTeletextView *vtxv=player->getTeletextDecoder()->getTeletxtView();
+  if (vtxv==NULL) {
+       vtxv= new VTeletextView((player)->getTeletextDecoder(),this);
+      (player)->getTeletextDecoder()->registerTeletextView(vtxv);
+      exists=false;
+  }
+  vtxv->setSubtitleMode(true);
+  vtxv->draw();
+  draw();
+  
+  if (!exists) {
+      BoxStack::getInstance()->add(vtxv);
+  }
+  BoxStack::getInstance()->update(this);
+  BoxStack::getInstance()->update(vtxv); 
+}
+
+void VVideoRec::processMessage(Message* m)
+{
+  Log::getInstance()->log("VVideoRec", Log::DEBUG, "Message received");
+
+  if (m->message == Message::MOUSE_LBDOWN)
+  {
+    UINT x = (m->parameter>>16) - getScreenX();
+    UINT y = (m->parameter&0xFFFF) - getScreenY();
+
+    if (!barShowing)
+    {
+      BoxStack::getInstance()->handleCommand(Remote::OK); //simulate rok press
+    }
+    else if (barRegion.x<=x && barRegion.y<=y && (barRegion.x+barRegion.w)>=x && (barRegion.y+barRegion.h)>=y)
+    {
+      int progBarXbase = barRegion.x + 300;
+      if (myRec->hasMarks())
+      {
+        MarkList* markList = myRec->getMarkList();
+        MarkList::iterator i;
+        Mark* loopMark = NULL;
+        int posPix;
+        ULONG lengthFrames;
+        if (myRec->recInfo->timerEnd > time(NULL))
+        {
+          // chasing playback
+          // Work out an approximate length in frames (good to 1s...)
+                       lengthFrames = (ULONG)((double)(myRec->recInfo->timerEnd - myRec->recInfo->timerStart) * myRec->recInfo->fps);
+        }
+        else
+        {
+          lengthFrames = player->getLengthFrames();
+        }
+        for(i = markList->begin(); i != markList->end(); i++)
+        {
+          loopMark = *i;
+          if (loopMark->pos)
+          {
+            posPix = 302 * loopMark->pos / lengthFrames;
+            rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 - 2, 3, 28, DrawStyle::DANGER);
+            if (x>=barRegion.x + progBarXbase + 2 + posPix
+                && x<=barRegion.x + progBarXbase + 2 + posPix+3
+                && y>=barRegion.y + 12 - 2
+                && y<=barRegion.y + 12 - 2+28)
+            {
+              player->jumpToMark(loopMark->pos);
+              doBar(3);
+              return;
+            }
+          }
+        }
+      }
+
+      if (x>=barRegion.x + progBarXbase + 24
+          && x<=barRegion.x + progBarXbase + 4 + 302
+          && y>=barRegion.y + 12 - 2
+          && y<=barRegion.y + 12 - 2+28)
+      {
+        int cx=x-(barRegion.x + progBarXbase + 4);
+        double percent=((double)cx)/302.*100.;
+        player->jumpToPercent(percent);
+        doBar(3);
+        return;
+        //  int progressWidth = 302 * currentFrameNum / lengthFrames;
+        //  rectangle(barRegion.x + progBarXbase + 4, barRegion.y + 16, progressWidth, 16, DrawStyle::SELECTHIGHLIGHT);
+      }
+    }
+    else
+    {
+      BoxStack::getInstance()->handleCommand(Remote::OK); //simulate rok press
+    }
+  }
+  else if (m->from == player)
+  {
+    if (m->message != Message::PLAYER_EVENT) return;
+    switch(m->parameter)
+    {
+      case Player::CONNECTION_LOST: // connection lost detected
+      {
+        // I can't handle this, send it to command
+        Message* m2 = new Message();
+        m2->to = Command::getInstance();
+        m2->message = Message::CONNECTION_LOST;
+        Command::getInstance()->postMessageNoLock(m2);
+        break;
+      }
+      case Player::STOP_PLAYBACK:
+      {
+        // FIXME Obselete ish - improve this
+        Message* m2 = new Message(); // Must be done after this thread finishes, and must break into master mutex
+        m2->to = Command::getInstance();
+        m2->message = Message::STOP_PLAYBACK;
+        Command::getInstance()->postMessageNoLock(m2);
+        break;
+      }
+      case Player::ASPECT43:
+      {
+#ifdef PAL_WSS
+        if (dowss)
+        {
+          Log::getInstance()->log("VVideoRec", Log::DEBUG, "Received do WSS 43");
+          wss.setWide(false);
+          wss.draw();
+          boxstack->update(this, &wssRegion);
+        }
+#endif
+        break;
+      }
+      case Player::ASPECT169:
+      {
+#ifdef PAL_WSS
+        if (dowss)
+        {
+          Log::getInstance()->log("VVideoRec", Log::DEBUG, "Received do WSS 169");
+          wss.setWide(true);
+          wss.draw();
+          boxstack->update(this, &wssRegion);
+        }
+#endif
+        break;
+      }
+    }
+  }
+  else if (m->message == Message::AUDIO_CHANGE_CHANNEL)
+  {
+    Log::getInstance()->log("VVideoRec", Log::DEBUG, "Received change audio channel to %i", m->parameter);
+    player->setAudioChannel(m->parameter&0xFFFF,(m->parameter&0xFF0000)>> 16,(m->parameter&0xFF000000)>> 24 );
+  }
+  else if (m->message == Message::SUBTITLE_CHANGE_CHANNEL)
+  {
+      Log::getInstance()->log("VVideoRec", Log::DEBUG, "Received change subtitle channel to %i", m->parameter);
+      int type=((m->parameter & 0xFF0000)>>16);
+      switch (type) {
+      case 0x10: { //dvbsubtitle
+          player->setSubtitleChannel((m->parameter & 0xFFFF));
+          player->turnSubtitlesOn(true);
+          VTeletextView *vtxt=((Player*)player)->getTeletextDecoder()->getTeletxtView();
+          if (vtxt && vtxt->isInSubtitleMode()) {
+              BoxStack::getInstance()->remove(vtxt);
+          }
+                 } break;
+      case 0xFF: { //nosubtitles
+          
+           player->turnSubtitlesOn(false);
+           VTeletextView *vtxt=((Player*)player)->getTeletextDecoder()->getTeletxtView();
+           if (vtxt && vtxt->isInSubtitleMode()) {
+              BoxStack::getInstance()->remove(vtxt);
+           }  
+          
+                 } break;
+      case 0x11: { //videotext
+          player->turnSubtitlesOn(false);
+          doTeletext();
+          ((Player*)player)->getTeletextDecoder()->setPage((m->parameter & 0xFFFF));
+                 } break;
+      };
+      if (vas) {
+        BoxStack::getInstance()->update(vas);
+      }
+      BoxStack::getInstance()->update(this);
+
+      
+  } 
+  else if (m->message == Message::CHILD_CLOSE)
+  {
+    if (m->from == vas)
+    {
+      vas = NULL;
+      barVasHold = false;
+      if (!barGenHold && !barScanHold && !barVasHold) removeBar();
+    }
+  }
+}
+
+void VVideoRec::stopPlay()
+{
+  Log::getInstance()->log("VVideoRec", Log::DEBUG, "Pre stopPlay");
+
+  removeBar();
+  Log::getInstance()->log("VVideoRec", Log::DEBUG, "1");
+  player->stop();
+  Log::getInstance()->log("VVideoRec", Log::DEBUG, "2");
+  vdr->stopStreaming();
+  Log::getInstance()->log("VVideoRec", Log::DEBUG, "3");
+  delete player;
+
+  playing = false;
+
+  if (!vdr->isConnected()) { Command::getInstance()->connectionLost(); return; }
+  Log::getInstance()->log("VVideoRec", Log::DEBUG, "Post stopPlay");
+}
+
+void VVideoRec::toggleChopSides()
+{
+  if (video->getTVsize() == Video::ASPECT16X9) return; // Means nothing for 16:9 TVs
+
+  if (videoMode == Video::NORMAL)
+  {
+    videoMode = Video::LETTERBOX;
+    video->setMode(Video::LETTERBOX);
+  }
+  else
+  {
+    videoMode = Video::NORMAL;
+    video->setMode(Video::NORMAL);
+  }
+}
+
+void VVideoRec::doAudioSelector()
+{
+    int subtitleChannel=player->getCurrentSubtitleChannel();
+    int subtitleType=0x10;
+    if (!(player)->isSubtitlesOn()) {
+        if ((player)->getTeletextDecoder()->getTeletxtView() &&
+            (player)->getTeletextDecoder()->getTeletxtView()->isInSubtitleMode() 
+            ) {
+                subtitleChannel=(player)->getTeletextDecoder()->getPage();
+                subtitleType=0x11;
+      
+           } else {
+                subtitleType=0xFF; //turnedOff
+                subtitleChannel=0;
+          }
+    }
+    if (player->isPesRecording()) {
+        bool* availableMpegAudioChannels = player->getDemuxerMpegAudioChannels();
+        bool* availableAc3AudioChannels = NULL;
+        bool* availableSubtitleChannels = player->getDemuxerSubtitleChannels();
+        int *availableTTxtpages = player->getTeletxtSubtitlePages();
+        int currentAudioChannel = player->getCurrentAudioChannel();
+        if (Audio::getInstance()->supportsAc3())
+        {
+            availableAc3AudioChannels = player->getDemuxerAc3AudioChannels();
+        }
+        
+        vas = new VAudioSelector(this, availableMpegAudioChannels, availableAc3AudioChannels, currentAudioChannel,availableSubtitleChannels, availableTTxtpages,
+            subtitleChannel, subtitleType, myRec->recInfo);
+    } else {
+        // Draw the selector
+        Channel *temp_channel=player->getDemuxerChannel();
+       // RecInfo *cur_info= myRec->recInfo;
+     /*   unsigned char numchan_recinfo = cur_info->numComponents;
+        unsigned char numchan_subtitles_siz = temp_channel.numSPids;
+        ULONG mp_audcounter = 0;
+        ULONG ac3_counter = 0;
+        int dvb_subcounter = 1;*/
+        int i;
+        
+        /*unsigned char type;
+        char* lang;
+        char* description;
+        for (i = 0; i < numchan_recinfo; i++)
+        {   
+            apid* ac = NULL;
+            type = cur_info->types[i];
+            lang = cur_info->languages[i];
+            description = cur_info->descriptions[i];
+            
+
+            if (cur_info->streams[i] == 2) {
+                switch (type)
+                {
+                case 1: //mpaudio mono
+                case 3: //mpaudio stereo
+                    if (mp_audcounter < temp_channel.numAPids) ac = &temp_channel.apids[mp_audcounter];
+                    
+                    mp_audcounter++;
+                    break;
+                case 5: //ac3
+                    if (ac3_counter < temp_channel.numDPids) ac = &temp_channel.dpids[ac3_counter];
+                    ac3_counter++;
+                    break;
+                }
+            } else if (cur_info->streams[i] == 3){
+                if (dvb_subcounter < numchan_subtitles_siz) ac = &temp_channel.spids[dvb_subcounter];
+            } else continue; //neither audio nor subtitle
+            if (ac)
+            {
+                if (description && (strlen(description) > 0))
+                {
+                    ac->name = new char[strlen(description) + 1];
+                    strcpy(ac->name, description);
+                    
+                } else if (lang && strlen(lang) > 0)
+                {
+                    ac->name = new char[strlen(lang) + 1];
+                    strcpy(ac->name, lang);
+                    
+                }
+            }
+        }*/
+        for (i=0;i<temp_channel->numAPids;i++) {
+            apid *ac=&temp_channel->apids[i];
+            if (ac->desc[0]==0) {
+                strncpy(ac->desc, tr("unknown"),9);
+            }
+        }
+        for (i=0;i<temp_channel->numDPids;i++) {
+            apid *ac=&temp_channel->dpids[i];
+            if (ac->desc[0]==0) {
+                strncpy(ac->desc, tr("unknown"),9);
+            }
+        }
+        for (i=0;i<temp_channel->numSPids;i++) {
+            apid *ac=&temp_channel->spids[i];
+            if (ac->desc[0]==0) {
+                strncpy(ac->desc, tr("unknown"),9);
+            }
+        }
+
+        vas = new VAudioSelector(this,temp_channel , (player)->getCurrentAudioChannel(),
+            subtitleType,subtitleChannel,player->getTeletxtSubtitlePages());  
+      /*   for (i=0;i<temp_channel.numAPids;i++) {
+            apid *ac=&temp_channel.apids[i];
+            delete[] ac->name;
+            ac->name=NULL;
+        }
+        for (i=0;i<temp_channel.numDPids;i++) {
+            apid *ac=&temp_channel.dpids[i];
+            delete[] ac->name;
+            ac->name=NULL;
+        }
+        for (i=0;i<temp_channel.numSPids;i++) {
+            apid *ac=&temp_channel.spids[i];
+            delete[] ac->name;
+            ac->name=NULL;
+        }*/
+    }
+
+
+  vas->setBackgroundColour(barBlue);
+  vas->setPosition(0, barRegion.y - 120);
+
+// pal 62, ntsc 57
+
+  barVasHold = true;
+  doBar(0);
+
+  vas->draw();
+  boxstack->add(vas);
+  boxstack->update(vas);
+}
+
+void VVideoRec::doBar(int action)
+{
+  barShowing = true;
+
+  rectangle(barRegion, barBlue);
+
+  /* Work out what to display - choices:
+
+  Playing  >
+  Paused   ||
+  FFwd     >>
+  FBwd     <<
+
+  Specials, informed by parameter
+
+  Skip forward 10s    >|
+  Skip backward 10s   |<
+  Skip forward 1m     >>|
+  Skip backward 1m    |<<
+
+  */
+
+  WSymbol w;
+  TEMPADD(&w);
+  w.nextSymbol = 0;
+  w.setPosition(barRegion.x + 66, barRegion.y + 16);
+
+  UCHAR playerState = 0;
+
+  if (action)
+  {
+    if (action == 1)       w.nextSymbol = WSymbol::SKIPFORWARD;
+    else if (action == 2)  w.nextSymbol = WSymbol::SKIPBACK;
+    else if (action == 3)  w.nextSymbol = WSymbol::SKIPFORWARD2;
+    else if (action == 4)  w.nextSymbol = WSymbol::SKIPBACK2;
+  }
+  else
+  {
+    playerState = player->getState();
+    if (playerState == Player::S_PAUSE_P)      w.nextSymbol = WSymbol::PAUSE;
+    else if (playerState == Player::S_PAUSE_I) w.nextSymbol = WSymbol::PAUSE;
+    else if (playerState == Player::S_FFWD)    w.nextSymbol = WSymbol::FFWD;
+    else if (playerState == Player::S_FBWD)    w.nextSymbol = WSymbol::FBWD;
+    else                                       w.nextSymbol = WSymbol::PLAY;
+  }
+
+  w.draw();
+
+  if ((playerState == Player::S_FFWD) || (playerState == Player::S_FBWD))
+  {
+    // draw blips to show how fast the scan is
+    UCHAR scanrate = player->getIScanRate();
+    if (scanrate >= 2)
+    {
+      char text[5];
+      SNPRINTF(text, 5, "%ux", scanrate);
+      drawText(text, barRegion.x + 102, barRegion.y + 12, DrawStyle::LIGHTTEXT);
+    }
+  }
+
+  drawBarClocks();
+
+  boxstack->update(this, &barRegion);
+
+  timers->cancelTimer(this, 1);
+
+
+  if ((playerState == Player::S_FFWD) || (playerState == Player::S_FBWD)) barScanHold = true;
+  else barScanHold = false;
+
+  if (!barGenHold && !barScanHold && !barVasHold) timers->setTimerD(this, 1, 4);
+
+  timers->setTimerD(this, 2, 0, 200000000);
+}
+
+void VVideoRec::timercall(int clientReference)
+{
+  switch(clientReference)
+  {
+    case 1:
+    {
+      // Remove bar
+      removeBar();
+      break;
+    }
+    case 2:
+    {
+      // Update clock
+      if (!barShowing) break;
+      drawBarClocks();
+      boxstack->update(this, &barRegion);
+      
+      timers->setTimerD(this, 2, 0, 200000000);
+      break;
+    }
+  }
+}
+
+hmsf VVideoRec::framesToHMSF(ULONG frames)
+{
+  hmsf ret;
+  /* from vdr */
+  double Seconds;
+  double fps=myRec->recInfo->fps;
+  ret.frames= int(modf((frames + 0.5) / fps, &Seconds) * fps + 1);
+  int s = int(Seconds);
+  ret.seconds=s % 60;
+  ret.minutes = s / 60 % 60;
+  ret.hours = s / 3600;
+
+
+  return ret;
+}
+
+void VVideoRec::drawBarClocks()
+{
+  if (barScanHold)
+  {
+    UCHAR playerState = player->getState();
+    // sticky bar is set if we are in ffwd/fbwd mode
+    // if player has gone to S_PLAY then kill stickyBar, and run doBar(0) which
+    // will repaint all the bar (it will call this function again, but
+    // this section won't run because stickyBarF will then == false)
+
+    if ((playerState != Player::S_FFWD) && (playerState != Player::S_FBWD))
+    {
+      barScanHold = false;
+      doBar(0);
+      return; // doBar will call this function and do the rest
+    }
+  }
+
+  Log* logger = Log::getInstance();
+  logger->log("VVideoRec", Log::DEBUG, "Draw bar clocks");
+
+  // Draw RTC
+  // Blank the area first
+  rectangle(barRegion.x + 624, barRegion.y + 12, 60, 30, barBlue);
+  char timeString[20];
+  time_t t;
+  time(&t);
+  struct tm* tms = localtime(&t);
+  strftime(timeString, 19, "%H:%M", tms);
+  drawText(timeString, barRegion.x + 624, barRegion.y + 12, DrawStyle::LIGHTTEXT);
+
+  // Draw clocks
+
+  rectangle(clocksRegion, barBlue);
+
+  ULONG currentFrameNum = player->getCurrentFrameNum();
+  ULONG lengthFrames;
+  if (myRec->recInfo->timerEnd > time(NULL))
+  {
+    // chasing playback
+    // Work out an approximate length in frames (good to 1s...)
+    lengthFrames =(ULONG) ((double)(myRec->recInfo->timerEnd - myRec->recInfo->timerStart) * myRec->recInfo->fps);
+  }
+  else
+  {
+    lengthFrames = player->getLengthFrames();
+  }
+
+  hmsf currentFrameHMSF = framesToHMSF(currentFrameNum);
+  hmsf lengthHMSF = framesToHMSF(lengthFrames);
+
+  char buffer[100];
+  if (currentFrameNum >= lengthFrames)
+  {
+    strcpy(buffer, "-:--:-- / -:--:--");
+  }
+  else
+  {
+    SNPRINTF(buffer, 99, "%01i:%02i:%02i / %01i:%02i:%02i", currentFrameHMSF.hours, currentFrameHMSF.minutes, currentFrameHMSF.seconds, lengthHMSF.hours, lengthHMSF.minutes, lengthHMSF.seconds);
+    logger->log("VVideoRec", Log::DEBUG, buffer);
+  }
+
+  drawText(buffer, clocksRegion.x, clocksRegion.y, DrawStyle::LIGHTTEXT);
+
+
+
+
+
+
+
+  // Draw progress bar
+  int progBarXbase = barRegion.x + 300;
+
+  rectangle(barRegion.x + progBarXbase, barRegion.y + 12, 310, 24, DrawStyle::LIGHTTEXT);
+  rectangle(barRegion.x + progBarXbase + 2, barRegion.y + 14, 306, 20, barBlue);
+
+  if (currentFrameNum > lengthFrames) return;
+  if (lengthFrames == 0) return;
+
+  // Draw yellow portion
+  int progressWidth = 302 * currentFrameNum / lengthFrames;
+  rectangle(barRegion.x + progBarXbase + 4, barRegion.y + 16, progressWidth, 16, DrawStyle::SELECTHIGHLIGHT);
+
+  if (myRec->recInfo->timerEnd > time(NULL)) // if chasing
+  {
+    int nrWidth = (int)(302 * ((double)(lengthFrames - player->getLengthFrames()) / lengthFrames));
+
+    Log::getInstance()->log("GVASDF", Log::DEBUG, "Length Frames: %lu", lengthFrames);
+    Log::getInstance()->log("GVASDF", Log::DEBUG, "Player lf: %lu", player->getLengthFrames());
+    Log::getInstance()->log("GVASDF", Log::DEBUG, "NR WDITH: %i", nrWidth);
+    rectangle(barRegion.x + progBarXbase + 4 + 302 - nrWidth, barRegion.y + 16, nrWidth, 16, DrawStyle::RED);
+  }
+
+  int posPix;
+  // Now calc position for blips
+
+  if (myRec->hasMarks())
+  {
+    // Draw blips where there are cut marks
+    MarkList* markList = myRec->getMarkList();
+    MarkList::iterator i;
+    Mark* loopMark = NULL;
+
+    for(i = markList->begin(); i != markList->end(); i++)
+    {
+      loopMark = *i;
+      if (loopMark->pos)
+      {
+        logger->log("VVideoRec", Log::DEBUG, "Drawing mark at frame %i", loopMark->pos);
+        posPix = 302 * loopMark->pos / lengthFrames;
+        rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 - 2, 3, 28, DrawStyle::DANGER);
+      }
+    }
+  }
+  else
+  {
+    // Draw blips where start and end margins probably are
+
+         posPix =(int) (302. * myRec->recInfo->fps * ((double)startMargin) /((double) lengthFrames));
+
+    rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 - 2, 2, 2, DrawStyle::LIGHTTEXT);
+    rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 + 24, 2, 2, DrawStyle::LIGHTTEXT);
+
+    posPix = (int)(302. * ((double)lengthFrames - ((double)endMargin) * myRec->recInfo->fps) / ((double)lengthFrames));
+
+    rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 - 2, 2, 2, DrawStyle::LIGHTTEXT);
+    rectangle(barRegion.x + progBarXbase + 2 + posPix, barRegion.y + 12 + 24, 2, 2, DrawStyle::LIGHTTEXT);
+  }
+}
+
+void VVideoRec::removeBar()
+{
+  if (!barShowing) return;
+  timers->cancelTimer(this, 2);
+  barShowing = false;
+  barGenHold = false;
+  barScanHold = false;
+  barVasHold = false;
+  rectangle(barRegion, transparent);
+  boxstack->update(this, &barRegion);
+}
+
+void VVideoRec::doSummary()
+{
+  vsummary = new VInfo();
+  vsummary->setTitleText(myRec->getProgName());
+  vsummary->setBorderOn(1);
+  vsummary->setExitable();
+  if (myRec->recInfo->summary) vsummary->setMainText(myRec->recInfo->summary);
+  else vsummary->setMainText(tr("Summary unavailable"));
+  if (Video::getInstance()->getFormat() == Video::PAL)
+  {
+    vsummary->setPosition(120, 130);
+  }
+  else
+  {
+    vsummary->setPosition(110, 90);
+  }
+  vsummary->setSize(510, 270);
+  add(vsummary);
+  vsummary->draw();
+
+  BoxStack::getInstance()->update(this);
+}
+
+void VVideoRec::removeSummary()
+{
+  if (vsummary)
+  {
+    remove(vsummary);
+    delete vsummary;
+    vsummary = NULL;
+    draw();
+    BoxStack::getInstance()->update(this);
+  }
+}
+
+void VVideoRec::drawOSDBitmap(UINT posX, UINT posY, const Bitmap& bm, const DisplayRegion& region)
+{
+  drawBitmap(posX, posY, bm, region);
+  Region r;
+  r.x = posX; r.y = posY; r.w = bm.getWidth(); r.h = bm.getHeight();
+  boxstack->update(this, &r);
+}
+
+void VVideoRec::clearOSD()
+{
+  rectangle(area, transparent);
+  boxstack->update(this, &area);
+}
+
+void VVideoRec::clearOSDArea(UINT posX, UINT posY, UINT width, UINT height, const DisplayRegion& region)
+{
+  Region r;
+  r.x = posX+region.windowx; r.y = posY+region.windowy; r.w = width; r.h = height;
+  //now convert to our display
+  float scalex=720.f/((float) (region.framewidth+1));
+  float scaley=576.f/((float) (region.frameheight+1));
+  r.x=floor(scalex*((float)r.x));
+  r.y=floor(scaley*((float)r.y));
+  r.w=ceil(scalex*((float)r.w));
+  r.h=ceil(scaley*((float)r.h));
+
+  rectangle(r, transparent);
+  boxstack->update(this, &r);
+}
index d7b032c602f6cfe7eef4c926daa2f0cdcfb55707..ee6e044faa4fb85a8036a27e8fbdb4b1172cdad9 100644 (file)
-/*\r
-    Copyright 2004-2005 Chris Tallon\r
-\r
-    This file is part of VOMP.\r
-\r
-    VOMP is free software; you can redistribute it and/or modify\r
-    it under the terms of the GNU General Public License as published by\r
-    the Free Software Foundation; either version 2 of the License, or\r
-    (at your option) any later version.\r
-\r
-    VOMP is distributed in the hope that it will be useful,\r
-    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-    GNU General Public License for more details.\r
-\r
-    You should have received a copy of the GNU General Public License\r
-    along with VOMP; if not, write to the Free Software\r
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
-*/\r
-\r
-#include "vwelcome.h"\r
-\r
-#include "remote.h"\r
-#include "vdr.h"\r
-#include "vchannellist.h"\r
-#include "vrecordinglist.h"\r
-#include "vtimerlist.h"\r
-#include "command.h"\r
-#include "message.h"\r
-#include "colour.h"\r
-#include "video.h"\r
-#include "i18n.h"\r
-#include "timers.h"\r
-#include "vscreensaver.h"\r
-#include "vmedialist.h"\r
-#include "boxstack.h"\r
-#include "vopts.h"\r
-\r
-#include "log.h"\r
-\r
-VWelcome::VWelcome()\r
-{\r
-  boxstack = BoxStack::getInstance();\r
-\r
-  clockRegion.x = 400;\r
-  clockRegion.y = 0;\r
-  clockRegion.w = 60;\r
-  clockRegion.h = 30;\r
-\r
-  setSize(460, 220);\r
-  createBuffer();\r
-  if (Video::getInstance()->getFormat() == Video::PAL)\r
-  {\r
-    setPosition(140, 170);\r
-  }\r
-  else\r
-  {\r
-    setPosition(130, 140);\r
-  }\r
-\r
-  setTitleBarOn(1);\r
-  setTitleBarColour(DrawStyle::TITLEBARBACKGROUND);\r
-\r
-  sl.setPosition(20, 40);\r
-  sl.setSize(200, 160);\r
-  add(&sl);\r
-\r
-  setTitleText(tr("Welcome"));\r
-  sl.addOption(tr("1. Live TV"), 1, 1);\r
-  sl.addOption(tr("2. Radio"), 2, 0);\r
-  sl.addOption(tr("3. Recordings"), 3, 0);\r
-  sl.addOption(tr("4. Timers"), 4, 0);\r
-#ifdef VOMP_PLATTFORM_MVP\r
-  sl.addOption(tr("5. MediaPlayer"), 5, 0);\r
-#endif\r
-\r
-  sl.addOption(tr("6. Options"), 6, 0);\r
-#ifndef VOMP_HAS_EXIT\r
-  sl.addOption(tr("7. Reboot"), 7, 0);\r
-#else\r
-    sl.addOption(tr("7. Exit"), 7, 0);\r
-#endif\r
-\r
-  jpeg.setPosition(240, 60);\r
-#ifndef _MIPS_ARCH  \r
-  jpeg.init("/vdr.jpg");\r
-#else\r
-  jpeg.init("vdr.jpg");\r
-#endif\r
-  add(&jpeg);\r
-}\r
-\r
-void VWelcome::preDelete()\r
-{\r
-  Timers::getInstance()->cancelTimer(this, 1);\r
-}\r
-\r
-VWelcome::~VWelcome()\r
-{\r
-}\r
-\r
-void VWelcome::draw()\r
-{\r
-  TBBoxx::draw();\r
-  drawClock();\r
-}\r
-\r
-void VWelcome::drawClock()\r
-{\r
-  // Blank the area first\r
-  rectangle(area.w - 60, 0, 60, 30, titleBarColour);\r
-\r
-  char timeString[20];\r
-  time_t t;\r
-  time(&t);\r
-  struct tm* tms = localtime(&t);\r
-  strftime(timeString, 19, "%H:%M", tms);\r
-  drawTextRJ(timeString, 450, 5, DrawStyle::LIGHTTEXT);\r
-\r
-  time_t dt = 60 - (t % 60);  // seconds to the next minute\r
-  if (dt == 0) dt = 60; // advance a whole minute if necessary\r
-  dt += t;  // get a time_t value for it rather than using duration\r
-  // (so it will occur at the actual second and not second and a half)\r
-\r
-  Timers::getInstance()->setTimerT(this, 1, dt);\r
-}\r
-\r
-void VWelcome::timercall(int clientReference)\r
-{\r
-  drawClock();\r
-  boxstack->update(this, &clockRegion);\r
-}\r
-\r
-int VWelcome::handleCommand(int command)\r
-{\r
-  switch(command)\r
-  {\r
-    case Remote::DF_UP:\r
-    case Remote::UP:\r
-    {\r
-      sl.up();\r
-      sl.draw();\r
-      boxstack->update(this);\r
-      return 2;\r
-    }\r
-    case Remote::DF_DOWN:\r
-    case Remote::DOWN:\r
-    {\r
-      sl.down();\r
-      sl.draw();\r
-      boxstack->update(this);\r
-      return 2;\r
-    }\r
-    case Remote::ONE:\r
-    {\r
-      doChannelsList();\r
-      return 2;\r
-    }\r
-    case Remote::TWO:\r
-    {\r
-      doRadioList();\r
-      return 2;\r
-    }\r
-    case Remote::THREE:\r
-    {\r
-      doRecordingsList();\r
-      return 2;\r
-    }\r
-    case Remote::FOUR:\r
-    {\r
-      doTimersList();\r
-      return 2;\r
-    }\r
-    case Remote::FIVE:\r
-    {\r
-#ifdef VOMP_PLATTFORM_MVP\r
-      doMediaList();\r
-#endif\r
-      return 2;\r
-    }\r
-    case Remote::SIX:\r
-    {\r
-      doOptions();\r
-      return 2;\r
-    }\r
-    case Remote::SEVEN:\r
-    {\r
-      Command::getInstance()->doReboot();\r
-      return 2;\r
-    }\r
-    case Remote::OK:\r
-    {\r
-      ULONG option = sl.getCurrentOptionData();\r
-      if (option == 1)\r
-      {\r
-        doChannelsList();\r
-        return 2;\r
-      }\r
-      else if (option == 2)\r
-      {\r
-        doRadioList();\r
-        return 2;\r
-      }\r
-      else if (option == 3)\r
-      {\r
-        doRecordingsList();\r
-        return 2;\r
-      }\r
-      else if (option == 4)\r
-      {\r
-        doTimersList();\r
-        return 2;\r
-      }\r
-      else if (option == 5)\r
-      {\r
-        doMediaList();\r
-        return 2;\r
-      }\r
-      else if (option == 6)\r
-      {\r
-        doOptions();\r
-        return 2;\r
-      }\r
-      else if (option == 7)\r
-      {\r
-        Command::getInstance()->doReboot();\r
-        return 2;\r
-      }\r
-      return 2; // never gets here\r
-    }\r
-//#ifdef DEV\r
-    case Remote::NINE:\r
-    {\r
-      VScreensaver* vscreensaver = new VScreensaver();\r
-      boxstack->add(vscreensaver);\r
-      vscreensaver->draw();\r
-//      boxstack->update(vscreensaver);\r
-\r
-      return 2;\r
-    }\r
-//#endif\r
-\r
-    // Test\r
-//    case Remote::BACK:\r
-//    {\r
-//      return 4;\r
-//    }\r
-\r
-  }\r
-  return 1;\r
-}\r
-\r
-void VWelcome::doChannelsList()\r
-{\r
-  ChannelList* chanList = VDR::getInstance()->getChannelsList(VDR::VIDEO);\r
-\r
-  if (chanList)\r
-  {\r
-    VChannelList* vchan = new VChannelList(VDR::VIDEO);\r
-    vchan->setList(chanList);\r
-\r
-    vchan->draw();\r
-    boxstack->add(vchan);\r
-    boxstack->update(vchan);\r
-  }\r
-  else\r
-  {\r
-    Command::getInstance()->connectionLost();\r
-  }\r
-}\r
-\r
-void VWelcome::doRadioList()\r
-{\r
-  ChannelList* chanList = VDR::getInstance()->getChannelsList(VDR::RADIO);\r
-\r
-  if (chanList)\r
-  {\r
-    VChannelList* vchan = new VChannelList(VDR::RADIO);\r
-    vchan->setList(chanList);\r
-\r
-    vchan->draw();\r
-    boxstack->add(vchan);\r
-    boxstack->update(vchan);\r
-  }\r
-  else\r
-  {\r
-    Command::getInstance()->connectionLost();\r
-  }\r
-}\r
-\r
-void VWelcome::doRecordingsList()\r
-{\r
-  VRecordingList* vrec = new VRecordingList();\r
-  vrec->draw();\r
-  boxstack->add(vrec);\r
-  boxstack->update(vrec);\r
-\r
-  if (!vrec->load())\r
-  {\r
-    Command::getInstance()->connectionLost();\r
-  }\r
-}\r
-\r
-void VWelcome::doMediaList()\r
-{\r
-#ifdef VOMP_MEDIAPLAYER\r
-  VMediaList::createList();\r
-#endif\r
-}\r
-\r
-void VWelcome::doTimersList()\r
-{\r
-  VTimerList* vtl = new VTimerList();\r
-  if (!vtl->load())\r
-  {\r
-    delete vtl;\r
-    Command::getInstance()->connectionLost();\r
-    return;\r
-  }\r
-  \r
-  vtl->draw();\r
-  boxstack->add(vtl);\r
-  boxstack->update(vtl);\r
-}\r
-\r
-void VWelcome::doOptions()\r
-{\r
-//  VOptionsMenu* voptionsmenu = new VOptionsMenu();\r
-//  voptionsmenu->draw();\r
-//  boxstack->add(voptionsmenu);\r
-//  boxstack->updateView(voptionsmenu);\r
-\r
-  VOpts* vopts = new VOpts();\r
-  vopts->draw();\r
-  boxstack->add(vopts);\r
-  boxstack->update(vopts);\r
-}\r
-\r
-void VWelcome::processMessage(Message* m)\r
-{\r
-  if (m->message == Message::MOUSE_MOVE)\r
-  {\r
-    if (sl.mouseMove((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))\r
-    {\r
-      sl.draw();\r
-      boxstack->update(this);\r
-    }\r
-  }\r
-  else if (m->message == Message::MOUSE_LBDOWN)\r
-  {\r
-    if (sl.mouseLBDOWN((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))\r
-    {\r
-      boxstack->handleCommand(Remote::OK); //simulate OK press\r
-    }\r
-  }\r
-}\r
+/*
+    Copyright 2004-2005 Chris Tallon
+
+    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 "vwelcome.h"
+
+#include "remote.h"
+#include "vdr.h"
+#include "vchannellist.h"
+#include "vrecordinglist.h"
+#include "vtimerlist.h"
+#include "command.h"
+#include "message.h"
+#include "colour.h"
+#include "video.h"
+#include "i18n.h"
+#include "timers.h"
+#include "vscreensaver.h"
+#include "vmedialist.h"
+#include "boxstack.h"
+#include "vopts.h"
+
+#include "log.h"
+
+VWelcome::VWelcome()
+{
+  boxstack = BoxStack::getInstance();
+
+  clockRegion.x = 400;
+  clockRegion.y = 0;
+  clockRegion.w = 60;
+  clockRegion.h = 30;
+
+  setSize(460, 220);
+  createBuffer();
+  if (Video::getInstance()->getFormat() == Video::PAL)
+  {
+    setPosition(140, 170);
+  }
+  else
+  {
+    setPosition(130, 140);
+  }
+
+  setTitleBarOn(1);
+  setTitleBarColour(DrawStyle::TITLEBARBACKGROUND);
+
+  sl.setPosition(20, 40);
+  sl.setSize(200, 160);
+  add(&sl);
+
+  setTitleText(tr("Welcome"));
+  sl.addOption(tr("1. Live TV"), 1, 1);
+  sl.addOption(tr("2. Radio"), 2, 0);
+  sl.addOption(tr("3. Recordings"), 3, 0);
+  sl.addOption(tr("4. Timers"), 4, 0);
+#ifdef VOMP_PLATTFORM_MVP
+  sl.addOption(tr("5. MediaPlayer"), 5, 0);
+#endif
+
+  sl.addOption(tr("6. Options"), 6, 0);
+#ifndef VOMP_HAS_EXIT
+  sl.addOption(tr("7. Reboot"), 7, 0);
+#else
+    sl.addOption(tr("7. Exit"), 7, 0);
+#endif
+
+  jpeg.setPosition(240, 60);
+#ifndef _MIPS_ARCH  
+  jpeg.init("/vdr.jpg");
+#else
+  jpeg.init("vdr.jpg");
+#endif
+  add(&jpeg);
+}
+
+void VWelcome::preDelete()
+{
+  Timers::getInstance()->cancelTimer(this, 1);
+}
+
+VWelcome::~VWelcome()
+{
+}
+
+void VWelcome::draw()
+{
+  TBBoxx::draw();
+  drawClock();
+}
+
+void VWelcome::drawClock()
+{
+  // Blank the area first
+  rectangle(area.w - 60, 0, 60, 30, titleBarColour);
+
+  char timeString[20];
+  time_t t;
+  time(&t);
+  struct tm* tms = localtime(&t);
+  strftime(timeString, 19, "%H:%M", tms);
+  drawTextRJ(timeString, 450, 5, DrawStyle::LIGHTTEXT);
+
+  time_t dt = 60 - (t % 60);  // seconds to the next minute
+  if (dt == 0) dt = 60; // advance a whole minute if necessary
+  dt += t;  // get a time_t value for it rather than using duration
+  // (so it will occur at the actual second and not second and a half)
+
+  Timers::getInstance()->setTimerT(this, 1, dt);
+}
+
+void VWelcome::timercall(int clientReference)
+{
+  drawClock();
+  boxstack->update(this, &clockRegion);
+}
+
+int VWelcome::handleCommand(int command)
+{
+  switch(command)
+  {
+    case Remote::DF_UP:
+    case Remote::UP:
+    {
+      sl.up();
+      sl.draw();
+      boxstack->update(this);
+      return 2;
+    }
+    case Remote::DF_DOWN:
+    case Remote::DOWN:
+    {
+      sl.down();
+      sl.draw();
+      boxstack->update(this);
+      return 2;
+    }
+    case Remote::ONE:
+    {
+      doChannelsList();
+      return 2;
+    }
+    case Remote::TWO:
+    {
+      doRadioList();
+      return 2;
+    }
+    case Remote::THREE:
+    {
+      doRecordingsList();
+      return 2;
+    }
+    case Remote::FOUR:
+    {
+      doTimersList();
+      return 2;
+    }
+    case Remote::FIVE:
+    {
+#ifdef VOMP_PLATTFORM_MVP
+      doMediaList();
+#endif
+      return 2;
+    }
+    case Remote::SIX:
+    {
+      doOptions();
+      return 2;
+    }
+    case Remote::SEVEN:
+    {
+      Command::getInstance()->doReboot();
+      return 2;
+    }
+    case Remote::OK:
+    {
+      ULONG option = sl.getCurrentOptionData();
+      if (option == 1)
+      {
+        doChannelsList();
+        return 2;
+      }
+      else if (option == 2)
+      {
+        doRadioList();
+        return 2;
+      }
+      else if (option == 3)
+      {
+        doRecordingsList();
+        return 2;
+      }
+      else if (option == 4)
+      {
+        doTimersList();
+        return 2;
+      }
+      else if (option == 5)
+      {
+        doMediaList();
+        return 2;
+      }
+      else if (option == 6)
+      {
+        doOptions();
+        return 2;
+      }
+      else if (option == 7)
+      {
+        Command::getInstance()->doReboot();
+        return 2;
+      }
+      return 2; // never gets here
+    }
+//#ifdef DEV
+    case Remote::NINE:
+    {
+      VScreensaver* vscreensaver = new VScreensaver();
+      boxstack->add(vscreensaver);
+      vscreensaver->draw();
+//      boxstack->update(vscreensaver);
+
+      return 2;
+    }
+//#endif
+
+    // Test
+//    case Remote::BACK:
+//    {
+//      return 4;
+//    }
+
+  }
+  return 1;
+}
+
+void VWelcome::doChannelsList()
+{
+  ChannelList* chanList = VDR::getInstance()->getChannelsList(VDR::VIDEO);
+
+  if (chanList)
+  {
+    VChannelList* vchan = new VChannelList(VDR::VIDEO);
+    vchan->setList(chanList);
+
+    vchan->draw();
+    boxstack->add(vchan);
+    boxstack->update(vchan);
+  }
+  else
+  {
+    Command::getInstance()->connectionLost();
+  }
+}
+
+void VWelcome::doRadioList()
+{
+  ChannelList* chanList = VDR::getInstance()->getChannelsList(VDR::RADIO);
+
+  if (chanList)
+  {
+    VChannelList* vchan = new VChannelList(VDR::RADIO);
+    vchan->setList(chanList);
+
+    vchan->draw();
+    boxstack->add(vchan);
+    boxstack->update(vchan);
+  }
+  else
+  {
+    Command::getInstance()->connectionLost();
+  }
+}
+
+void VWelcome::doRecordingsList()
+{
+  VRecordingList* vrec = new VRecordingList();
+  vrec->draw();
+  boxstack->add(vrec);
+  boxstack->update(vrec);
+
+  if (!vrec->load())
+  {
+    Command::getInstance()->connectionLost();
+  }
+}
+
+void VWelcome::doMediaList()
+{
+#ifdef VOMP_MEDIAPLAYER
+  VMediaList::createList();
+#endif
+}
+
+void VWelcome::doTimersList()
+{
+  VTimerList* vtl = new VTimerList();
+  if (!vtl->load())
+  {
+    delete vtl;
+    Command::getInstance()->connectionLost();
+    return;
+  }
+  
+  vtl->draw();
+  boxstack->add(vtl);
+  boxstack->update(vtl);
+}
+
+void VWelcome::doOptions()
+{
+//  VOptionsMenu* voptionsmenu = new VOptionsMenu();
+//  voptionsmenu->draw();
+//  boxstack->add(voptionsmenu);
+//  boxstack->updateView(voptionsmenu);
+
+  VOpts* vopts = new VOpts();
+  vopts->draw();
+  boxstack->add(vopts);
+  boxstack->update(vopts);
+}
+
+void VWelcome::processMessage(Message* m)
+{
+  if (m->message == Message::MOUSE_MOVE)
+  {
+    if (sl.mouseMove((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))
+    {
+      sl.draw();
+      boxstack->update(this);
+    }
+  }
+  else if (m->message == Message::MOUSE_LBDOWN)
+  {
+    if (sl.mouseLBDOWN((m->parameter>>16)-getScreenX(),(m->parameter&0xFFFF)-getScreenY()))
+    {
+      boxstack->handleCommand(Remote::OK); //simulate OK press
+    }
+  }
+}
index 40d74e23f6e2545838cf879a203602f978a7f2ad..eed4a379c9bac4e95562419c28513049295f0337 100644 (file)
-/*\r
-    Copyright 2004-2005 Chris Tallon\r
-\r
-    This file is part of VOMP.\r
-\r
-    VOMP is free software; you can redistribute it and/or modify\r
-    it under the terms of the GNU General Public License as published by\r
-    the Free Software Foundation; either version 2 of the License, or\r
-    (at your option) any later version.\r
-\r
-    VOMP is distributed in the hope that it will be useful,\r
-    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-    GNU General Public License for more details.\r
-\r
-    You should have received a copy of the GNU General Public License\r
-    along with VOMP; if not, write to the Free Software\r
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
-*/\r
-\r
-#include "wbutton.h"\r
-\r
-#include "colour.h"\r
-\r
-WButton::WButton()\r
-{\r
-\r
-  setSize(70, 21/*fontHeight*/);\r
-\r
-  mytext = NULL;\r
-  active = 0;\r
-  tag = 0;\r
-  dimmed = false;\r
-}\r
-\r
-WButton::~WButton()\r
-{\r
-  if (mytext) delete[] mytext;\r
-}\r
-\r
-void WButton::setText(const char* takeText)\r
-{\r
-  int length = strlen(takeText);\r
-  mytext = new char[length + 1];\r
-  strcpy(mytext, takeText);\r
-}\r
-\r
-void WButton::setActive(UCHAR tactive)\r
-{\r
-  dimmed = false;\r
-  active = tactive;\r
-}\r
-\r
-void WButton::dim()\r
-{\r
-  // a bolt on for now - an active but dimmed state\r
-  dimmed = true;\r
-  active = false;\r
-}\r
-\r
-void WButton::draw()\r
-{\r
-  if (dimmed)\r
-  {\r
-    fillColour(DrawStyle::BLACK);\r
-    drawTextCentre(mytext, area.w / 2, 0, DrawStyle::SELECTHIGHLIGHT);\r
-  }\r
-  else if (active)\r
-  {\r
-    fillColour(DrawStyle::SELECTHIGHLIGHT);\r
-    drawTextCentre(mytext, area.w / 2, 0, DrawStyle::DARKTEXT);\r
-  }\r
-  else\r
-  {\r
-    fillColour(DrawStyle::BUTTONBACKGROUND);\r
-    drawTextCentre(mytext, area.w / 2, 0, DrawStyle::LIGHTTEXT);\r
-  }\r
-}\r
-\r
-void WButton::setTag(int newTag)\r
-{\r
-  tag = newTag;\r
-}\r
-\r
-int WButton::getTag()\r
-{\r
-  return tag;\r
-}\r
-\r
-// Sorry, I've broken these in the boxx upgrade - chris\r
-\r
-bool WButton::mouseMove(int x, int y)\r
-{\r
-  if ((x-getRootBoxOffsetX())>=0 && (y-getRootBoxOffsetY())>=0\r
-    && (x-getRootBoxOffsetX())<=(int)area.w && (y-getRootBoxOffsetY())<=(int)area.h && !active)\r
-  {\r
-    setActive(1);\r
-    return true;\r
-  }\r
-  return false;\r
-}\r
-\r
-bool WButton::mouseLBDOWN(int x, int y)\r
-{\r
-  if ((x-getRootBoxOffsetX())>=0 && (y-getRootBoxOffsetY())>=0\r
-    && (x-getRootBoxOffsetX())<=(int)area.w && (y-getRootBoxOffsetY())<=(int)area.h && active)\r
-  {\r
-    return true;\r
-  }\r
-  return false;\r
-}\r
+/*
+    Copyright 2004-2005 Chris Tallon
+
+    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 "wbutton.h"
+
+#include "colour.h"
+
+WButton::WButton()
+{
+
+  setSize(70, 21/*fontHeight*/);
+
+  mytext = NULL;
+  active = 0;
+  tag = 0;
+  dimmed = false;
+}
+
+WButton::~WButton()
+{
+  if (mytext) delete[] mytext;
+}
+
+void WButton::setText(const char* takeText)
+{
+  int length = strlen(takeText);
+  mytext = new char[length + 1];
+  strcpy(mytext, takeText);
+}
+
+void WButton::setActive(UCHAR tactive)
+{
+  dimmed = false;
+  active = tactive;
+}
+
+void WButton::dim()
+{
+  // a bolt on for now - an active but dimmed state
+  dimmed = true;
+  active = false;
+}
+
+void WButton::draw()
+{
+  if (dimmed)
+  {
+    fillColour(DrawStyle::BLACK);
+    drawTextCentre(mytext, area.w / 2, 0, DrawStyle::SELECTHIGHLIGHT);
+  }
+  else if (active)
+  {
+    fillColour(DrawStyle::SELECTHIGHLIGHT);
+    drawTextCentre(mytext, area.w / 2, 0, DrawStyle::DARKTEXT);
+  }
+  else
+  {
+    fillColour(DrawStyle::BUTTONBACKGROUND);
+    drawTextCentre(mytext, area.w / 2, 0, DrawStyle::LIGHTTEXT);
+  }
+}
+
+void WButton::setTag(int newTag)
+{
+  tag = newTag;
+}
+
+int WButton::getTag()
+{
+  return tag;
+}
+
+// Sorry, I've broken these in the boxx upgrade - chris
+
+bool WButton::mouseMove(int x, int y)
+{
+  if ((x-getRootBoxOffsetX())>=0 && (y-getRootBoxOffsetY())>=0
+    && (x-getRootBoxOffsetX())<=(int)area.w && (y-getRootBoxOffsetY())<=(int)area.h && !active)
+  {
+    setActive(1);
+    return true;
+  }
+  return false;
+}
+
+bool WButton::mouseLBDOWN(int x, int y)
+{
+  if ((x-getRootBoxOffsetX())>=0 && (y-getRootBoxOffsetY())>=0
+    && (x-getRootBoxOffsetX())<=(int)area.w && (y-getRootBoxOffsetY())<=(int)area.h && active)
+  {
+    return true;
+  }
+  return false;
+}
index 6e0993b1d60e2fd43d588f53a717fad106ace529..7c766787c4f0f9e3abac1698002ca5d2bb34d1d5 100644 (file)
--- a/wjpeg.cc
+++ b/wjpeg.cc
@@ -1,60 +1,60 @@
-/*\r
-    Copyright 2004-2005 Chris Tallon\r
-\r
-    This file is part of VOMP.\r
-\r
-    VOMP is free software; you can redistribute it and/or modify\r
-    it under the terms of the GNU General Public License as published by\r
-    the Free Software Foundation; either version 2 of the License, or\r
-    (at your option) any later version.\r
-\r
-    VOMP is distributed in the hope that it will be useful,\r
-    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-    GNU General Public License for more details.\r
-\r
-    You should have received a copy of the GNU General Public License\r
-    along with VOMP; if not, write to the Free Software\r
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
-*/\r
-#include "boxx.h"\r
-#include "wjpeg.h"\r
-#include <setjmp.h>\r
-#include <sys/types.h>\r
-#include <sys/stat.h>\r
-\r
-#ifndef WIN32\r
-#include <unistd.h>\r
-#else\r
-\r
-#endif\r
-\r
-#include "i18n.h"\r
-#include "log.h"\r
-#include "surface.h"\r
-\r
-\r
-/*----------------------------------------------------------------\r
-  the implementation\r
-  ----------------------------------------------------------------\r
- */\r
-\r
-\r
-WJpeg::WJpeg(){\r
-\r
-}\r
-\r
-WJpeg::~WJpeg() {\r
-}\r
-\r
-\r
-\r
-\r
-\r
-\r
-void WJpeg::draw()\r
-{\r
-\r
-}\r
-\r
-\r
+/*
+    Copyright 2004-2005 Chris Tallon
+
+    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 "boxx.h"
+#include "wjpeg.h"
+#include <setjmp.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#ifndef WIN32
+#include <unistd.h>
+#else
+
+#endif
+
+#include "i18n.h"
+#include "log.h"
+#include "surface.h"
+
+
+/*----------------------------------------------------------------
+  the implementation
+  ----------------------------------------------------------------
+ */
+
+
+WJpeg::WJpeg(){
+
+}
+
+WJpeg::~WJpeg() {
+}
+
+
+
+
+
+
+void WJpeg::draw()
+{
+
+}
+
+
diff --git a/wjpeg.h b/wjpeg.h
index b52931a06b9f3a11f111e1182c0a61ff973619ae..88be7637c8dd3fe970006b202055c39bfa95bcaa 100644 (file)
--- a/wjpeg.h
+++ b/wjpeg.h
@@ -1,59 +1,59 @@
-/*\r
-    Copyright 2004-2005 Chris Tallon\r
-\r
-    This file is part of VOMP.\r
-\r
-    VOMP is free software; you can redistribute it and/or modify\r
-    it under the terms of the GNU General Public License as published by\r
-    the Free Software Foundation; either version 2 of the License, or\r
-    (at your option) any later version.\r
-\r
-    VOMP is distributed in the hope that it will be useful,\r
-    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-    GNU General Public License for more details.\r
-\r
-    You should have received a copy of the GNU General Public License\r
-    along with VOMP; if not, write to the Free Software\r
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
-*/\r
-\r
-#ifndef WJPEG_H\r
-#define WJPEG_H\r
-\r
-#include <stdio.h>\r
-#include <malloc.h>\r
-#include "boxx.h"\r
-\r
-\r
-\r
-\r
-class WJpeg : public Boxx\r
-{\r
-  public:\r
-  \r
-    // temp for boxx\r
-    void setDimensions(int width, int height) {area.w=width;area.h=height;};\r
-  \r
-  \r
-    WJpeg();\r
-    virtual ~WJpeg();\r
-    //old style usage - load local file\r
-    //the sequence is init(filename), draw\r
-    //the new usage is drawJpeg (with having the right offsets computed)\r
-    virtual int init(const char* fileName)=0;\r
-    virtual void draw();\r
-\r
-\r
-};\r
-\r
-\r
-#if defined(VOMP_PLATTFORM_MVP) //Complex jpegs only on mvp\r
-#define WJpegTYPE WJpegComplex\r
-#include "wjpegcomplex.h"\r
-#else\r
-#define WJpegTYPE WJpegSimple\r
-#include "wjpegsimple.h"\r
-#endif\r
-\r
-#endif\r
+/*
+    Copyright 2004-2005 Chris Tallon
+
+    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 WJPEG_H
+#define WJPEG_H
+
+#include <stdio.h>
+#include <malloc.h>
+#include "boxx.h"
+
+
+
+
+class WJpeg : public Boxx
+{
+  public:
+  
+    // temp for boxx
+    void setDimensions(int width, int height) {area.w=width;area.h=height;};
+  
+  
+    WJpeg();
+    virtual ~WJpeg();
+    //old style usage - load local file
+    //the sequence is init(filename), draw
+    //the new usage is drawJpeg (with having the right offsets computed)
+    virtual int init(const char* fileName)=0;
+    virtual void draw();
+
+
+};
+
+
+#if defined(VOMP_PLATTFORM_MVP) //Complex jpegs only on mvp
+#define WJpegTYPE WJpegComplex
+#include "wjpegcomplex.h"
+#else
+#define WJpegTYPE WJpegSimple
+#include "wjpegsimple.h"
+#endif
+
+#endif
index 7b1516872d2b90ca4be01952836d9da875c21ca3..e96ccf204f144b73ac9cc1db6342035604a01900 100644 (file)
-/*\r
-    Copyright 2004-2005 Chris Tallon\r
-\r
-    This file is part of VOMP.\r
-\r
-    VOMP is free software; you can redistribute it and/or modify\r
-    it under the terms of the GNU General Public License as published by\r
-    the Free Software Foundation; either version 2 of the License, or\r
-    (at your option) any later version.\r
-\r
-    VOMP is distributed in the hope that it will be useful,\r
-    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-    GNU General Public License for more details.\r
-\r
-    You should have received a copy of the GNU General Public License\r
-    along with VOMP; if not, write to the Free Software\r
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
-*/\r
-#include "boxx.h"\r
-#include "wjpegcomplex.h"\r
-#include <setjmp.h>\r
-#include <sys/types.h>\r
-#include <sys/stat.h>\r
-\r
-#ifndef WIN32\r
-#include <unistd.h>\r
-#else\r
-\r
-#endif\r
-\r
-#include "i18n.h"\r
-#include "log.h"\r
-#include "surface.h"\r
-\r
-#ifndef __ANDROID__\r
-extern "C"\r
-{\r
-  #include <jpeglib.h>\r
-}\r
-#endif\r
-\r
-#ifndef __ANDROID__\r
-//#define USE_BUFFER\r
-//#define EXTENDED_JPEGLIB\r
-\r
-//a struct to store user data for the jpeg decompressor\r
-class jpegUserData{\r
-  public:\r
-    WJpegComplex::JpegControl * ctl;\r
-    JpegReader *reader;\r
-    jpegUserData() {\r
-      ctl=NULL;\r
-      reader=NULL;\r
-      }\r
-  };\r
-\r
-//the scale factors supported by the jpeg lib\r
-\r
-struct scale{\r
-  UINT num;\r
-  UINT denom;\r
-};\r
-\r
-\r
-struct scale jpegFactors[]={\r
-#ifndef EXTENDED_JPEGLIB\r
-  {1,1},{1,2},{1,4},{1,8}\r
-#else\r
-  {1,1},{7,8},{3,4},{5,8},{1,2},{3,8},{1,4},{1,8}\r
-#endif\r
-};\r
-#endif\r
-\r
-#ifdef WIN32\r
-#define LocalReader WindowsResourceJpegReader\r
-class WindowsResourceJpegReader: public JpegReader {\r
-  public:\r
-  virtual ULONG initRead(const char *filename);\r
-  virtual ULONG readChunk(ULONG offset,ULONG len,char **buf);\r
-  virtual ULONG getSize();\r
-  virtual ~WindowsResourceJpegReader();\r
-protected:\r
-  HGLOBAL hres;\r
-  LPVOID buffer;\r
-  DWORD size;\r
-};\r
-\r
-ULONG WindowsResourceJpegReader::initRead(const char *filename)\r
-{\r
-    HRSRC res=FindResource(NULL,filename,RT_RCDATA);\r
-    hres=LoadResource(NULL,res);\r
-    buffer=LockResource(hres);\r
-    size=SizeofResource(NULL,res);\r
-    //CloseHandle(hres);\r
-    return size;\r
-}\r
-\r
- ULONG WindowsResourceJpegReader::readChunk(ULONG offset,ULONG len,char **buf)\r
-{\r
-    if (offset>size) return 0;\r
-    ULONG toread=min(size-offset,len);\r
-    char* buffy=(char*)malloc(toread);\r
-    memcpy(buffy,((char*)buffer)+offset,toread);\r
-    *buf=buffy;\r
-    return toread;\r
-}\r
-\r
- WindowsResourceJpegReader::~WindowsResourceJpegReader(){\r
-    buffer=NULL;\r
-    size=0;\r
-    FreeResource(hres);\r
- }\r
-\r
- ULONG WindowsResourceJpegReader::getSize(){\r
-   return (ULONG)size;\r
-}\r
-#else\r
-\r
-#define LocalReader LocalJpegReader\r
-class LocalJpegReader: public JpegReader {\r
-  public:\r
-  virtual ULONG initRead(const char *filename);\r
-  virtual ULONG readChunk(ULONG offset,ULONG len,char **buf);\r
-  virtual ~LocalJpegReader();\r
-  virtual ULONG getSize();\r
-  LocalJpegReader();\r
-protected:\r
-  FILE *file;\r
-  ULONG size;\r
-};\r
-\r
-LocalJpegReader::LocalJpegReader(){\r
-  file=NULL;\r
-  size=0;\r
-}\r
-\r
-ULONG LocalJpegReader::initRead(const char *filename)\r
-{\r
-    if (file) fclose(file);\r
-    size=0;\r
-    file=fopen(filename,"r");\r
-    if (file) {\r
-      struct stat st;\r
-      if (fstat(fileno(file), &st) != 0) return 0;\r
-      size= st.st_size;\r
-      return size;\r
-    }\r
-    Log::getInstance()->log("WJepg", Log::ERR, "localReader unable to open File %s", filename);\r
-    return 0;\r
-}\r
-\r
-ULONG LocalJpegReader::readChunk(ULONG offset,ULONG len,char **buf)\r
-{\r
-   *buf=NULL;\r
-   ULONG bread=0;\r
-   if (file) {\r
-     ULLONG cpos=ftell(file);\r
-     if (offset != cpos) {\r
-      fseek(file,offset-cpos,SEEK_CUR);\r
-     }\r
-     if (offset != (ULONG)ftell(file)) {\r
-       Log::getInstance()->log("WJepg", Log::ERR, "readChunk pos = %lu not available", offset);\r
-     }\r
-     else {\r
-       *buf=(char *)malloc(len);\r
-       if ( ! (*buf)) {\r
-         Log::getInstance()->log("WJepg", Log::ERR, "readChunk pos = %lu not available", offset);\r
-       }\r
-       else {\r
-         bread=fread(*buf,1,len,file);\r
-       }\r
-     }\r
-   }\r
-   return bread;\r
-}\r
-\r
-LocalJpegReader::~LocalJpegReader(){\r
-  if (file) fclose(file);\r
-  file=NULL;\r
-}\r
-ULONG LocalJpegReader::getSize(){\r
-  return size;\r
-}\r
-#endif\r
-\r
-#ifndef __ANDROID__\r
-/*----------------------------------------------------------------\r
-  the jpeg lib routines\r
-  ----------------------------------------------------------------\r
- */\r
-\r
-extern "C" {\r
-\r
-\r
-struct my_error_mgr {\r
-  struct jpeg_error_mgr pub;    /* "public" fields */\r
-\r
-  jmp_buf setjmp_buffer;        /* for return to caller */\r
-};\r
-\r
-typedef struct my_error_mgr * my_error_ptr;\r
-\r
-/*\r
- * Here's the routine that will replace the standard error_exit method:\r
- */\r
-\r
-METHODDEF(void)\r
-my_error_exit (j_common_ptr cinfo)\r
-{\r
-  /* cinfo->err really points to a my_error_mgr struct, so coerce pointer */\r
-  my_error_ptr myerr = (my_error_ptr) cinfo->err;\r
-\r
-  /* Always display the message. */\r
-  /* We could postpone this until after returning, if we chose. */\r
-  (*cinfo->err->output_message) (cinfo);\r
-  /* Return control to the setjmp point */\r
-  longjmp(myerr->setjmp_buffer, 1);\r
-}\r
-\r
-ULONG jpeg_call_reader(ULONG offset,ULONG size,char ** buf,void *cb) {\r
-  jpegUserData *user=(jpegUserData *)cb;\r
-  return user->reader->readChunk(offset,size,buf);\r
-}\r
-//the memory buffer reader for the jpeg lib\r
-//taken from jdatasrc.c\r
-\r
-#include "jinclude.h"\r
-#include "jpeglib.h"\r
-#include "jerror.h"\r
-\r
-\r
-typedef struct {\r
-  struct jpeg_source_mgr pub;   /* public fields */\r
-\r
-  JOCTET * buffer;              /* start of buffer */\r
-  boolean start_of_file;        /* have we gotten any data yet? */\r
-  void * userdata;              /* used for callback */\r
-  ULONG offset;\r
-} my_source_mgr;\r
-\r
-typedef my_source_mgr * my_src_ptr;\r
-\r
-#define INPUT_BUF_SIZE  (64*4096)       /* choose an efficiently fread'able size */\r
-\r
-\r
-/*\r
- * Initialize source --- called by jpeg_read_header\r
- * before any data is actually read.\r
- */\r
-\r
-METHODDEF(void)\r
-linit_source (j_decompress_ptr cinfo)\r
-{\r
-  my_src_ptr src = (my_src_ptr) cinfo->src;\r
-\r
-  /* We reset the empty-input-file flag for each image,\r
-   * but we don't clear the input buffer.\r
-   * This is correct behavior for reading a series of images from one source.\r
-   */\r
-  src->start_of_file = TRUE;\r
-  src->offset=0;\r
-}\r
-\r
-\r
-/*\r
- * Fill the input buffer --- called whenever buffer is emptied.\r
- *\r
- * In typical applications, this should read fresh data into the buffer\r
- * (ignoring the current state of next_input_byte & bytes_in_buffer),\r
- * reset the pointer & count to the start of the buffer, and return TRUE\r
- * indicating that the buffer has been reloaded.  It is not necessary to\r
- * fill the buffer entirely, only to obtain at least one more byte.\r
- *\r
- * There is no such thing as an EOF return.  If the end of the file has been\r
- * reached, the routine has a choice of ERREXIT() or inserting fake data into\r
- * the buffer.  In most cases, generating a warning message and inserting a\r
- * fake EOI marker is the best course of action --- this will allow the\r
- * decompressor to output however much of the image is there.  However,\r
- * the resulting error message is misleading if the real problem is an empty\r
- * input file, so we handle that case specially.\r
- *\r
- * In applications that need to be able to suspend compression due to input\r
- * not being available yet, a FALSE return indicates that no more data can be\r
- * obtained right now, but more may be forthcoming later.  In this situation,\r
- * the decompressor will return to its caller (with an indication of the\r
- * number of scanlines it has read, if any).  The application should resume\r
- * decompression after it has loaded more data into the input buffer.  Note\r
- * that there are substantial restrictions on the use of suspension --- see\r
- * the documentation.\r
- *\r
- * When suspending, the decompressor will back up to a convenient restart point\r
- * (typically the start of the current MCU). next_input_byte & bytes_in_buffer\r
- * indicate where the restart point will be if the current call returns FALSE.\r
- * Data beyond this point must be rescanned after resumption, so move it to\r
- * the front of the buffer rather than discarding it.\r
- */\r
-\r
-METHODDEF(boolean)\r
-lfill_input_buffer (j_decompress_ptr cinfo)\r
-{\r
-  my_src_ptr src = (my_src_ptr) cinfo->src;\r
-  size_t nbytes;\r
-  if (src->buffer) free(src->buffer);\r
-  src->buffer=NULL;\r
-  nbytes = jpeg_call_reader(src->offset, INPUT_BUF_SIZE,(char **)&(src->buffer), src->userdata);\r
-\r
-  if (nbytes <= 0) {\r
-    WARNMS(cinfo, JWRN_JPEG_EOF);\r
-    src->buffer =  (JOCTET *)malloc(2);\r
-    src->buffer[0] = (JOCTET) 0xFF;\r
-    src->buffer[1] = (JOCTET) JPEG_EOI;\r
-    nbytes = 2;\r
-\r
-  }\r
-  src->offset+=nbytes;\r
-\r
-  src->pub.next_input_byte = src->buffer;\r
-  src->pub.bytes_in_buffer = nbytes;\r
-  src->start_of_file = FALSE;\r
-\r
-  return TRUE;\r
-}\r
-\r
-\r
-/*\r
- * Skip data --- used to skip over a potentially large amount of\r
- * uninteresting data (such as an APPn marker).\r
- *\r
- * Writers of suspendable-input applications must note that skip_input_data\r
- * is not granted the right to give a suspension return.  If the skip extends\r
- * beyond the data currently in the buffer, the buffer can be marked empty so\r
- * that the next read will cause a fill_input_buffer call that can suspend.\r
- * Arranging for additional bytes to be discarded before reloading the input\r
- * buffer is the application writer's problem.\r
- */\r
-\r
-METHODDEF(void)\r
-lskip_input_data (j_decompress_ptr cinfo, long num_bytes)\r
-{\r
-  my_src_ptr src = (my_src_ptr) cinfo->src;\r
-\r
-  /* Just a dumb implementation for now.  Could use fseek() except\r
-   * it doesn't work on pipes.  Not clear that being smart is worth\r
-   * any trouble anyway --- large skips are infrequent.\r
-   */\r
-  if (num_bytes > 0) {\r
-    while (num_bytes > (long) src->pub.bytes_in_buffer) {\r
-      num_bytes -= (long) src->pub.bytes_in_buffer;\r
-      (void) lfill_input_buffer(cinfo);\r
-      /* note we assume that fill_input_buffer will never return FALSE,\r
-       * so suspension need not be handled.\r
-       */\r
-    }\r
-    src->pub.next_input_byte += (size_t) num_bytes;\r
-    src->pub.bytes_in_buffer -= (size_t) num_bytes;\r
-  }\r
-}\r
-\r
-\r
-/*\r
- * An additional method that can be provided by data source modules is the\r
- * resync_to_restart method for error recovery in the presence of RST markers.\r
- * For the moment, this source module just uses the default resync method\r
- * provided by the JPEG library.  That method assumes that no backtracking\r
- * is possible.\r
- */\r
-\r
-\r
-/*\r
- * Terminate source --- called by jpeg_finish_decompress\r
- * after all data has been read.  Often a no-op.\r
- *\r
- * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding\r
- * application must deal with any cleanup that should happen even\r
- * for error exit.\r
- */\r
-\r
-METHODDEF(void)\r
-lterm_source (j_decompress_ptr cinfo)\r
-{\r
-  /* no work necessary here */\r
-}\r
-\r
-\r
-/*\r
- * Prepare for input from a stdio stream.\r
- * The caller must have already opened the stream, and is responsible\r
- * for closing it after finishing decompression.\r
- */\r
-\r
-extern "C" void\r
-jpeg_memio_src (j_decompress_ptr cinfo, void * userdata)\r
-{\r
-  my_src_ptr src;\r
-\r
-  /* The source object and input buffer are made permanent so that a series\r
-   * of JPEG images can be read from the same file by calling jpeg_stdio_src\r
-   * only before the first one.  (If we discarded the buffer at the end of\r
-   * one image, we'd likely lose the start of the next one.)\r
-   * This makes it unsafe to use this manager and a different source\r
-   * manager serially with the same JPEG object.  Caveat programmer.\r
-   */\r
-  if (cinfo->src == NULL) {     /* first time for this JPEG object? */\r
-    cinfo->src = (struct jpeg_source_mgr *)\r
-      (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,\r
-                                  SIZEOF(my_source_mgr));\r
-    src = (my_src_ptr) cinfo->src;\r
-    src->buffer = NULL;\r
-  }\r
-\r
-  src = (my_src_ptr) cinfo->src;\r
-  src->pub.init_source = linit_source;\r
-  src->pub.fill_input_buffer = lfill_input_buffer;\r
-  src->pub.skip_input_data = lskip_input_data;\r
-  src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */\r
-  src->pub.term_source = lterm_source;\r
-  src->userdata=userdata;\r
-  src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */\r
-  src->pub.next_input_byte = NULL; /* until buffer loaded */\r
-  src->offset=0;\r
-  src->userdata=userdata;\r
-  if (src->buffer) {\r
-     free(src->buffer);\r
-     src->buffer=NULL;\r
-     }\r
-}\r
-/* cleanup to be called before cleanup of cinfo*/\r
-extern "C" void\r
-jpeg_memio_cleanup (j_decompress_ptr cinfo) {\r
-  my_src_ptr src=(my_src_ptr)cinfo->src;\r
-  Log::getInstance()->log("BJpeg", Log::DEBUG, "cleanup src, src=%p, buf=%p",src,(src?src->buffer:0));\r
-  if (src && src->buffer) {\r
-    free(src->buffer);\r
-    src->buffer=NULL;\r
-    }\r
-}\r
-\r
-//taken from mvpmc\r
-//http://git.mvpmc.org/cgi-bin/gitweb.cgi?p=mvpmc.git;a=blob_plain;h=02d4354c0cbbed802a9aa1478918a49fcbf61d00;f=libs/libwidget/image_jpeg.c\r
-\r
-#define GET2BYTES(cinfo, V, swap, offset) do { \\r
-                if (cinfo->src->bytes_in_buffer == 0) (*mysrc->pub.fill_input_buffer)(cinfo); \\r
-                cinfo->src->bytes_in_buffer--; \\r
-                V = (*cinfo->src->next_input_byte++) << (swap?0:8); \\r
-                if (cinfo->src->bytes_in_buffer == 0) (*mysrc->pub.fill_input_buffer)(cinfo); \\r
-                cinfo->src->bytes_in_buffer--; \\r
-                V += (*cinfo->src->next_input_byte++) << (swap?8:0); \\r
-                offset += 2; } while(0) \r
-\r
-#define GET4BYTES(cinfo, V, swap, offset) do { \\r
-                if (cinfo->src->bytes_in_buffer == 0) (*mysrc->pub.fill_input_buffer)(cinfo); \\r
-                cinfo->src->bytes_in_buffer--; \\r
-                V = (*cinfo->src->next_input_byte++) << (swap?0:24); \\r
-                if (cinfo->src->bytes_in_buffer == 0) (*mysrc->pub.fill_input_buffer)(cinfo); \\r
-                cinfo->src->bytes_in_buffer--; \\r
-                V += (*cinfo->src->next_input_byte++) << (swap?8:16); \\r
-                if (cinfo->src->bytes_in_buffer == 0) (*mysrc->pub.fill_input_buffer)(cinfo); \\r
-                cinfo->src->bytes_in_buffer--; \\r
-                V += (*cinfo->src->next_input_byte++) << (swap?16:8); \\r
-                if (cinfo->src->bytes_in_buffer == 0) (*mysrc->pub.fill_input_buffer)(cinfo); \\r
-                cinfo->src->bytes_in_buffer--; \\r
-                V += (*cinfo->src->next_input_byte++) << (swap?24:0); \\r
-                offset += 4; } while(0)\r
-\r
-static boolean\r
-get_exif_orient (j_decompress_ptr cinfo)\r
-/* Get the Exif orientation info */\r
-{\r
-        unsigned int tmp, offset, length, numtags;\r
-        int orient=-1;\r
-        jpegUserData * ud=0;\r
-        boolean swap;\r
-        orient = 1;\r
-        offset = 0;\r
-        my_src_ptr mysrc = (my_src_ptr) cinfo->src;\r
-\r
-        /* marker length */\r
-        GET2BYTES(cinfo, length, 0, offset);\r
-        if (length<8) goto err;\r
-        /* Exif header */\r
-        GET4BYTES(cinfo, tmp, 0, offset);\r
-        if (tmp != 0x45786966) goto err;\r
-        GET2BYTES(cinfo, tmp, 0, offset);\r
-        if (tmp != 0x0000) goto err;\r
-        /* Byte-order */\r
-        GET2BYTES(cinfo, tmp, 0, offset);\r
-        if (tmp == 0x4949) swap = 1;\r
-        else if (tmp == 0x4d4d) swap = 0;\r
-        else goto err;\r
-        GET2BYTES(cinfo, tmp, swap, offset);\r
-        if (tmp != 0x002A) goto err;\r
-        /* offset to first IFD */\r
-        GET4BYTES(cinfo, tmp, swap, offset);\r
-        offset += tmp-8;\r
-        (*mysrc->pub.skip_input_data)(cinfo, tmp-8);\r
-        /* number of tags in IFD */\r
-        GET2BYTES(cinfo, numtags, swap, offset);\r
-        if (numtags == 0) goto err;\r
-        \r
-        /* Search for Orientation Tag in IFD0 */\r
-        for (;;) {\r
-                if (offset > length-12) goto err;\r
-                GET2BYTES(cinfo, tmp, swap, offset);\r
-                if (tmp == 0x0112) break; /* found Orientation Tag */\r
-                if (--numtags == 0) goto err;\r
-                offset += 10;\r
-                (*mysrc->pub.skip_input_data)(cinfo, 10);\r
-        }\r
-        offset += 6;\r
-        (*mysrc->pub.skip_input_data)(cinfo, 6);\r
-        GET2BYTES(cinfo, orient, swap, offset);\r
-        if( orient==0 || orient>8 ) orient = 1;\r
-        \r
-        Log::getInstance()->log("WJpeg", Log::DEBUG, "read exif orientation %u", orient);\r
-        ud=(jpegUserData *)(mysrc->userdata);\r
-        switch(orient) {\r
-          case 3:\r
-            ud->ctl->exifRotation=WJpegComplex::ROT_180;\r
-            break;\r
-          case 6:\r
-            ud->ctl->exifRotation=WJpegComplex::ROT_90;\r
-            break;\r
-          case 8:\r
-            ud->ctl->exifRotation=WJpegComplex::ROT_270;\r
-            break;\r
-        }\r
-\r
-err:\r
-        (*mysrc->pub.skip_input_data)(cinfo, length-offset);\r
-        return TRUE;\r
-}\r
-}\r
-#endif\r
-/*----------------------------------------------------------------\r
-  the implementation\r
-  ----------------------------------------------------------------\r
- */\r
-\r
-\r
-WJpegComplex::WJpegComplex(){\r
-  reader=NULL;\r
-  owningReader=false;\r
-  errbuf[0]=0;\r
-}\r
-\r
-WJpegComplex::~WJpegComplex() {\r
-  if (owningReader && reader) delete reader;\r
-}\r
-\r
-int WJpegComplex::init(const char* tfileName)\r
-{\r
-  if (owningReader && reader) delete reader;\r
-  errbuf[0]=0; //clean error state\r
-  LocalReader *myreader=new LocalReader();\r
-  reader=myreader;\r
-  owningReader=true;\r
-  ULONG psize=myreader->initRead(tfileName);\r
-  if (psize == 0) {\r
-    delete reader;\r
-    reader=NULL;\r
-    owningReader=false;\r
-    SNPRINTF(errbuf,200,"unable to open %s",tfileName);\r
-    return 0;\r
-  }\r
-  return 1;\r
-}\r
-\r
-\r
-\r
-\r
-bool WJpegComplex::hasError() {\r
-  return (errbuf[0] != 0);\r
-}\r
-void WJpegComplex::draw()\r
-{\r
-  bool ok=false;\r
-  JpegControl ctl;\r
-  if (reader) {\r
-    Region myRegion;\r
-    Surface *sfc=getSurface(myRegion);\r
-    myRegion.w=area.w;\r
-    myRegion.h=area.h;\r
-    ctl.area=myRegion;\r
-    ctl.enlarge=true;\r
-    if (drawJpeg(&ctl,sfc,reader,backgroundColour) ) ok=true;\r
-  }\r
-  else {\r
-    SNPRINTF(errbuf,200,"jpeg reader not initialized");\r
-  }\r
-  if (! ok) {\r
-    drawTextCentre(tr("Jpeg ERROR"), 240, 170, DrawStyle::LIGHTTEXT);\r
-    if (errbuf[0] != 0) drawTextCentre(errbuf,240,200, DrawStyle::LIGHTTEXT);\r
-    if (ctl.error[0] != 0) drawTextCentre(ctl.error,240,230, DrawStyle::LIGHTTEXT);\r
-  }\r
-}\r
-\r
-\r
-\r
-/**\r
-  the main drawing function\r
-  this will read the pciture via the reader\r
-  and draw directly into the surface\r
-  it will compute an appropriate scale and set the infos in the\r
-  JpegControl structure\r
-**/  \r
-\r
-#ifndef __ANDROID__\r
-\r
-bool WJpegComplex::drawJpeg(JpegControl * ctl,Surface * sfc,JpegReader *rdr, DrawStyle & backgroundColour) {\r
-  Log* logger = Log::getInstance();\r
-  if (! rdr || ! sfc) {\r
-    logger->log("BJpeg", Log::ERR, "JPEG error rdr=NULL or sfc=NULL");\r
-    return false;\r
-  }\r
-  logger->log("BJpeg", Log::DEBUG, "draw Jpeg Started sfc=%p, rdr=%p",sfc,rdr);\r
-  unsigned char* buffer =NULL;\r
-  struct jpeg_decompress_struct cinfo;\r
-  struct my_error_mgr jerr;\r
-  cinfo.err = jpeg_std_error(&jerr.pub);\r
-  jerr.pub.error_exit = my_error_exit;\r
-  /* Establish the setjmp return context for my_error_exit to use. */\r
-  if (setjmp(jerr.setjmp_buffer)) {\r
-    /* If we get here, the JPEG code has signaled an error.\r
-     * We need to clean up the JPEG object, close the input file, and return.\r
-     */\r
-    if (rdr) jpeg_memio_cleanup(&cinfo);\r
-    jpeg_destroy_decompress(&cinfo);\r
-    logger->log("BJpeg", Log::ERR, "JPEG error");\r
-    if (buffer) free(buffer);\r
-    return false;\r
-  }\r
-  jpegUserData userdata;\r
-  int xpos=0;\r
-  int ypos=0;\r
-  jpeg_create_decompress(&cinfo);\r
-  userdata.reader=rdr;\r
-  userdata.ctl=ctl;\r
-  ctl->exifRotation=ROT_0;\r
-  ctl->error[0]=0;\r
-  ctl->exifDate[0]=0;\r
-  //create the input for the jpeg lib\r
-  jpeg_memio_src(&cinfo,(void *)(&userdata));\r
-  //processor for EXIF data\r
-  jpeg_set_marker_processor(&cinfo, JPEG_APP0+1, get_exif_orient);\r
-  //read in header info\r
-  jpeg_read_header(&cinfo, TRUE);\r
-  ctl->picw=cinfo.image_width;\r
-  ctl->pich=cinfo.image_height;\r
-  ctl->compressedSize=rdr->getSize();\r
-  //now we have important info available in ctl (pictuerw,h, exif orientation,size)\r
-  //compute rotation due to the defined enum values we can simply add them\r
-  ctl->finalRotation=(enum Rotation)((ctl->rotation+ctl->exifRotation)%4);\r
-  logger->log("BJpeg", Log::DEBUG, "JPEG read header w=%i h=%i, rot=%i", ctl->picw,ctl->pich,ctl->finalRotation);\r
-  //now we have to compute the scale\r
-  //input: ctl->picw,ctl->pich,ctl->finalRotation,ctl->mode,ctl->scaleAmount, ctl->scaleafter\r
-  //       list of available jpeg scale factors\r
-  //out:   scalenum,scaledenom,scaleafter\r
-\r
-  UINT picturew=ctl->picw;\r
-  UINT pictureh=ctl->pich;\r
-  switch (ctl->finalRotation){\r
-    case ROT_90:\r
-    case ROT_270:\r
-      pictureh=ctl->picw;\r
-      picturew=ctl->pich;\r
-      break;\r
-    default:\r
-      break;\r
-  }\r
-  UINT scalenum=1;\r
-  UINT scaledenom=1;\r
-  UINT scaleafter=1;\r
-  if (! ctl->enlarge) {\r
-    //scale - compute the factors to fit 100%\r
-    int scalew=1000*picturew/ctl->area.w;\r
-    int scaleh=1000*pictureh/ctl->area.h;\r
-    int scale=scaleh;\r
-    if (scalew > scaleh) scale=scalew;\r
-\r
-    //OK now find out which is the optimal setting\r
-    //rule: find settings being nearest to:\r
-    //   mode=LETTER - smaller or equal screen size (i.e. scale*scalefactor <= 1000)\r
-    //   mode=CROP   - bigger or equal screen size (i.e. scale *scalefactor>= 1000)\r
-    //   mode=CROPPERCENT - smaller or equal screensize*scaleamount (i.e. scale*scalefactor<= 1000*scaleamount)\r
-    //                      scaleamount is in % - so in reality we use scaleamount*10 instead scaleamount*1000\r
-    //the scalefactor computes as scalenum/(scaledenom*scaleafter)\r
-    scaledenom=8;\r
-    int minDiff=1000;\r
-    logger->log("BJpeg", Log::DEBUG, "start scaling screenw=%u, screenh=%u, pw=%u,ph=%u, scale=%d, mode=%d, %%=%u, after=%u",\r
-       ctl->area.w,ctl->area.h,picturew,pictureh,scale,(int)ctl->mode,ctl->scaleAmount, ctl->scaleafter); \r
-    for (UINT j=0;j<sizeof(jpegFactors)/sizeof(jpegFactors[0]);j++) {\r
-      for (UINT sa=1;sa<=ctl->scaleafter;sa++) {\r
-        int curf=(scale*jpegFactors[j].num)/(jpegFactors[j].denom*sa);\r
-        bool setThis=false;\r
-        logger->log("BJpeg", Log::DEBUG, "testing scale curf=%d,num=%u,denom=%u,after=%u,minDiff=%d", \r
-            curf,jpegFactors[j].num,jpegFactors[j].denom,sa,minDiff);\r
-        switch(ctl->mode) {\r
-          case CROP:\r
-            if (curf >= 1000 && curf < (minDiff +1000)) {\r
-              setThis=true;\r
-              minDiff=curf-1000;\r
-            }\r
-            break;\r
-          case LETTER:\r
-            if (curf <= 1000 && curf > (1000-minDiff)) {\r
-              setThis=true;\r
-              minDiff=1000-curf;\r
-            }\r
-            break;\r
-          case CROPPERCENT:\r
-            if (curf <= 10*(int)ctl->scaleAmount ) {\r
-              int abs=curf-1000;\r
-              if (abs < 0) abs=-abs;\r
-              if (abs < minDiff) {\r
-                   setThis=true;\r
-                   minDiff=abs;\r
-              }\r
-            }\r
-            break;\r
-        }\r
-        if (setThis) {\r
-          logger->log("BJpeg", Log::DEBUG, "testing scale curf=%d,take this",curf);\r
-          scalenum=jpegFactors[j].num;\r
-          scaledenom=jpegFactors[j].denom;\r
-          scaleafter=sa;\r
-        }\r
-      }\r
-    }\r
-    ctl->scale=100*scalenum/(scaledenom*scaleafter);\r
-\r
-    logger->log("BJpeg", Log::DEBUG, "JPEG scaling found scale=%i num=%i denom=%i after=%i result=%i scale=%i%% ",\r
-        scale,scalenum,scaledenom,scaleafter,scale*ctl->scale/100,ctl->scale);\r
-\r
-    cinfo.scale_denom=scaledenom;\r
-    cinfo.scale_num=scalenum;\r
-    }\r
-  else\r
-  {\r
-    //set drawing area according to picture\r
-    ctl->area.w=ctl->picw;\r
-    ctl->area.h=ctl->pich;\r
-  }\r
-\r
-  //now we know the scaling\r
-  //compute the scaled size and position\r
-\r
-  jpeg_start_decompress(&cinfo);\r
-  //picturew/h is now the output width from the decompressor and afterscaler\r
-  //this is unrotated \r
-  picturew=cinfo.output_width;\r
-  pictureh=cinfo.output_height;\r
-  if (scaleafter > 1) {\r
-    picturew=picturew/scaleafter;\r
-    pictureh=pictureh/scaleafter;\r
-  }\r
-  //if our image is smaller - center it\r
-  if (! ctl->enlarge) {\r
-    if (ctl->finalRotation == ROT_90 || ctl->finalRotation == ROT_270) {\r
-      int dim=pictureh;\r
-      xpos=(((int)ctl->area.w)-dim)/2;\r
-      dim=picturew;\r
-      ypos=(((int)ctl->area.h)-dim)/2;\r
-    } else {\r
-      int dim=picturew;\r
-      xpos=(((int)ctl->area.w)-dim)/2;\r
-      dim=pictureh;\r
-      ypos=(((int)ctl->area.h)-dim)/2;\r
-    }\r
-    if (xpos <0) xpos=0;\r
-    if (ypos <0) ypos=0;\r
-  }\r
-  xpos+=ctl->area.x;\r
-  ypos+=ctl->area.y;\r
-  //remember the jpeg dimensions for computing the buffer\r
-  UINT jpegwidth=cinfo.output_width;\r
-  UINT jpegheight=cinfo.output_height;\r
-  logger->log("BJpeg", Log::DEBUG, "JPEG startup done pw=%i ph=%i, xo=%i,yo=%i, jw=%i, jh=%i, rot=%d", \r
-      picturew, pictureh,xpos,ypos,jpegwidth,jpegheight,(int)ctl->finalRotation*90);\r
-\r
-  //fill the background\r
-  sfc->fillblt(ctl->area.x,ctl->area.y,ctl->area.w,ctl->area.h,backgroundColour);\r
-\r
-  //line len in bytes (3 bytes per Pixel) - for buffer (can be bigger then surface)\r
-  int linelen=jpegwidth*3;\r
-#ifdef USE_BUFFER\r
-  // MAKE THE 2D ARRAY\r
-  buffer = (unsigned char*)malloc(jpegheight * linelen);\r
-  logger->log("BJpeg", Log::DEBUG, "Buffer allocated at %p, lines = %i linelen = %i", buffer, jpegheight, linelen);\r
-  if (buffer == NULL) {\r
-    if (rdr) jpeg_memio_cleanup(&cinfo);\r
-    jpeg_destroy_decompress(&cinfo);\r
-    logger->log("BJpeg", Log::ERR, "JPEG error - no room for buffer");\r
-    SNPRINTF(ctl->error,100,"no room for buffer");\r
-    return false;\r
-  }\r
-#endif\r
-\r
-#ifndef USE_BUFFER\r
-  //unsigned char lbuf[linelen];\r
-  unsigned char *lbuf=new unsigned char[linelen*scaleafter];\r
-  unsigned char * ptr=lbuf;\r
-  UINT outy=0;\r
-#else\r
-  unsigned char * ptr=buffer;\r
-#endif\r
-\r
-  int rowsread = 0;\r
-\r
-  DrawStyle c;\r
-  sfc->startFastDraw();//Tell the surface, that we will draw a lot of pixel,\r
-  //so that performance, can be optimized\r
-  logger->log("BJpeg", Log::DEBUG, "start drawing ");\r
-  UINT colincr=0;\r
-  //factors to base 1024\r
-  UINT fac=1024;\r
-  if (scaleafter > 1) {\r
-     colincr=3*scaleafter-3;\r
-     fac=1024/(scaleafter*scaleafter);\r
-     }\r
-  logger->log("BJpeg", Log::DEBUG, "jpeg  draw scale %d image: %u %u, picture: %u %u", scaleafter,picturew,pictureh,jpegwidth,jpegheight);\r
-  while (cinfo.output_scanline < jpegheight)\r
-  {\r
-//  logger->log("BJpeg", Log::DEBUG, "%i", rowsread);\r
-    rowsread += jpeg_read_scanlines(&cinfo,&ptr,1);\r
-#ifdef USE_BUFFER\r
-    ptr+=linelen;\r
-#else\r
-    if (scaleafter > 1) {\r
-      if (rowsread % scaleafter != scaleafter-1) {\r
-        //this simple approach wold maybe forget scaleafter -1 lines at the end...\r
-        ptr+=linelen;\r
-        continue;\r
-      }\r
-      ptr=lbuf;\r
-    }\r
-    drawLine(sfc,ctl->finalRotation,ptr,scaleafter,picturew,pictureh,xpos,ypos,outy,linelen,colincr,scaleafter,fac);\r
-    outy++;\r
-    \r
-#endif\r
-  }\r
-  sfc->endFastDraw();\r
-\r
-  logger->log("BJpeg", Log::DEBUG, "Done all jpeg_read");\r
-\r
-  jpeg_finish_decompress(&cinfo);\r
-  jpeg_memio_cleanup(&cinfo);\r
-  jpeg_destroy_decompress(&cinfo);\r
-\r
-  logger->log("BJpeg", Log::DEBUG, "jpeg shutdown done");\r
-  rdr->drawingDone();\r
-\r
-#ifdef USE_BUFFER\r
-  UINT y;\r
-  //Tell the surface, that we will draw a lot of pixel,\r
-  //so that performance, can be optimized\r
-  sfc->startFastDraw();\r
-  logger->log("BJpeg", Log::DEBUG, "jpeg start buffer draw" );\r
-  unsigned char* p=buffer; //start of first row\r
-  UINT rowincr=linelen*scaleafter;\r
-  //for simplicity omit last line to avoid running out of buffer\r
-  for (y = 0; y < pictureh-1 ;y++)\r
-  {\r
-    drawLine(sfc,ctl->finalRotation,p,scaleafter,picturew,pictureh,xpos,ypos,y,linelen,colincr,scaleafter,fac);\r
-    p+=rowincr;\r
-  }\r
-  sfc->endFastDraw();\r
-  logger->log("BJpeg", Log::DEBUG, "end draw");\r
-  free(buffer);\r
-#else\r
-  delete[] lbuf;\r
-#endif\r
-  logger->log("BJpeg", Log::DEBUG, "deleted buffer");\r
-  return true;\r
-}\r
-\r
-\r
-#else\r
-bool WJpegComplex::drawJpeg(JpegControl * ctl,Surface * sfc,JpegReader *rdr, DrawStyle & backgroundColour) {\r
-       return true;\r
-}\r
-#endif\r
-\r
-//get my own surface\r
-Surface * WJpegComplex::getSurface(Region & r) {\r
-  r.x=getRootBoxOffsetX();\r
-  r.y=getRootBoxOffsetY();\r
-  r.w=area.w;\r
-  r.h=area.h;\r
-  return Boxx::getSurface();\r
-}\r
-\r
+/*
+    Copyright 2004-2005 Chris Tallon
+
+    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 "boxx.h"
+#include "wjpegcomplex.h"
+#include <setjmp.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#ifndef WIN32
+#include <unistd.h>
+#else
+
+#endif
+
+#include "i18n.h"
+#include "log.h"
+#include "surface.h"
+
+#ifndef __ANDROID__
+extern "C"
+{
+  #include <jpeglib.h>
+}
+#endif
+
+#ifndef __ANDROID__
+//#define USE_BUFFER
+//#define EXTENDED_JPEGLIB
+
+//a struct to store user data for the jpeg decompressor
+class jpegUserData{
+  public:
+    WJpegComplex::JpegControl * ctl;
+    JpegReader *reader;
+    jpegUserData() {
+      ctl=NULL;
+      reader=NULL;
+      }
+  };
+
+//the scale factors supported by the jpeg lib
+
+struct scale{
+  UINT num;
+  UINT denom;
+};
+
+
+struct scale jpegFactors[]={
+#ifndef EXTENDED_JPEGLIB
+  {1,1},{1,2},{1,4},{1,8}
+#else
+  {1,1},{7,8},{3,4},{5,8},{1,2},{3,8},{1,4},{1,8}
+#endif
+};
+#endif
+
+#ifdef WIN32
+#define LocalReader WindowsResourceJpegReader
+class WindowsResourceJpegReader: public JpegReader {
+  public:
+  virtual ULONG initRead(const char *filename);
+  virtual ULONG readChunk(ULONG offset,ULONG len,char **buf);
+  virtual ULONG getSize();
+  virtual ~WindowsResourceJpegReader();
+protected:
+  HGLOBAL hres;
+  LPVOID buffer;
+  DWORD size;
+};
+
+ULONG WindowsResourceJpegReader::initRead(const char *filename)
+{
+    HRSRC res=FindResource(NULL,filename,RT_RCDATA);
+    hres=LoadResource(NULL,res);
+    buffer=LockResource(hres);
+    size=SizeofResource(NULL,res);
+    //CloseHandle(hres);
+    return size;
+}
+
+ ULONG WindowsResourceJpegReader::readChunk(ULONG offset,ULONG len,char **buf)
+{
+    if (offset>size) return 0;
+    ULONG toread=min(size-offset,len);
+    char* buffy=(char*)malloc(toread);
+    memcpy(buffy,((char*)buffer)+offset,toread);
+    *buf=buffy;
+    return toread;
+}
+
+ WindowsResourceJpegReader::~WindowsResourceJpegReader(){
+    buffer=NULL;
+    size=0;
+    FreeResource(hres);
+ }
+
+ ULONG WindowsResourceJpegReader::getSize(){
+   return (ULONG)size;
+}
+#else
+
+#define LocalReader LocalJpegReader
+class LocalJpegReader: public JpegReader {
+  public:
+  virtual ULONG initRead(const char *filename);
+  virtual ULONG readChunk(ULONG offset,ULONG len,char **buf);
+  virtual ~LocalJpegReader();
+  virtual ULONG getSize();
+  LocalJpegReader();
+protected:
+  FILE *file;
+  ULONG size;
+};
+
+LocalJpegReader::LocalJpegReader(){
+  file=NULL;
+  size=0;
+}
+
+ULONG LocalJpegReader::initRead(const char *filename)
+{
+    if (file) fclose(file);
+    size=0;
+    file=fopen(filename,"r");
+    if (file) {
+      struct stat st;
+      if (fstat(fileno(file), &st) != 0) return 0;
+      size= st.st_size;
+      return size;
+    }
+    Log::getInstance()->log("WJepg", Log::ERR, "localReader unable to open File %s", filename);
+    return 0;
+}
+
+ULONG LocalJpegReader::readChunk(ULONG offset,ULONG len,char **buf)
+{
+   *buf=NULL;
+   ULONG bread=0;
+   if (file) {
+     ULLONG cpos=ftell(file);
+     if (offset != cpos) {
+      fseek(file,offset-cpos,SEEK_CUR);
+     }
+     if (offset != (ULONG)ftell(file)) {
+       Log::getInstance()->log("WJepg", Log::ERR, "readChunk pos = %lu not available", offset);
+     }
+     else {
+       *buf=(char *)malloc(len);
+       if ( ! (*buf)) {
+         Log::getInstance()->log("WJepg", Log::ERR, "readChunk pos = %lu not available", offset);
+       }
+       else {
+         bread=fread(*buf,1,len,file);
+       }
+     }
+   }
+   return bread;
+}
+
+LocalJpegReader::~LocalJpegReader(){
+  if (file) fclose(file);
+  file=NULL;
+}
+ULONG LocalJpegReader::getSize(){
+  return size;
+}
+#endif
+
+#ifndef __ANDROID__
+/*----------------------------------------------------------------
+  the jpeg lib routines
+  ----------------------------------------------------------------
+ */
+
+extern "C" {
+
+
+struct my_error_mgr {
+  struct jpeg_error_mgr pub;    /* "public" fields */
+
+  jmp_buf setjmp_buffer;        /* for return to caller */
+};
+
+typedef struct my_error_mgr * my_error_ptr;
+
+/*
+ * Here's the routine that will replace the standard error_exit method:
+ */
+
+METHODDEF(void)
+my_error_exit (j_common_ptr cinfo)
+{
+  /* cinfo->err really points to a my_error_mgr struct, so coerce pointer */
+  my_error_ptr myerr = (my_error_ptr) cinfo->err;
+
+  /* Always display the message. */
+  /* We could postpone this until after returning, if we chose. */
+  (*cinfo->err->output_message) (cinfo);
+  /* Return control to the setjmp point */
+  longjmp(myerr->setjmp_buffer, 1);
+}
+
+ULONG jpeg_call_reader(ULONG offset,ULONG size,char ** buf,void *cb) {
+  jpegUserData *user=(jpegUserData *)cb;
+  return user->reader->readChunk(offset,size,buf);
+}
+//the memory buffer reader for the jpeg lib
+//taken from jdatasrc.c
+
+#include "jinclude.h"
+#include "jpeglib.h"
+#include "jerror.h"
+
+
+typedef struct {
+  struct jpeg_source_mgr pub;   /* public fields */
+
+  JOCTET * buffer;              /* start of buffer */
+  boolean start_of_file;        /* have we gotten any data yet? */
+  void * userdata;              /* used for callback */
+  ULONG offset;
+} my_source_mgr;
+
+typedef my_source_mgr * my_src_ptr;
+
+#define INPUT_BUF_SIZE  (64*4096)       /* choose an efficiently fread'able size */
+
+
+/*
+ * Initialize source --- called by jpeg_read_header
+ * before any data is actually read.
+ */
+
+METHODDEF(void)
+linit_source (j_decompress_ptr cinfo)
+{
+  my_src_ptr src = (my_src_ptr) cinfo->src;
+
+  /* We reset the empty-input-file flag for each image,
+   * but we don't clear the input buffer.
+   * This is correct behavior for reading a series of images from one source.
+   */
+  src->start_of_file = TRUE;
+  src->offset=0;
+}
+
+
+/*
+ * Fill the input buffer --- called whenever buffer is emptied.
+ *
+ * In typical applications, this should read fresh data into the buffer
+ * (ignoring the current state of next_input_byte & bytes_in_buffer),
+ * reset the pointer & count to the start of the buffer, and return TRUE
+ * indicating that the buffer has been reloaded.  It is not necessary to
+ * fill the buffer entirely, only to obtain at least one more byte.
+ *
+ * There is no such thing as an EOF return.  If the end of the file has been
+ * reached, the routine has a choice of ERREXIT() or inserting fake data into
+ * the buffer.  In most cases, generating a warning message and inserting a
+ * fake EOI marker is the best course of action --- this will allow the
+ * decompressor to output however much of the image is there.  However,
+ * the resulting error message is misleading if the real problem is an empty
+ * input file, so we handle that case specially.
+ *
+ * In applications that need to be able to suspend compression due to input
+ * not being available yet, a FALSE return indicates that no more data can be
+ * obtained right now, but more may be forthcoming later.  In this situation,
+ * the decompressor will return to its caller (with an indication of the
+ * number of scanlines it has read, if any).  The application should resume
+ * decompression after it has loaded more data into the input buffer.  Note
+ * that there are substantial restrictions on the use of suspension --- see
+ * the documentation.
+ *
+ * When suspending, the decompressor will back up to a convenient restart point
+ * (typically the start of the current MCU). next_input_byte & bytes_in_buffer
+ * indicate where the restart point will be if the current call returns FALSE.
+ * Data beyond this point must be rescanned after resumption, so move it to
+ * the front of the buffer rather than discarding it.
+ */
+
+METHODDEF(boolean)
+lfill_input_buffer (j_decompress_ptr cinfo)
+{
+  my_src_ptr src = (my_src_ptr) cinfo->src;
+  size_t nbytes;
+  if (src->buffer) free(src->buffer);
+  src->buffer=NULL;
+  nbytes = jpeg_call_reader(src->offset, INPUT_BUF_SIZE,(char **)&(src->buffer), src->userdata);
+
+  if (nbytes <= 0) {
+    WARNMS(cinfo, JWRN_JPEG_EOF);
+    src->buffer =  (JOCTET *)malloc(2);
+    src->buffer[0] = (JOCTET) 0xFF;
+    src->buffer[1] = (JOCTET) JPEG_EOI;
+    nbytes = 2;
+
+  }
+  src->offset+=nbytes;
+
+  src->pub.next_input_byte = src->buffer;
+  src->pub.bytes_in_buffer = nbytes;
+  src->start_of_file = FALSE;
+
+  return TRUE;
+}
+
+
+/*
+ * Skip data --- used to skip over a potentially large amount of
+ * uninteresting data (such as an APPn marker).
+ *
+ * Writers of suspendable-input applications must note that skip_input_data
+ * is not granted the right to give a suspension return.  If the skip extends
+ * beyond the data currently in the buffer, the buffer can be marked empty so
+ * that the next read will cause a fill_input_buffer call that can suspend.
+ * Arranging for additional bytes to be discarded before reloading the input
+ * buffer is the application writer's problem.
+ */
+
+METHODDEF(void)
+lskip_input_data (j_decompress_ptr cinfo, long num_bytes)
+{
+  my_src_ptr src = (my_src_ptr) cinfo->src;
+
+  /* Just a dumb implementation for now.  Could use fseek() except
+   * it doesn't work on pipes.  Not clear that being smart is worth
+   * any trouble anyway --- large skips are infrequent.
+   */
+  if (num_bytes > 0) {
+    while (num_bytes > (long) src->pub.bytes_in_buffer) {
+      num_bytes -= (long) src->pub.bytes_in_buffer;
+      (void) lfill_input_buffer(cinfo);
+      /* note we assume that fill_input_buffer will never return FALSE,
+       * so suspension need not be handled.
+       */
+    }
+    src->pub.next_input_byte += (size_t) num_bytes;
+    src->pub.bytes_in_buffer -= (size_t) num_bytes;
+  }
+}
+
+
+/*
+ * An additional method that can be provided by data source modules is the
+ * resync_to_restart method for error recovery in the presence of RST markers.
+ * For the moment, this source module just uses the default resync method
+ * provided by the JPEG library.  That method assumes that no backtracking
+ * is possible.
+ */
+
+
+/*
+ * Terminate source --- called by jpeg_finish_decompress
+ * after all data has been read.  Often a no-op.
+ *
+ * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding
+ * application must deal with any cleanup that should happen even
+ * for error exit.
+ */
+
+METHODDEF(void)
+lterm_source (j_decompress_ptr cinfo)
+{
+  /* no work necessary here */
+}
+
+
+/*
+ * Prepare for input from a stdio stream.
+ * The caller must have already opened the stream, and is responsible
+ * for closing it after finishing decompression.
+ */
+
+extern "C" void
+jpeg_memio_src (j_decompress_ptr cinfo, void * userdata)
+{
+  my_src_ptr src;
+
+  /* The source object and input buffer are made permanent so that a series
+   * of JPEG images can be read from the same file by calling jpeg_stdio_src
+   * only before the first one.  (If we discarded the buffer at the end of
+   * one image, we'd likely lose the start of the next one.)
+   * This makes it unsafe to use this manager and a different source
+   * manager serially with the same JPEG object.  Caveat programmer.
+   */
+  if (cinfo->src == NULL) {     /* first time for this JPEG object? */
+    cinfo->src = (struct jpeg_source_mgr *)
+      (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
+                                  SIZEOF(my_source_mgr));
+    src = (my_src_ptr) cinfo->src;
+    src->buffer = NULL;
+  }
+
+  src = (my_src_ptr) cinfo->src;
+  src->pub.init_source = linit_source;
+  src->pub.fill_input_buffer = lfill_input_buffer;
+  src->pub.skip_input_data = lskip_input_data;
+  src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */
+  src->pub.term_source = lterm_source;
+  src->userdata=userdata;
+  src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */
+  src->pub.next_input_byte = NULL; /* until buffer loaded */
+  src->offset=0;
+  src->userdata=userdata;
+  if (src->buffer) {
+     free(src->buffer);
+     src->buffer=NULL;
+     }
+}
+/* cleanup to be called before cleanup of cinfo*/
+extern "C" void
+jpeg_memio_cleanup (j_decompress_ptr cinfo) {
+  my_src_ptr src=(my_src_ptr)cinfo->src;
+  Log::getInstance()->log("BJpeg", Log::DEBUG, "cleanup src, src=%p, buf=%p",src,(src?src->buffer:0));
+  if (src && src->buffer) {
+    free(src->buffer);
+    src->buffer=NULL;
+    }
+}
+
+//taken from mvpmc
+//http://git.mvpmc.org/cgi-bin/gitweb.cgi?p=mvpmc.git;a=blob_plain;h=02d4354c0cbbed802a9aa1478918a49fcbf61d00;f=libs/libwidget/image_jpeg.c
+
+#define GET2BYTES(cinfo, V, swap, offset) do { \
+                if (cinfo->src->bytes_in_buffer == 0) (*mysrc->pub.fill_input_buffer)(cinfo); \
+                cinfo->src->bytes_in_buffer--; \
+                V = (*cinfo->src->next_input_byte++) << (swap?0:8); \
+                if (cinfo->src->bytes_in_buffer == 0) (*mysrc->pub.fill_input_buffer)(cinfo); \
+                cinfo->src->bytes_in_buffer--; \
+                V += (*cinfo->src->next_input_byte++) << (swap?8:0); \
+                offset += 2; } while(0) 
+
+#define GET4BYTES(cinfo, V, swap, offset) do { \
+                if (cinfo->src->bytes_in_buffer == 0) (*mysrc->pub.fill_input_buffer)(cinfo); \
+                cinfo->src->bytes_in_buffer--; \
+                V = (*cinfo->src->next_input_byte++) << (swap?0:24); \
+                if (cinfo->src->bytes_in_buffer == 0) (*mysrc->pub.fill_input_buffer)(cinfo); \
+                cinfo->src->bytes_in_buffer--; \
+                V += (*cinfo->src->next_input_byte++) << (swap?8:16); \
+                if (cinfo->src->bytes_in_buffer == 0) (*mysrc->pub.fill_input_buffer)(cinfo); \
+                cinfo->src->bytes_in_buffer--; \
+                V += (*cinfo->src->next_input_byte++) << (swap?16:8); \
+                if (cinfo->src->bytes_in_buffer == 0) (*mysrc->pub.fill_input_buffer)(cinfo); \
+                cinfo->src->bytes_in_buffer--; \
+                V += (*cinfo->src->next_input_byte++) << (swap?24:0); \
+                offset += 4; } while(0)
+
+static boolean
+get_exif_orient (j_decompress_ptr cinfo)
+/* Get the Exif orientation info */
+{
+        unsigned int tmp, offset, length, numtags;
+        int orient=-1;
+        jpegUserData * ud=0;
+        boolean swap;
+        orient = 1;
+        offset = 0;
+        my_src_ptr mysrc = (my_src_ptr) cinfo->src;
+
+        /* marker length */
+        GET2BYTES(cinfo, length, 0, offset);
+        if (length<8) goto err;
+        /* Exif header */
+        GET4BYTES(cinfo, tmp, 0, offset);
+        if (tmp != 0x45786966) goto err;
+        GET2BYTES(cinfo, tmp, 0, offset);
+        if (tmp != 0x0000) goto err;
+        /* Byte-order */
+        GET2BYTES(cinfo, tmp, 0, offset);
+        if (tmp == 0x4949) swap = 1;
+        else if (tmp == 0x4d4d) swap = 0;
+        else goto err;
+        GET2BYTES(cinfo, tmp, swap, offset);
+        if (tmp != 0x002A) goto err;
+        /* offset to first IFD */
+        GET4BYTES(cinfo, tmp, swap, offset);
+        offset += tmp-8;
+        (*mysrc->pub.skip_input_data)(cinfo, tmp-8);
+        /* number of tags in IFD */
+        GET2BYTES(cinfo, numtags, swap, offset);
+        if (numtags == 0) goto err;
+        
+        /* Search for Orientation Tag in IFD0 */
+        for (;;) {
+                if (offset > length-12) goto err;
+                GET2BYTES(cinfo, tmp, swap, offset);
+                if (tmp == 0x0112) break; /* found Orientation Tag */
+                if (--numtags == 0) goto err;
+                offset += 10;
+                (*mysrc->pub.skip_input_data)(cinfo, 10);
+        }
+        offset += 6;
+        (*mysrc->pub.skip_input_data)(cinfo, 6);
+        GET2BYTES(cinfo, orient, swap, offset);
+        if( orient==0 || orient>8 ) orient = 1;
+        
+        Log::getInstance()->log("WJpeg", Log::DEBUG, "read exif orientation %u", orient);
+        ud=(jpegUserData *)(mysrc->userdata);
+        switch(orient) {
+          case 3:
+            ud->ctl->exifRotation=WJpegComplex::ROT_180;
+            break;
+          case 6:
+            ud->ctl->exifRotation=WJpegComplex::ROT_90;
+            break;
+          case 8:
+            ud->ctl->exifRotation=WJpegComplex::ROT_270;
+            break;
+        }
+
+err:
+        (*mysrc->pub.skip_input_data)(cinfo, length-offset);
+        return TRUE;
+}
+}
+#endif
+/*----------------------------------------------------------------
+  the implementation
+  ----------------------------------------------------------------
+ */
+
+
+WJpegComplex::WJpegComplex(){
+  reader=NULL;
+  owningReader=false;
+  errbuf[0]=0;
+}
+
+WJpegComplex::~WJpegComplex() {
+  if (owningReader && reader) delete reader;
+}
+
+int WJpegComplex::init(const char* tfileName)
+{
+  if (owningReader && reader) delete reader;
+  errbuf[0]=0; //clean error state
+  LocalReader *myreader=new LocalReader();
+  reader=myreader;
+  owningReader=true;
+  ULONG psize=myreader->initRead(tfileName);
+  if (psize == 0) {
+    delete reader;
+    reader=NULL;
+    owningReader=false;
+    SNPRINTF(errbuf,200,"unable to open %s",tfileName);
+    return 0;
+  }
+  return 1;
+}
+
+
+
+
+bool WJpegComplex::hasError() {
+  return (errbuf[0] != 0);
+}
+void WJpegComplex::draw()
+{
+  bool ok=false;
+  JpegControl ctl;
+  if (reader) {
+    Region myRegion;
+    Surface *sfc=getSurface(myRegion);
+    myRegion.w=area.w;
+    myRegion.h=area.h;
+    ctl.area=myRegion;
+    ctl.enlarge=true;
+    if (drawJpeg(&ctl,sfc,reader,backgroundColour) ) ok=true;
+  }
+  else {
+    SNPRINTF(errbuf,200,"jpeg reader not initialized");
+  }
+  if (! ok) {
+    drawTextCentre(tr("Jpeg ERROR"), 240, 170, DrawStyle::LIGHTTEXT);
+    if (errbuf[0] != 0) drawTextCentre(errbuf,240,200, DrawStyle::LIGHTTEXT);
+    if (ctl.error[0] != 0) drawTextCentre(ctl.error,240,230, DrawStyle::LIGHTTEXT);
+  }
+}
+
+
+
+/**
+  the main drawing function
+  this will read the pciture via the reader
+  and draw directly into the surface
+  it will compute an appropriate scale and set the infos in the
+  JpegControl structure
+**/  
+
+#ifndef __ANDROID__
+
+bool WJpegComplex::drawJpeg(JpegControl * ctl,Surface * sfc,JpegReader *rdr, DrawStyle & backgroundColour) {
+  Log* logger = Log::getInstance();
+  if (! rdr || ! sfc) {
+    logger->log("BJpeg", Log::ERR, "JPEG error rdr=NULL or sfc=NULL");
+    return false;
+  }
+  logger->log("BJpeg", Log::DEBUG, "draw Jpeg Started sfc=%p, rdr=%p",sfc,rdr);
+  unsigned char* buffer =NULL;
+  struct jpeg_decompress_struct cinfo;
+  struct my_error_mgr jerr;
+  cinfo.err = jpeg_std_error(&jerr.pub);
+  jerr.pub.error_exit = my_error_exit;
+  /* Establish the setjmp return context for my_error_exit to use. */
+  if (setjmp(jerr.setjmp_buffer)) {
+    /* If we get here, the JPEG code has signaled an error.
+     * We need to clean up the JPEG object, close the input file, and return.
+     */
+    if (rdr) jpeg_memio_cleanup(&cinfo);
+    jpeg_destroy_decompress(&cinfo);
+    logger->log("BJpeg", Log::ERR, "JPEG error");
+    if (buffer) free(buffer);
+    return false;
+  }
+  jpegUserData userdata;
+  int xpos=0;
+  int ypos=0;
+  jpeg_create_decompress(&cinfo);
+  userdata.reader=rdr;
+  userdata.ctl=ctl;
+  ctl->exifRotation=ROT_0;
+  ctl->error[0]=0;
+  ctl->exifDate[0]=0;
+  //create the input for the jpeg lib
+  jpeg_memio_src(&cinfo,(void *)(&userdata));
+  //processor for EXIF data
+  jpeg_set_marker_processor(&cinfo, JPEG_APP0+1, get_exif_orient);
+  //read in header info
+  jpeg_read_header(&cinfo, TRUE);
+  ctl->picw=cinfo.image_width;
+  ctl->pich=cinfo.image_height;
+  ctl->compressedSize=rdr->getSize();
+  //now we have important info available in ctl (pictuerw,h, exif orientation,size)
+  //compute rotation due to the defined enum values we can simply add them
+  ctl->finalRotation=(enum Rotation)((ctl->rotation+ctl->exifRotation)%4);
+  logger->log("BJpeg", Log::DEBUG, "JPEG read header w=%i h=%i, rot=%i", ctl->picw,ctl->pich,ctl->finalRotation);
+  //now we have to compute the scale
+  //input: ctl->picw,ctl->pich,ctl->finalRotation,ctl->mode,ctl->scaleAmount, ctl->scaleafter
+  //       list of available jpeg scale factors
+  //out:   scalenum,scaledenom,scaleafter
+
+  UINT picturew=ctl->picw;
+  UINT pictureh=ctl->pich;
+  switch (ctl->finalRotation){
+    case ROT_90:
+    case ROT_270:
+      pictureh=ctl->picw;
+      picturew=ctl->pich;
+      break;
+    default:
+      break;
+  }
+  UINT scalenum=1;
+  UINT scaledenom=1;
+  UINT scaleafter=1;
+  if (! ctl->enlarge) {
+    //scale - compute the factors to fit 100%
+    int scalew=1000*picturew/ctl->area.w;
+    int scaleh=1000*pictureh/ctl->area.h;
+    int scale=scaleh;
+    if (scalew > scaleh) scale=scalew;
+
+    //OK now find out which is the optimal setting
+    //rule: find settings being nearest to:
+    //   mode=LETTER - smaller or equal screen size (i.e. scale*scalefactor <= 1000)
+    //   mode=CROP   - bigger or equal screen size (i.e. scale *scalefactor>= 1000)
+    //   mode=CROPPERCENT - smaller or equal screensize*scaleamount (i.e. scale*scalefactor<= 1000*scaleamount)
+    //                      scaleamount is in % - so in reality we use scaleamount*10 instead scaleamount*1000
+    //the scalefactor computes as scalenum/(scaledenom*scaleafter)
+    scaledenom=8;
+    int minDiff=1000;
+    logger->log("BJpeg", Log::DEBUG, "start scaling screenw=%u, screenh=%u, pw=%u,ph=%u, scale=%d, mode=%d, %%=%u, after=%u",
+       ctl->area.w,ctl->area.h,picturew,pictureh,scale,(int)ctl->mode,ctl->scaleAmount, ctl->scaleafter); 
+    for (UINT j=0;j<sizeof(jpegFactors)/sizeof(jpegFactors[0]);j++) {
+      for (UINT sa=1;sa<=ctl->scaleafter;sa++) {
+        int curf=(scale*jpegFactors[j].num)/(jpegFactors[j].denom*sa);
+        bool setThis=false;
+        logger->log("BJpeg", Log::DEBUG, "testing scale curf=%d,num=%u,denom=%u,after=%u,minDiff=%d", 
+            curf,jpegFactors[j].num,jpegFactors[j].denom,sa,minDiff);
+        switch(ctl->mode) {
+          case CROP:
+            if (curf >= 1000 && curf < (minDiff +1000)) {
+              setThis=true;
+              minDiff=curf-1000;
+            }
+            break;
+          case LETTER:
+            if (curf <= 1000 && curf > (1000-minDiff)) {
+              setThis=true;
+              minDiff=1000-curf;
+            }
+            break;
+          case CROPPERCENT:
+            if (curf <= 10*(int)ctl->scaleAmount ) {
+              int abs=curf-1000;
+              if (abs < 0) abs=-abs;
+              if (abs < minDiff) {
+                   setThis=true;
+                   minDiff=abs;
+              }
+            }
+            break;
+        }
+        if (setThis) {
+          logger->log("BJpeg", Log::DEBUG, "testing scale curf=%d,take this",curf);
+          scalenum=jpegFactors[j].num;
+          scaledenom=jpegFactors[j].denom;
+          scaleafter=sa;
+        }
+      }
+    }
+    ctl->scale=100*scalenum/(scaledenom*scaleafter);
+
+    logger->log("BJpeg", Log::DEBUG, "JPEG scaling found scale=%i num=%i denom=%i after=%i result=%i scale=%i%% ",
+        scale,scalenum,scaledenom,scaleafter,scale*ctl->scale/100,ctl->scale);
+
+    cinfo.scale_denom=scaledenom;
+    cinfo.scale_num=scalenum;
+    }
+  else
+  {
+    //set drawing area according to picture
+    ctl->area.w=ctl->picw;
+    ctl->area.h=ctl->pich;
+  }
+
+  //now we know the scaling
+  //compute the scaled size and position
+
+  jpeg_start_decompress(&cinfo);
+  //picturew/h is now the output width from the decompressor and afterscaler
+  //this is unrotated 
+  picturew=cinfo.output_width;
+  pictureh=cinfo.output_height;
+  if (scaleafter > 1) {
+    picturew=picturew/scaleafter;
+    pictureh=pictureh/scaleafter;
+  }
+  //if our image is smaller - center it
+  if (! ctl->enlarge) {
+    if (ctl->finalRotation == ROT_90 || ctl->finalRotation == ROT_270) {
+      int dim=pictureh;
+      xpos=(((int)ctl->area.w)-dim)/2;
+      dim=picturew;
+      ypos=(((int)ctl->area.h)-dim)/2;
+    } else {
+      int dim=picturew;
+      xpos=(((int)ctl->area.w)-dim)/2;
+      dim=pictureh;
+      ypos=(((int)ctl->area.h)-dim)/2;
+    }
+    if (xpos <0) xpos=0;
+    if (ypos <0) ypos=0;
+  }
+  xpos+=ctl->area.x;
+  ypos+=ctl->area.y;
+  //remember the jpeg dimensions for computing the buffer
+  UINT jpegwidth=cinfo.output_width;
+  UINT jpegheight=cinfo.output_height;
+  logger->log("BJpeg", Log::DEBUG, "JPEG startup done pw=%i ph=%i, xo=%i,yo=%i, jw=%i, jh=%i, rot=%d", 
+      picturew, pictureh,xpos,ypos,jpegwidth,jpegheight,(int)ctl->finalRotation*90);
+
+  //fill the background
+  sfc->fillblt(ctl->area.x,ctl->area.y,ctl->area.w,ctl->area.h,backgroundColour);
+
+  //line len in bytes (3 bytes per Pixel) - for buffer (can be bigger then surface)
+  int linelen=jpegwidth*3;
+#ifdef USE_BUFFER
+  // MAKE THE 2D ARRAY
+  buffer = (unsigned char*)malloc(jpegheight * linelen);
+  logger->log("BJpeg", Log::DEBUG, "Buffer allocated at %p, lines = %i linelen = %i", buffer, jpegheight, linelen);
+  if (buffer == NULL) {
+    if (rdr) jpeg_memio_cleanup(&cinfo);
+    jpeg_destroy_decompress(&cinfo);
+    logger->log("BJpeg", Log::ERR, "JPEG error - no room for buffer");
+    SNPRINTF(ctl->error,100,"no room for buffer");
+    return false;
+  }
+#endif
+
+#ifndef USE_BUFFER
+  //unsigned char lbuf[linelen];
+  unsigned char *lbuf=new unsigned char[linelen*scaleafter];
+  unsigned char * ptr=lbuf;
+  UINT outy=0;
+#else
+  unsigned char * ptr=buffer;
+#endif
+
+  int rowsread = 0;
+
+  DrawStyle c;
+  sfc->startFastDraw();//Tell the surface, that we will draw a lot of pixel,
+  //so that performance, can be optimized
+  logger->log("BJpeg", Log::DEBUG, "start drawing ");
+  UINT colincr=0;
+  //factors to base 1024
+  UINT fac=1024;
+  if (scaleafter > 1) {
+     colincr=3*scaleafter-3;
+     fac=1024/(scaleafter*scaleafter);
+     }
+  logger->log("BJpeg", Log::DEBUG, "jpeg  draw scale %d image: %u %u, picture: %u %u", scaleafter,picturew,pictureh,jpegwidth,jpegheight);
+  while (cinfo.output_scanline < jpegheight)
+  {
+//  logger->log("BJpeg", Log::DEBUG, "%i", rowsread);
+    rowsread += jpeg_read_scanlines(&cinfo,&ptr,1);
+#ifdef USE_BUFFER
+    ptr+=linelen;
+#else
+    if (scaleafter > 1) {
+      if (rowsread % scaleafter != scaleafter-1) {
+        //this simple approach wold maybe forget scaleafter -1 lines at the end...
+        ptr+=linelen;
+        continue;
+      }
+      ptr=lbuf;
+    }
+    drawLine(sfc,ctl->finalRotation,ptr,scaleafter,picturew,pictureh,xpos,ypos,outy,linelen,colincr,scaleafter,fac);
+    outy++;
+    
+#endif
+  }
+  sfc->endFastDraw();
+
+  logger->log("BJpeg", Log::DEBUG, "Done all jpeg_read");
+
+  jpeg_finish_decompress(&cinfo);
+  jpeg_memio_cleanup(&cinfo);
+  jpeg_destroy_decompress(&cinfo);
+
+  logger->log("BJpeg", Log::DEBUG, "jpeg shutdown done");
+  rdr->drawingDone();
+
+#ifdef USE_BUFFER
+  UINT y;
+  //Tell the surface, that we will draw a lot of pixel,
+  //so that performance, can be optimized
+  sfc->startFastDraw();
+  logger->log("BJpeg", Log::DEBUG, "jpeg start buffer draw" );
+  unsigned char* p=buffer; //start of first row
+  UINT rowincr=linelen*scaleafter;
+  //for simplicity omit last line to avoid running out of buffer
+  for (y = 0; y < pictureh-1 ;y++)
+  {
+    drawLine(sfc,ctl->finalRotation,p,scaleafter,picturew,pictureh,xpos,ypos,y,linelen,colincr,scaleafter,fac);
+    p+=rowincr;
+  }
+  sfc->endFastDraw();
+  logger->log("BJpeg", Log::DEBUG, "end draw");
+  free(buffer);
+#else
+  delete[] lbuf;
+#endif
+  logger->log("BJpeg", Log::DEBUG, "deleted buffer");
+  return true;
+}
+
+
+#else
+bool WJpegComplex::drawJpeg(JpegControl * ctl,Surface * sfc,JpegReader *rdr, DrawStyle & backgroundColour) {
+       return true;
+}
+#endif
+
+//get my own surface
+Surface * WJpegComplex::getSurface(Region & r) {
+  r.x=getRootBoxOffsetX();
+  r.y=getRootBoxOffsetY();
+  r.w=area.w;
+  r.h=area.h;
+  return Boxx::getSurface();
+}
+
index c0956f39aedd714ef1a57630acd92e583d67817c..64ad624f7fd9f90ddf1d3f39ac6445a6a4f7d77e 100644 (file)
-/*\r
-    Copyright 2004-2005 Chris Tallon\r
-\r
-    This file is part of VOMP.\r
-\r
-    VOMP is free software; you can redistribute it and/or modify\r
-    it under the terms of the GNU General Public License as published by\r
-    the Free Software Foundation; either version 2 of the License, or\r
-    (at your option) any later version.\r
-\r
-    VOMP is distributed in the hope that it will be useful,\r
-    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-    GNU General Public License for more details.\r
-\r
-    You should have received a copy of the GNU General Public License\r
-    along with VOMP; if not, write to the Free Software\r
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
-*/\r
-\r
-#ifndef WJPEGCOMPLEX_H\r
-#define WJPEGCOMPLEX_H\r
-\r
-// This is the complex jpeg readeing stuff not supported on all plattforms\r
-\r
-\r
-#include <stdio.h>\r
-#include <malloc.h>\r
-\r
-#include "wjpeg.h"\r
-\r
-#ifdef WIN32\r
-\r
-#include <winsock2.h>\r
-#include <windows.h>\r
-\r
-\r
-//#define NEED_FAR_POINTERS\r
-#define XMD_H //workaround some compiling issues\r
-#endif\r
-\r
-class Surface;\r
-class Boxx;\r
-\r
-//a reader to be implemented by the caller\r
-class JpegReader {\r
-  public:\r
-  //read the next chunk of jpeg data\r
-  //offset - from start of file\r
-  //len I buf len (max bytes to read)\r
-  //return read len, 0 on EOF, -1 on error, *buf set to buffer\r
-  //will be released with free(!!!) after decoding\r
-  virtual ULONG readChunk(ULONG offset,ULONG len,char **buf)=0;\r
-  //a callback when the drawing is complete\r
-  //the implementation is optional\r
-  virtual void drawingDone(){};\r
-  //get the size of the current picture\r
-  virtual ULONG getSize(){ return 0;}\r
-  virtual ~JpegReader(){};\r
-};\r
-class WJpegComplex : public WJpeg\r
-{\r
-  public:\r
-  \r
-    // temp for boxx\r
-    void setDimensions(int width, int height) {area.w=width;area.h=height;};\r
-  \r
-  \r
-    WJpegComplex();\r
-    virtual ~WJpegComplex();\r
-    //old style usage - load local file\r
-    //the sequence is init(filename), draw\r
-    //the new usage is drawJpeg (with having the right offsets computed)\r
-    int init(const char* fileName);\r
-    void draw();\r
-\r
-    bool hasError();\r
-    \r
-    //mode for scaling pictures\r
-    enum ScaleMode {\r
-        LETTER=0,\r
-        CROP=1,\r
-        CROPPERCENT=2};\r
-    //rotations\r
-    enum Rotation{\r
-     ROT_0=0,\r
-     ROT_90=1,\r
-     ROT_180=2,\r
-     ROT_270=3\r
-    };\r
-    //jpeg info \r
-    struct JpegControl {\r
-      public:\r
-      //the available drawing area\r
-      Region area;\r
-      bool enlarge;\r
-      //the maximum allowed scale factor after decompress\r
-      UINT scaleafter;\r
-      //the scale mode\r
-      enum ScaleMode mode;\r
-      //the size value if scaleMode==cropPercent\r
-      //%of the drawing area size\r
-      UINT  scaleAmount;\r
-      //the rotation (user defined as input)\r
-      //if exif rotation is found this will be added\r
-      enum Rotation rotation;\r
-\r
-      //paremeters filled during Jpeg parsing\r
-      enum Rotation exifRotation;\r
-      char exifDate[30];\r
-      char error[100];\r
-      UINT picw;\r
-      UINT pich;\r
-      ULONG compressedSize;\r
-\r
-      //parameters computed to display picture\r
-      enum Rotation finalRotation;\r
-      //scale in %\r
-      UINT scale;\r
-      JpegControl() {\r
-        area.x=0;\r
-        area.y=0;\r
-        area.w=0;\r
-        area.h=0;\r
-        enlarge=false;\r
-        scaleafter=3;\r
-        scaleAmount=110;\r
-        mode=CROPPERCENT;\r
-        rotation=ROT_0;\r
-        exifRotation=ROT_0;\r
-        finalRotation=ROT_0;\r
-        exifDate[0]='\0';\r
-        error[0]='\0';\r
-        picw=0;\r
-        pich=0;\r
-        compressedSize=0;\r
-        scale=100;\r
-      }\r
-    };\r
-\r
-    //the standalone drawing function\r
-    //this will draw into the provided surface\r
-    //the reader has to be initialized before\r
-    //calling this function does not need a WJpeg being instantiated\r
-    //it simply draws into the surface\r
-    bool static drawJpeg(JpegControl * control, Surface* sfc, JpegReader *rdr, DrawStyle & backgroundColour);\r
-\r
-  private:\r
-    //our drawPixel with considers rotation\r
-    /* handle picture rotation\r
-       90: xr=h-y\r
-           yr=x\r
-       180:xr=w-x\r
-           yr=h-y\r
-       270:xr=y\r
-           yr=w-x\r
-    */\r
-#ifndef __ANDROID__\r
-    inline static void  drawPixel(Surface * sfc,enum Rotation rotate,int x, int y,int w,int h,int xpos, int ypos,Colour c){\r
-    int xb=0;\r
-    int yb=0;\r
-    switch(rotate) {\r
-       case ROT_0:\r
-          xb=x;\r
-          yb=y;\r
-          break;\r
-       case ROT_90:\r
-          xb=h-y;\r
-          yb=x;\r
-          break;\r
-       case ROT_180:\r
-          xb=w-x;\r
-          yb=h-y;\r
-          break;\r
-       case ROT_270:\r
-          xb=y;\r
-          yb=w-x;\r
-          break;\r
-       }\r
-       xb+=xpos;\r
-       yb+=ypos;\r
-       if (xb < 0 || yb < 0 ) {\r
-         return;\r
-       }\r
-       sfc->drawPixel((UINT)xb,(UINT)yb,c,true);\r
-    }\r
-\r
-    /**\r
-      draw a line of pixels coming from the decompressor\r
-      if scaleafter > 1 we draw that many lines (numlines is the# lines in the buffer)\r
-      picturew is the resulting width of the picture\r
-    **/  \r
-    inline static void drawLine(Surface *sfc,enum Rotation rotate, unsigned char *cp,UINT scaleafter,UINT picturew,UINT pictureh, \r
-        UINT xpos, UINT ypos, UINT outy, UINT linelen,UINT pixeloffset, UINT numlines, UINT fac) {\r
-      Colour c;\r
-      for (UINT x = 0; x < picturew; x++)\r
-      {\r
-        if (scaleafter > 1 ) {\r
-           //boxfilter scalefactor*scalefactor\r
-           //take 0...scalefactor pixels in x and y direction\r
-           for (int colornum=0;colornum<3;colornum++) {\r
-             UINT comp=0;\r
-             unsigned char * accp=cp;\r
-             for (UINT rows=0;rows<scaleafter;rows++) {\r
-               unsigned char * pp=accp;\r
-               for (UINT cols=0;cols<scaleafter;cols++) {\r
-                 comp+=(UINT)*pp;\r
-                 if (pp-accp < (int)linelen-3) pp+=3;\r
-                 }\r
-               if (rows < numlines) accp+=linelen;\r
-               }\r
-             comp=(comp*fac) >> 10;\r
-             if (colornum == 0) c.red=comp;\r
-             if (colornum == 1) c.green=comp;\r
-             if (colornum == 2) c.blue=comp;\r
-             cp++;\r
-           }\r
-          \r
-        }\r
-        else {\r
-          c.red = *cp;cp++;\r
-          c.green = *cp;cp++;\r
-          c.blue = *cp;cp++;\r
-        }\r
-        cp+=pixeloffset;\r
-        drawPixel(sfc,rotate,x, outy, picturew,pictureh,xpos,ypos,c);\r
-      }\r
-    }\r
-#endif\r
-    //find my own surface and fill the area with my x and y offset within\r
-    Surface * getSurface(Region &a);\r
-\r
-    JpegReader *reader;\r
-    bool owningReader;\r
-    char errbuf[200];\r
-};\r
-\r
-#endif\r
+/*
+    Copyright 2004-2005 Chris Tallon
+
+    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 WJPEGCOMPLEX_H
+#define WJPEGCOMPLEX_H
+
+// This is the complex jpeg readeing stuff not supported on all plattforms
+
+
+#include <stdio.h>
+#include <malloc.h>
+
+#include "wjpeg.h"
+
+#ifdef WIN32
+
+#include <winsock2.h>
+#include <windows.h>
+
+
+//#define NEED_FAR_POINTERS
+#define XMD_H //workaround some compiling issues
+#endif
+
+class Surface;
+class Boxx;
+
+//a reader to be implemented by the caller
+class JpegReader {
+  public:
+  //read the next chunk of jpeg data
+  //offset - from start of file
+  //len I buf len (max bytes to read)
+  //return read len, 0 on EOF, -1 on error, *buf set to buffer
+  //will be released with free(!!!) after decoding
+  virtual ULONG readChunk(ULONG offset,ULONG len,char **buf)=0;
+  //a callback when the drawing is complete
+  //the implementation is optional
+  virtual void drawingDone(){};
+  //get the size of the current picture
+  virtual ULONG getSize(){ return 0;}
+  virtual ~JpegReader(){};
+};
+class WJpegComplex : public WJpeg
+{
+  public:
+  
+    // temp for boxx
+    void setDimensions(int width, int height) {area.w=width;area.h=height;};
+  
+  
+    WJpegComplex();
+    virtual ~WJpegComplex();
+    //old style usage - load local file
+    //the sequence is init(filename), draw
+    //the new usage is drawJpeg (with having the right offsets computed)
+    int init(const char* fileName);
+    void draw();
+
+    bool hasError();
+    
+    //mode for scaling pictures
+    enum ScaleMode {
+        LETTER=0,
+        CROP=1,
+        CROPPERCENT=2};
+    //rotations
+    enum Rotation{
+     ROT_0=0,
+     ROT_90=1,
+     ROT_180=2,
+     ROT_270=3
+    };
+    //jpeg info 
+    struct JpegControl {
+      public:
+      //the available drawing area
+      Region area;
+      bool enlarge;
+      //the maximum allowed scale factor after decompress
+      UINT scaleafter;
+      //the scale mode
+      enum ScaleMode mode;
+      //the size value if scaleMode==cropPercent
+      //%of the drawing area size
+      UINT  scaleAmount;
+      //the rotation (user defined as input)
+      //if exif rotation is found this will be added
+      enum Rotation rotation;
+
+      //paremeters filled during Jpeg parsing
+      enum Rotation exifRotation;
+      char exifDate[30];
+      char error[100];
+      UINT picw;
+      UINT pich;
+      ULONG compressedSize;
+
+      //parameters computed to display picture
+      enum Rotation finalRotation;
+      //scale in %
+      UINT scale;
+      JpegControl() {
+        area.x=0;
+        area.y=0;
+        area.w=0;
+        area.h=0;
+        enlarge=false;
+        scaleafter=3;
+        scaleAmount=110;
+        mode=CROPPERCENT;
+        rotation=ROT_0;
+        exifRotation=ROT_0;
+        finalRotation=ROT_0;
+        exifDate[0]='\0';
+        error[0]='\0';
+        picw=0;
+        pich=0;
+        compressedSize=0;
+        scale=100;
+      }
+    };
+
+    //the standalone drawing function
+    //this will draw into the provided surface
+    //the reader has to be initialized before
+    //calling this function does not need a WJpeg being instantiated
+    //it simply draws into the surface
+    bool static drawJpeg(JpegControl * control, Surface* sfc, JpegReader *rdr, DrawStyle & backgroundColour);
+
+  private:
+    //our drawPixel with considers rotation
+    /* handle picture rotation
+       90: xr=h-y
+           yr=x
+       180:xr=w-x
+           yr=h-y
+       270:xr=y
+           yr=w-x
+    */
+#ifndef __ANDROID__
+    inline static void  drawPixel(Surface * sfc,enum Rotation rotate,int x, int y,int w,int h,int xpos, int ypos,Colour c){
+    int xb=0;
+    int yb=0;
+    switch(rotate) {
+       case ROT_0:
+          xb=x;
+          yb=y;
+          break;
+       case ROT_90:
+          xb=h-y;
+          yb=x;
+          break;
+       case ROT_180:
+          xb=w-x;
+          yb=h-y;
+          break;
+       case ROT_270:
+          xb=y;
+          yb=w-x;
+          break;
+       }
+       xb+=xpos;
+       yb+=ypos;
+       if (xb < 0 || yb < 0 ) {
+         return;
+       }
+       sfc->drawPixel((UINT)xb,(UINT)yb,c,true);
+    }
+
+    /**
+      draw a line of pixels coming from the decompressor
+      if scaleafter > 1 we draw that many lines (numlines is the# lines in the buffer)
+      picturew is the resulting width of the picture
+    **/  
+    inline static void drawLine(Surface *sfc,enum Rotation rotate, unsigned char *cp,UINT scaleafter,UINT picturew,UINT pictureh, 
+        UINT xpos, UINT ypos, UINT outy, UINT linelen,UINT pixeloffset, UINT numlines, UINT fac) {
+      Colour c;
+      for (UINT x = 0; x < picturew; x++)
+      {
+        if (scaleafter > 1 ) {
+           //boxfilter scalefactor*scalefactor
+           //take 0...scalefactor pixels in x and y direction
+           for (int colornum=0;colornum<3;colornum++) {
+             UINT comp=0;
+             unsigned char * accp=cp;
+             for (UINT rows=0;rows<scaleafter;rows++) {
+               unsigned char * pp=accp;
+               for (UINT cols=0;cols<scaleafter;cols++) {
+                 comp+=(UINT)*pp;
+                 if (pp-accp < (int)linelen-3) pp+=3;
+                 }
+               if (rows < numlines) accp+=linelen;
+               }
+             comp=(comp*fac) >> 10;
+             if (colornum == 0) c.red=comp;
+             if (colornum == 1) c.green=comp;
+             if (colornum == 2) c.blue=comp;
+             cp++;
+           }
+          
+        }
+        else {
+          c.red = *cp;cp++;
+          c.green = *cp;cp++;
+          c.blue = *cp;cp++;
+        }
+        cp+=pixeloffset;
+        drawPixel(sfc,rotate,x, outy, picturew,pictureh,xpos,ypos,c);
+      }
+    }
+#endif
+    //find my own surface and fill the area with my x and y offset within
+    Surface * getSurface(Region &a);
+
+    JpegReader *reader;
+    bool owningReader;
+    char errbuf[200];
+};
+
+#endif
index 04095d14d78d0d9208cf58cfe82de15bf9a8aa99..d94be69a1fa953315906c170628bc2636ccd7637 100644 (file)
@@ -1,66 +1,66 @@
-/*\r
-    Copyright 2004-2005 Chris Tallon\r
-\r
-    This file is part of VOMP.\r
-\r
-    VOMP is free software; you can redistribute it and/or modify\r
-    it under the terms of the GNU General Public License as published by\r
-    the Free Software Foundation; either version 2 of the License, or\r
-    (at your option) any later version.\r
-\r
-    VOMP is distributed in the hope that it will be useful,\r
-    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-    GNU General Public License for more details.\r
-\r
-    You should have received a copy of the GNU General Public License\r
-    along with VOMP; if not, write to the Free Software\r
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
-*/\r
-#include "boxx.h"\r
-#include "wjpegsimple.h"\r
-#include <setjmp.h>\r
-#include <sys/types.h>\r
-#include <sys/stat.h>\r
-\r
-\r
-\r
-#include "i18n.h"\r
-#include "log.h"\r
-#include "surface.h"\r
-\r
-\r
-\r
-\r
-WJpegSimple::WJpegSimple(){\r
-\r
-}\r
-\r
-WJpegSimple::~WJpegSimple() {\r
-\r
-}\r
-\r
-int WJpegSimple::init(const char* tfileName)\r
-{\r
-       fileName=tfileName;\r
-\r
-  return 1;\r
-}\r
-\r
-\r
-\r
-\r
-\r
-void WJpegSimple::draw()\r
-{\r
-         int width,height;\r
-         width=height=1;\r
-         drawJpeg(fileName,0,0,&width,&height);//This should went into the abstract base classes?\r
-         //Windows has a problem with the leading / fixme\r
-         setDimensions(width, height);\r
-\r
-}\r
-\r
-\r
-\r
-\r
+/*
+    Copyright 2004-2005 Chris Tallon
+
+    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 "boxx.h"
+#include "wjpegsimple.h"
+#include <setjmp.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+
+
+#include "i18n.h"
+#include "log.h"
+#include "surface.h"
+
+
+
+
+WJpegSimple::WJpegSimple(){
+
+}
+
+WJpegSimple::~WJpegSimple() {
+
+}
+
+int WJpegSimple::init(const char* tfileName)
+{
+       fileName=tfileName;
+
+  return 1;
+}
+
+
+
+
+
+void WJpegSimple::draw()
+{
+         int width,height;
+         width=height=1;
+         drawJpeg(fileName,0,0,&width,&height);//This should went into the abstract base classes?
+         //Windows has a problem with the leading / fixme
+         setDimensions(width, height);
+
+}
+
+
+
+
index 21bf4dc06233588027848280461da65c8355122f..980a699d968b389d16ffad869f30a53ee9a43278 100644 (file)
@@ -1,50 +1,50 @@
-/*\r
-    Copyright 2004-2005 Chris Tallon\r
-\r
-    This file is part of VOMP.\r
-\r
-    VOMP is free software; you can redistribute it and/or modify\r
-    it under the terms of the GNU General Public License as published by\r
-    the Free Software Foundation; either version 2 of the License, or\r
-    (at your option) any later version.\r
-\r
-    VOMP is distributed in the hope that it will be useful,\r
-    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-    GNU General Public License for more details.\r
-\r
-    You should have received a copy of the GNU General Public License\r
-    along with VOMP; if not, write to the Free Software\r
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
-*/\r
-\r
-#ifndef WJPEGSIMPLE_H\r
-#define WJPEGSIMPLE_H\r
-\r
-#include <stdio.h>\r
-#include <malloc.h>\r
-#include "wjpeg.h"\r
-\r
-\r
-class WJpegSimple : public WJpeg\r
-{\r
-public:\r
-  \r
-    // temp for boxx\r
-    void setDimensions(int width, int height) {area.w=width;area.h=height;};\r
-  \r
-  \r
-    WJpegSimple();\r
-    virtual ~WJpegSimple();\r
-    // Only old style usage - load local file\r
-\r
-    int init(const char* fileName);\r
-    void draw();\r
-\r
-private:\r
-   const char* fileName;\r
-\r
-\r
-};\r
-\r
-#endif\r
+/*
+    Copyright 2004-2005 Chris Tallon
+
+    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 WJPEGSIMPLE_H
+#define WJPEGSIMPLE_H
+
+#include <stdio.h>
+#include <malloc.h>
+#include "wjpeg.h"
+
+
+class WJpegSimple : public WJpeg
+{
+public:
+  
+    // temp for boxx
+    void setDimensions(int width, int height) {area.w=width;area.h=height;};
+  
+  
+    WJpegSimple();
+    virtual ~WJpegSimple();
+    // Only old style usage - load local file
+
+    int init(const char* fileName);
+    void draw();
+
+private:
+   const char* fileName;
+
+
+};
+
+#endif
index 9707b9948358179abbb6a0e110c7d532de1dc55e..3c9b0a0843c54deb48d9f169fe4b6e17a39f5173 100644 (file)
-/*\r
-    Copyright 2004-2005 Chris Tallon\r
-\r
-    This file is part of VOMP.\r
-\r
-    VOMP is free software; you can redistribute it and/or modify\r
-    it under the terms of the GNU General Public License as published by\r
-    the Free Software Foundation; either version 2 of the License, or\r
-    (at your option) any later version.\r
-\r
-    VOMP is distributed in the hope that it will be useful,\r
-    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-    GNU General Public License for more details.\r
-\r
-    You should have received a copy of the GNU General Public License\r
-    along with VOMP; if not, write to the Free Software\r
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
-*/\r
-\r
-#include "wselectlist.h"\r
-\r
-#include "colour.h"\r
-#include "log.h"\r
-\r
-WSelectList::WSelectList():\r
-backgroundColour(DrawStyle::VIEWBACKGROUND)\r
-{\r
-  selectedOption = 0;\r
-  topOption = 0;\r
-  numOptionsDisplayable = 0;\r
-  numColumns = 0;\r
-  noLoop = 0;\r
-  gap = 1;\r
-  showseloption = true;\r
-  darkseloption = false;\r
-\r
-}\r
-\r
-WSelectList::~WSelectList()\r
-{\r
-  clear();\r
-}\r
-\r
-void WSelectList::clear()\r
-{\r
-  int vsize = options.size();\r
-  for (int i = 0; i < vsize; i++)\r
-  {\r
-    delete[] options[i].text;\r
-  }\r
-  options.clear();\r
-\r
-  selectedOption = 0;\r
-  topOption = 0;\r
-  numOptionsDisplayable = 0;\r
-  numColumns = 0;\r
-}\r
-\r
-void WSelectList::setNoLoop()\r
-{\r
-  noLoop = 1;\r
-}\r
-\r
-void WSelectList::setBackgroundColour(const DrawStyle& colour)\r
-{\r
-  backgroundColour = colour;\r
-}\r
-\r
-void WSelectList::hintSetCurrent(int idx)\r
-{\r
-  selectedOption = idx;\r
-  if (selectedOption >= options.size()) selectedOption = options.size() - 1;\r
-}\r
-\r
-void WSelectList::hintSetTop(int idx)\r
-{\r
-  topOption = idx;\r
-}\r
-\r
-int WSelectList::addOption(const char* text, ULONG data, int selected)\r
-{\r
-  int thisNewOption = options.size();\r
-\r
-  wsloption wslo;\r
-  wslo.text = new char[strlen(text) + 1];\r
-  strcpy(wslo.text, text);\r
-  wslo.data = data;\r
-  options.push_back(wslo);\r
-  if (selected) selectedOption = thisNewOption;\r
-  return thisNewOption;\r
-}\r
-\r
-void WSelectList::draw()\r
-{\r
-  int fontHeight = getFontHeight();\r
-  int ySeperation = fontHeight + gap;\r
-\r
-  numOptionsDisplayable = (area.h - 5) / ySeperation;\r
-\r
-  if (selectedOption == (topOption + numOptionsDisplayable)) topOption++;\r
-  if (selectedOption == ((UINT)topOption - 1)) topOption--;\r
-  // if still not visible...\r
-  if ((selectedOption < (UINT)topOption) || (selectedOption > (topOption + numOptionsDisplayable)))\r
-  {\r
-    topOption = selectedOption - (numOptionsDisplayable / 2);\r
-  }\r
-\r
-  if (topOption < 0) topOption = 0;\r
-\r
-\r
-  fillColour(backgroundColour);\r
-\r
-  UINT ypos = 5;\r
-  for (UINT i = topOption; i < (topOption + numOptionsDisplayable); i++)\r
-  {\r
-    if (i == options.size()) return;\r
-    if ((ypos + ySeperation) > area.h) break;\r
-\r
-    if (i == selectedOption && showseloption)\r
-    {\r
-\r
-      rectangle(0, ypos, area.w, fontHeight, darkseloption ? DrawStyle::SELECTDARKHIGHLIGHT: DrawStyle::SELECTHIGHLIGHT);\r
-\r
-      drawOptionLine(options[i].text, 5, ypos, area.w - 5, DrawStyle::DARKTEXT);\r
-    }\r
-    else\r
-    {\r
-\r
-      drawOptionLine(options[i].text, 5, ypos, area.w - 5, DrawStyle::LIGHTTEXT);\r
-    }\r
-    ypos += ySeperation;\r
-  }\r
-\r
-}\r
-\r
-void WSelectList::addColumn(int x)\r
-{\r
-  if (numColumns == 10) return;\r
-  columns[numColumns++] = x;\r
-}\r
-\r
-void WSelectList::drawOptionLine(char* text, int xpos, int ypos, int width, const DrawStyle& colour)\r
-{\r
-  if (!numColumns)\r
-  {\r
-\r
-    drawText(text, xpos, ypos, width, colour);\r
-  }\r
-  else\r
-  {\r
-    char buffer[200];\r
-    strncpy(buffer, text, 199);\r
-    int currentColumn = 0;\r
-    char* pointer;\r
-\r
-    pointer = strtok(buffer, "\t");\r
-    while(pointer)\r
-    {\r
-\r
-      drawText(pointer, xpos + columns[currentColumn], ypos, width - columns[currentColumn], colour);\r
-\r
-      currentColumn++;\r
-      if (currentColumn == 10) return;\r
-      pointer = strtok(NULL, "\t");\r
-    }\r
-  }\r
-}\r
-\r
-void WSelectList::up()\r
-{\r
-  if (selectedOption > 0)\r
-  {\r
-    selectedOption--;\r
-  }\r
-  else\r
-  {\r
-    if (!noLoop) selectedOption = options.size() - 1;\r
-  }\r
-}\r
-\r
-void WSelectList::down()\r
-{\r
-  if (selectedOption < options.size() - 1)\r
-  {\r
-    selectedOption++;\r
-  }\r
-  else\r
-  {\r
-    if (!noLoop) selectedOption = 0;\r
-  }\r
-}\r
-\r
-void WSelectList::pageUp()\r
-{\r
-  topOption -= numOptionsDisplayable;\r
-  if (topOption < 0) topOption = 0;\r
-\r
-  selectedOption = topOption;\r
-}\r
-\r
-void WSelectList::pageDown()\r
-{\r
-  if ((topOption + numOptionsDisplayable) >= options.size())\r
-  {\r
-    selectedOption = options.size() - 1;\r
-  }\r
-  else\r
-  {\r
-    topOption += numOptionsDisplayable;\r
-    selectedOption = topOption;\r
-  }\r
-}\r
-\r
-int WSelectList::getTopOption()\r
-{\r
-  return topOption;\r
-}\r
-\r
-int WSelectList::getNumOptions()\r
-{\r
-  return options.size();\r
-}\r
-\r
-int WSelectList::getBottomOption()\r
-{\r
-  UINT retval = topOption + numOptionsDisplayable;\r
-  if (retval > options.size()) return options.size();\r
-  else return retval;\r
-}\r
-\r
-int WSelectList::getCurrentOption()\r
-{\r
-  return selectedOption;\r
-}\r
-\r
-ULONG WSelectList::getCurrentOptionData()\r
-{\r
-  if (!options.size()) return 0;\r
-  return options[selectedOption].data;\r
-}\r
-\r
-bool WSelectList::mouseAndroidScroll(int x, int y,int sx, int sy)\r
-{\r
-/*     int fontHeight = getFontHeight();\r
-       int movelines= sy/fontHeight;\r
-\r
-       int seloption=selectedOption+movelines;\r
-       if (seloption<0) seloption=0;\r
-       else if (seloption>options.size()-1) seloption=options.size()-1;\r
-       selectedOption=seloption;*/\r
-\r
-}\r
-\r
-bool WSelectList::mouseMove(int x, int y)\r
-{\r
-  int ml = getMouseLine(x-getRootBoxOffsetX(), y-getRootBoxOffsetY());\r
-  if (ml>=0 && ml!=(int)selectedOption)\r
-  {\r
-    selectedOption = ml;\r
-    return true;\r
-  }\r
-  return false;\r
-}\r
-\r
-bool WSelectList::mouseLBDOWN(int x, int y)\r
-{\r
-  int ml = getMouseLine(x-getRootBoxOffsetX(), y-getRootBoxOffsetY());\r
-  if (ml == (int)selectedOption)\r
-  {\r
-    /* caller should generate a OK message*/\r
-    return true;\r
-  }\r
-  return false;\r
-}\r
-\r
-int WSelectList::getMouseLine(int x,int y)\r
-{\r
-  int fontHeight = getFontHeight();\r
-  int ySeperation = fontHeight + gap;\r
-\r
-  if (y<0) return -1;\r
-  if (x<0 || x>(int)area.w) return -1;\r
-  if (y>(int)(10+numOptionsDisplayable*ySeperation)) return -1;\r
-\r
-  int cy = y - 5;\r
-\r
-  int selected=cy/ySeperation;\r
-  if (y<5) selected=-1;\r
-  if (selected> ((int)numOptionsDisplayable)) return -1;\r
-  /* Important: should be the same algorithm used in draw! */\r
-  if (selectedOption == (topOption + numOptionsDisplayable)) topOption++;\r
-  if (selectedOption == ((UINT)topOption - 1)) topOption--;\r
-  // if still not visible...\r
-  if ((selectedOption < (UINT)topOption) || (selectedOption > (topOption + numOptionsDisplayable)))\r
-  {\r
-    topOption = selectedOption - (numOptionsDisplayable / 2);\r
-  }\r
-\r
-  if (topOption < 0) topOption = 0;\r
-\r
-  if ((selected+topOption >= (int) options.size()) ||\r
-      (selected + topOption < 0)) return -1;\r
-\r
-  return selected + topOption;\r
-}\r
+/*
+    Copyright 2004-2005 Chris Tallon
+
+    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 "wselectlist.h"
+
+#include "colour.h"
+#include "log.h"
+
+WSelectList::WSelectList():
+backgroundColour(DrawStyle::VIEWBACKGROUND)
+{
+  selectedOption = 0;
+  topOption = 0;
+  numOptionsDisplayable = 0;
+  numColumns = 0;
+  noLoop = 0;
+  gap = 1;
+  showseloption = true;
+  darkseloption = false;
+
+}
+
+WSelectList::~WSelectList()
+{
+  clear();
+}
+
+void WSelectList::clear()
+{
+  int vsize = options.size();
+  for (int i = 0; i < vsize; i++)
+  {
+    delete[] options[i].text;
+  }
+  options.clear();
+
+  selectedOption = 0;
+  topOption = 0;
+  numOptionsDisplayable = 0;
+  numColumns = 0;
+}
+
+void WSelectList::setNoLoop()
+{
+  noLoop = 1;
+}
+
+void WSelectList::setBackgroundColour(const DrawStyle& colour)
+{
+  backgroundColour = colour;
+}
+
+void WSelectList::hintSetCurrent(int idx)
+{
+  selectedOption = idx;
+  if (selectedOption >= options.size()) selectedOption = options.size() - 1;
+}
+
+void WSelectList::hintSetTop(int idx)
+{
+  topOption = idx;
+}
+
+int WSelectList::addOption(const char* text, ULONG data, int selected)
+{
+  int thisNewOption = options.size();
+
+  wsloption wslo;
+  wslo.text = new char[strlen(text) + 1];
+  strcpy(wslo.text, text);
+  wslo.data = data;
+  options.push_back(wslo);
+  if (selected) selectedOption = thisNewOption;
+  return thisNewOption;
+}
+
+void WSelectList::draw()
+{
+  int fontHeight = getFontHeight();
+  int ySeperation = fontHeight + gap;
+
+  numOptionsDisplayable = (area.h - 5) / ySeperation;
+
+  if (selectedOption == (topOption + numOptionsDisplayable)) topOption++;
+  if (selectedOption == ((UINT)topOption - 1)) topOption--;
+  // if still not visible...
+  if ((selectedOption < (UINT)topOption) || (selectedOption > (topOption + numOptionsDisplayable)))
+  {
+    topOption = selectedOption - (numOptionsDisplayable / 2);
+  }
+
+  if (topOption < 0) topOption = 0;
+
+
+  fillColour(backgroundColour);
+
+  UINT ypos = 5;
+  for (UINT i = topOption; i < (topOption + numOptionsDisplayable); i++)
+  {
+    if (i == options.size()) return;
+    if ((ypos + ySeperation) > area.h) break;
+
+    if (i == selectedOption && showseloption)
+    {
+
+      rectangle(0, ypos, area.w, fontHeight, darkseloption ? DrawStyle::SELECTDARKHIGHLIGHT: DrawStyle::SELECTHIGHLIGHT);
+
+      drawOptionLine(options[i].text, 5, ypos, area.w - 5, DrawStyle::DARKTEXT);
+    }
+    else
+    {
+
+      drawOptionLine(options[i].text, 5, ypos, area.w - 5, DrawStyle::LIGHTTEXT);
+    }
+    ypos += ySeperation;
+  }
+
+}
+
+void WSelectList::addColumn(int x)
+{
+  if (numColumns == 10) return;
+  columns[numColumns++] = x;
+}
+
+void WSelectList::drawOptionLine(char* text, int xpos, int ypos, int width, const DrawStyle& colour)
+{
+  if (!numColumns)
+  {
+
+    drawText(text, xpos, ypos, width, colour);
+  }
+  else
+  {
+    char buffer[200];
+    strncpy(buffer, text, 199);
+    int currentColumn = 0;
+    char* pointer;
+
+    pointer = strtok(buffer, "\t");
+    while(pointer)
+    {
+
+      drawText(pointer, xpos + columns[currentColumn], ypos, width - columns[currentColumn], colour);
+
+      currentColumn++;
+      if (currentColumn == 10) return;
+      pointer = strtok(NULL, "\t");
+    }
+  }
+}
+
+void WSelectList::up()
+{
+  if (selectedOption > 0)
+  {
+    selectedOption--;
+  }
+  else
+  {
+    if (!noLoop) selectedOption = options.size() - 1;
+  }
+}
+
+void WSelectList::down()
+{
+  if (selectedOption < options.size() - 1)
+  {
+    selectedOption++;
+  }
+  else
+  {
+    if (!noLoop) selectedOption = 0;
+  }
+}
+
+void WSelectList::pageUp()
+{
+  topOption -= numOptionsDisplayable;
+  if (topOption < 0) topOption = 0;
+
+  selectedOption = topOption;
+}
+
+void WSelectList::pageDown()
+{
+  if ((topOption + numOptionsDisplayable) >= options.size())
+  {
+    selectedOption = options.size() - 1;
+  }
+  else
+  {
+    topOption += numOptionsDisplayable;
+    selectedOption = topOption;
+  }
+}
+
+int WSelectList::getTopOption()
+{
+  return topOption;
+}
+
+int WSelectList::getNumOptions()
+{
+  return options.size();
+}
+
+int WSelectList::getBottomOption()
+{
+  UINT retval = topOption + numOptionsDisplayable;
+  if (retval > options.size()) return options.size();
+  else return retval;
+}
+
+int WSelectList::getCurrentOption()
+{
+  return selectedOption;
+}
+
+ULONG WSelectList::getCurrentOptionData()
+{
+  if (!options.size()) return 0;
+  return options[selectedOption].data;
+}
+
+bool WSelectList::mouseAndroidScroll(int x, int y,int sx, int sy)
+{
+/*     int fontHeight = getFontHeight();
+       int movelines= sy/fontHeight;
+
+       int seloption=selectedOption+movelines;
+       if (seloption<0) seloption=0;
+       else if (seloption>options.size()-1) seloption=options.size()-1;
+       selectedOption=seloption;*/
+
+}
+
+bool WSelectList::mouseMove(int x, int y)
+{
+  int ml = getMouseLine(x-getRootBoxOffsetX(), y-getRootBoxOffsetY());
+  if (ml>=0 && ml!=(int)selectedOption)
+  {
+    selectedOption = ml;
+    return true;
+  }
+  return false;
+}
+
+bool WSelectList::mouseLBDOWN(int x, int y)
+{
+  int ml = getMouseLine(x-getRootBoxOffsetX(), y-getRootBoxOffsetY());
+  if (ml == (int)selectedOption)
+  {
+    /* caller should generate a OK message*/
+    return true;
+  }
+  return false;
+}
+
+int WSelectList::getMouseLine(int x,int y)
+{
+  int fontHeight = getFontHeight();
+  int ySeperation = fontHeight + gap;
+
+  if (y<0) return -1;
+  if (x<0 || x>(int)area.w) return -1;
+  if (y>(int)(10+numOptionsDisplayable*ySeperation)) return -1;
+
+  int cy = y - 5;
+
+  int selected=cy/ySeperation;
+  if (y<5) selected=-1;
+  if (selected> ((int)numOptionsDisplayable)) return -1;
+  /* Important: should be the same algorithm used in draw! */
+  if (selectedOption == (topOption + numOptionsDisplayable)) topOption++;
+  if (selectedOption == ((UINT)topOption - 1)) topOption--;
+  // if still not visible...
+  if ((selectedOption < (UINT)topOption) || (selectedOption > (topOption + numOptionsDisplayable)))
+  {
+    topOption = selectedOption - (numOptionsDisplayable / 2);
+  }
+
+  if (topOption < 0) topOption = 0;
+
+  if ((selected+topOption >= (int) options.size()) ||
+      (selected + topOption < 0)) return -1;
+
+  return selected + topOption;
+}
index 72b53e011fb89e3a02ac5cdbed7ea9fd1e66c8aa..bb981311cc9e3364790d8d9d9e93baf4d5bd919b 100644 (file)
@@ -1,90 +1,90 @@
-/*\r
-    Copyright 2004-2005 Chris Tallon\r
-\r
-    This file is part of VOMP.\r
-\r
-    VOMP is free software; you can redistribute it and/or modify\r
-    it under the terms of the GNU General Public License as published by\r
-    the Free Software Foundation; either version 2 of the License, or\r
-    (at your option) any later version.\r
-\r
-    VOMP is distributed in the hope that it will be useful,\r
-    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-    GNU General Public License for more details.\r
-\r
-    You should have received a copy of the GNU General Public License\r
-    along with VOMP; if not, write to the Free Software\r
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
-*/\r
-\r
-#ifndef WSELECTLIST_H\r
-#define WSELECTLIST_H\r
-\r
-#include <stdio.h>\r
-#include <string.h>\r
-\r
-#include <vector>\r
-\r
-#include "defines.h"\r
-#include "boxx.h"\r
-\r
-using namespace std;\r
-\r
-typedef struct\r
-{\r
-  char* text;\r
-  ULONG data;\r
-} wsloption;\r
-\r
-class WSelectList : public Boxx\r
-{\r
-  public:\r
-    WSelectList();\r
-    virtual ~WSelectList();\r
-    void clear();\r
-    void addColumn(int x);\r
-\r
-    void setNoLoop();\r
-    void setShowSelOption(bool set) { showseloption = set; };\r
-    void setDarkSelOption(bool set) { darkseloption = set; };\r
-    int addOption(const char* text, ULONG data, int selected);\r
-    void draw();\r
-    void setBackgroundColour(const DrawStyle& colour);\r
-\r
-    void down();\r
-    void up();\r
-    void pageUp();\r
-    void pageDown();\r
-\r
-    int getTopOption();\r
-    int getNumOptions();\r
-    int getBottomOption();     // actually returns bottom + 1 i.e. the one just past display ?!\r
-    int getCurrentOption();\r
-    ULONG getCurrentOptionData();\r
-\r
-    void hintSetCurrent(int index);\r
-    void hintSetTop(int index);\r
-\r
-    virtual bool mouseMove(int x, int y);\r
-    virtual bool mouseLBDOWN(int x, int y);\r
-    virtual bool mouseAndroidScroll(int x, int y,int sx, int sy);\r
-\r
-  private:\r
-    void drawOptionLine(char* text, int xpos, int ypos, int width, const DrawStyle& colour);\r
-    int getMouseLine(int x, int y);\r
-\r
-    vector<wsloption> options;\r
-    UINT selectedOption;\r
-    int topOption;\r
-    UINT numOptionsDisplayable;\r
-    int columns[10];\r
-    int numColumns;\r
-    int noLoop;\r
-    bool showseloption, darkseloption;\r
-    \r
-    UINT gap;\r
-    DrawStyle backgroundColour;\r
-};\r
-\r
-#endif\r
+/*
+    Copyright 2004-2005 Chris Tallon
+
+    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 WSELECTLIST_H
+#define WSELECTLIST_H
+
+#include <stdio.h>
+#include <string.h>
+
+#include <vector>
+
+#include "defines.h"
+#include "boxx.h"
+
+using namespace std;
+
+typedef struct
+{
+  char* text;
+  ULONG data;
+} wsloption;
+
+class WSelectList : public Boxx
+{
+  public:
+    WSelectList();
+    virtual ~WSelectList();
+    void clear();
+    void addColumn(int x);
+
+    void setNoLoop();
+    void setShowSelOption(bool set) { showseloption = set; };
+    void setDarkSelOption(bool set) { darkseloption = set; };
+    int addOption(const char* text, ULONG data, int selected);
+    void draw();
+    void setBackgroundColour(const DrawStyle& colour);
+
+    void down();
+    void up();
+    void pageUp();
+    void pageDown();
+
+    int getTopOption();
+    int getNumOptions();
+    int getBottomOption();     // actually returns bottom + 1 i.e. the one just past display ?!
+    int getCurrentOption();
+    ULONG getCurrentOptionData();
+
+    void hintSetCurrent(int index);
+    void hintSetTop(int index);
+
+    virtual bool mouseMove(int x, int y);
+    virtual bool mouseLBDOWN(int x, int y);
+    virtual bool mouseAndroidScroll(int x, int y,int sx, int sy);
+
+  private:
+    void drawOptionLine(char* text, int xpos, int ypos, int width, const DrawStyle& colour);
+    int getMouseLine(int x, int y);
+
+    vector<wsloption> options;
+    UINT selectedOption;
+    int topOption;
+    UINT numOptionsDisplayable;
+    int columns[10];
+    int numColumns;
+    int noLoop;
+    bool showseloption, darkseloption;
+    
+    UINT gap;
+    DrawStyle backgroundColour;
+};
+
+#endif