From 46a6feb1ecb29df686b3ccf49d437f73123e8116 Mon Sep 17 00:00:00 2001 From: Marten Richter Date: Mon, 5 Nov 2012 08:11:01 +0100 Subject: [PATCH] Normalize line endings --- vopts.cc | 938 ++++++++--------- vradiorec.cc | 1094 ++++++++++---------- vrecording.cc | 776 +++++++-------- vrecordinglist.cc | 1096 ++++++++++---------- vteletextview.cc | 420 ++++---- vteletextview.h | 128 +-- vtimerlist.cc | 784 +++++++-------- vvideolivetv.cc | 2434 ++++++++++++++++++++++----------------------- vvideomedia.cc | 1568 ++++++++++++++--------------- vvideorec.cc | 2206 ++++++++++++++++++++-------------------- vwelcome.cc | 712 ++++++------- wbutton.cc | 222 ++--- wjpeg.cc | 120 +-- wjpeg.h | 118 +-- wjpegcomplex.cc | 1784 ++++++++++++++++----------------- wjpegcomplex.h | 476 ++++----- wjpegsimple.cc | 132 +-- wjpegsimple.h | 100 +- wselectlist.cc | 612 ++++++------ wselectlist.h | 180 ++-- 20 files changed, 7950 insertions(+), 7950 deletions(-) diff --git a/vopts.cc b/vopts.cc index 3ea90a4..64920d3 100644 --- a/vopts.cc +++ b/vopts.cc @@ -1,469 +1,469 @@ -/* - 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::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 - } - } -} - +/* + 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::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 + } + } +} + diff --git a/vradiorec.cc b/vradiorec.cc index 566274e..1dc28a7 100644 --- a/vradiorec.cc +++ b/vradiorec.cc @@ -1,547 +1,547 @@ -/* - 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); -} - +/* + 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); +} + diff --git a/vrecording.cc b/vrecording.cc index c3b2461..b285061 100644 --- a/vrecording.cc +++ b/vrecording.cc @@ -1,388 +1,388 @@ -/* - 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); - } -} - +/* + 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); + } +} + diff --git a/vrecordinglist.cc b/vrecordinglist.cc index 5e872c6..0426ae8 100644 --- a/vrecordinglist.cc +++ b/vrecordinglist.cc @@ -1,548 +1,548 @@ -/* - 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(" %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); -} - +/* + 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(" %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); +} + diff --git a/vteletextview.cc b/vteletextview.cc index 113bf6b..de95dc1 100644 --- a/vteletextview.cc +++ b/vteletextview.cc @@ -1,210 +1,210 @@ -/* - 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 -#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); - - } -} - - +/* + 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 +#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); + + } +} + + diff --git a/vteletextview.h b/vteletextview.h index af3b5c9..01bf5e0 100644 --- a/vteletextview.h +++ b/vteletextview.h @@ -1,64 +1,64 @@ -/* - 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 - -#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 +/* + 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 + +#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 diff --git a/vtimerlist.cc b/vtimerlist.cc index 2cc3558..58e0501 100644 --- a/vtimerlist.cc +++ b/vtimerlist.cc @@ -1,392 +1,392 @@ -/* - 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); - } -} - +/* + 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); + } +} + diff --git a/vvideolivetv.cc b/vvideolivetv.cc index 69e8a49..4c2f1be 100644 --- a/vvideolivetv.cc +++ b/vvideolivetv.cc @@ -1,1217 +1,1217 @@ -/* - 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(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(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(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(player))->turnSubtitlesOn(false); - VTeletextView *vtxt=((PlayerLiveTV*)player)->getTeletextDecoder()->getTeletxtView(); - if (vtxt && vtxt->isInSubtitleMode()) { - BoxStack::getInstance()->remove(vtxt); - } - } - } break; - case 0x11: { //videotext - (static_cast(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); -} +/* + 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(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(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(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(player))->turnSubtitlesOn(false); + VTeletextView *vtxt=((PlayerLiveTV*)player)->getTeletextDecoder()->getTeletxtView(); + if (vtxt && vtxt->isInSubtitleMode()) { + BoxStack::getInstance()->remove(vtxt); + } + } + } break; + case 0x11: { //videotext + (static_cast(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); +} diff --git a/vvideomedia.cc b/vvideomedia.cc index f4b069e..6f97b59 100644 --- a/vvideomedia.cc +++ b/vvideomedia.cc @@ -1,784 +1,784 @@ -/* - 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; -} - - +/* + 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; +} + + diff --git a/vvideorec.cc b/vvideorec.cc index 56142bb..654bc77 100644 --- a/vvideorec.cc +++ b/vvideorec.cc @@ -1,1107 +1,1107 @@ -/* - 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 - -#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) - { +/* + 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 + +#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: - { - 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::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: - { - 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::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: - { - player->fastForward(); - doBar(0); - return 2; - } + case Remote::FORWARD: + { + player->fastForward(); + doBar(0); + return 2; + } case Remote::LEFT: - 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;inumAPids;i++) { - apid *ac=&temp_channel->apids[i]; - if (ac->desc[0]==0) { - strncpy(ac->desc, tr("unknown"),9); - } - } - for (i=0;inumDPids;i++) { - apid *ac=&temp_channel->dpids[i]; - if (ac->desc[0]==0) { - strncpy(ac->desc, tr("unknown"),9); - } - } - for (i=0;inumSPids;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;iname; - ac->name=NULL; - } - for (i=0;iname; - ac->name=NULL; - } - for (i=0;iname; - 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); -} + 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;inumAPids;i++) { + apid *ac=&temp_channel->apids[i]; + if (ac->desc[0]==0) { + strncpy(ac->desc, tr("unknown"),9); + } + } + for (i=0;inumDPids;i++) { + apid *ac=&temp_channel->dpids[i]; + if (ac->desc[0]==0) { + strncpy(ac->desc, tr("unknown"),9); + } + } + for (i=0;inumSPids;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;iname; + ac->name=NULL; + } + for (i=0;iname; + ac->name=NULL; + } + for (i=0;iname; + 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); +} diff --git a/vwelcome.cc b/vwelcome.cc index d7b032c..ee6e044 100644 --- a/vwelcome.cc +++ b/vwelcome.cc @@ -1,356 +1,356 @@ -/* - 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 - } - } -} +/* + 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 + } + } +} diff --git a/wbutton.cc b/wbutton.cc index 40d74e2..eed4a37 100644 --- a/wbutton.cc +++ b/wbutton.cc @@ -1,111 +1,111 @@ -/* - 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; -} +/* + 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; +} diff --git a/wjpeg.cc b/wjpeg.cc index 6e0993b..7c76678 100644 --- a/wjpeg.cc +++ b/wjpeg.cc @@ -1,60 +1,60 @@ -/* - 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 -#include -#include - -#ifndef WIN32 -#include -#else - -#endif - -#include "i18n.h" -#include "log.h" -#include "surface.h" - - -/*---------------------------------------------------------------- - the implementation - ---------------------------------------------------------------- - */ - - -WJpeg::WJpeg(){ - -} - -WJpeg::~WJpeg() { -} - - - - - - -void WJpeg::draw() -{ - -} - - +/* + 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 +#include +#include + +#ifndef WIN32 +#include +#else + +#endif + +#include "i18n.h" +#include "log.h" +#include "surface.h" + + +/*---------------------------------------------------------------- + the implementation + ---------------------------------------------------------------- + */ + + +WJpeg::WJpeg(){ + +} + +WJpeg::~WJpeg() { +} + + + + + + +void WJpeg::draw() +{ + +} + + diff --git a/wjpeg.h b/wjpeg.h index b52931a..88be763 100644 --- a/wjpeg.h +++ b/wjpeg.h @@ -1,59 +1,59 @@ -/* - 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 -#include -#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 +/* + 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 +#include +#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 diff --git a/wjpegcomplex.cc b/wjpegcomplex.cc index 7b15168..e96ccf2 100644 --- a/wjpegcomplex.cc +++ b/wjpegcomplex.cc @@ -1,892 +1,892 @@ -/* - 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 -#include -#include - -#ifndef WIN32 -#include -#else - -#endif - -#include "i18n.h" -#include "log.h" -#include "surface.h" - -#ifndef __ANDROID__ -extern "C" -{ - #include -} -#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;jscaleafter;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(); -} - +/* + 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 +#include +#include + +#ifndef WIN32 +#include +#else + +#endif + +#include "i18n.h" +#include "log.h" +#include "surface.h" + +#ifndef __ANDROID__ +extern "C" +{ + #include +} +#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;jscaleafter;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(); +} + diff --git a/wjpegcomplex.h b/wjpegcomplex.h index c0956f3..64ad624 100644 --- a/wjpegcomplex.h +++ b/wjpegcomplex.h @@ -1,238 +1,238 @@ -/* - 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 -#include - -#include "wjpeg.h" - -#ifdef WIN32 - -#include -#include - - -//#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> 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 +/* + 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 +#include + +#include "wjpeg.h" + +#ifdef WIN32 + +#include +#include + + +//#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> 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 diff --git a/wjpegsimple.cc b/wjpegsimple.cc index 04095d1..d94be69 100644 --- a/wjpegsimple.cc +++ b/wjpegsimple.cc @@ -1,66 +1,66 @@ -/* - 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 -#include -#include - - - -#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); - -} - - - - +/* + 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 +#include +#include + + + +#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); + +} + + + + diff --git a/wjpegsimple.h b/wjpegsimple.h index 21bf4dc..980a699 100644 --- a/wjpegsimple.h +++ b/wjpegsimple.h @@ -1,50 +1,50 @@ -/* - 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 -#include -#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 +/* + 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 +#include +#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 diff --git a/wselectlist.cc b/wselectlist.cc index 9707b99..3c9b0a0 100644 --- a/wselectlist.cc +++ b/wselectlist.cc @@ -1,306 +1,306 @@ -/* - 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; -} +/* + 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; +} diff --git a/wselectlist.h b/wselectlist.h index 72b53e0..bb98131 100644 --- a/wselectlist.h +++ b/wselectlist.h @@ -1,90 +1,90 @@ -/* - 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 -#include - -#include - -#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 options; - UINT selectedOption; - int topOption; - UINT numOptionsDisplayable; - int columns[10]; - int numColumns; - int noLoop; - bool showseloption, darkseloption; - - UINT gap; - DrawStyle backgroundColour; -}; - -#endif +/* + 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 +#include + +#include + +#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 options; + UINT selectedOption; + int topOption; + UINT numOptionsDisplayable; + int columns[10]; + int numColumns; + int noLoop; + bool showseloption, darkseloption; + + UINT gap; + DrawStyle backgroundColour; +}; + +#endif -- 2.39.2