-/*\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
+ }
+ }
+}
+
-/*\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);
+}
+
-/*\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);
+ }
+}
+
-/*\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);
+}
+
-/*\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);
+
+ }
+}
+
+
-/*\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
-/*\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);
+ }
+}
+
-/*\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);
+}
-/*\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;
+}
+
+
-/*\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);
+}
-/*\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
+ }
+ }
+}
-/*\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;
+}
-/*\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()
+{
+
+}
+
+
-/*\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
-/*\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();
+}
+
-/*\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
-/*\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);
+
+}
+
+
+
+
-/*\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
-/*\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;
+}
-/*\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