Files
recycled-ni-neutrino/src/gui/upnpbrowser.cpp
Thilo Graf a4699de070 CUpnpBrowserGui: block infoclock
Infoclock was not blocked in all modes, e.g. after stopped video
infoclock was unblocked and clock was back on screen. Clock should be now
not visible while upnp browser window is openend.


Origin commit data
------------------
Commit: 2358c6333e
Author: Thilo Graf <dbt@novatux.de>
Date: 2016-03-03 (Thu, 03 Mar 2016)
2016-03-03 09:52:22 +01:00

1272 lines
36 KiB
C++

/*
Neutrino-GUI - DBoxII-Project
UPnP Browser (c) 2007 by Jochen Friedrich
(c) 2009-2011,2016 Stefan Seyfried
(c) 2016 Thilo Graf
License: GPL
This program 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.
This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <sstream>
#include <stdexcept>
#include <global.h>
#include <neutrino.h>
#include <xmlinterface.h>
#include <upnpclient.h>
#include <driver/fontrenderer.h>
#include <driver/rcinput.h>
#include <driver/audioplay.h>
#include <driver/audiofile.h>
#include <driver/audiometadata.h>
#include <driver/screen_max.h>
#include <driver/display.h>
#include <gui/audiomute.h>
#include <gui/color.h>
#include <gui/movieplayer.h>
#include <gui/components/cc.h>
#include <gui/widget/messagebox.h>
#include <gui/widget/hintbox.h>
#include <system/settings.h>
#include <gui/infoclock.h>
#include <gui/upnpbrowser.h>
#include <zapit/zapit.h>
#include <video.h>
extern cVideo * videoDecoder;
extern CPictureViewer * g_PicViewer;
const struct button_label RescanButton = {NEUTRINO_ICON_BUTTON_BLUE , LOCALE_UPNPBROWSER_RESCAN};
const struct button_label BrowseButtons[] =
{
{ NEUTRINO_ICON_BUTTON_RED , LOCALE_FILEBROWSER_NEXTPAGE },
{ NEUTRINO_ICON_BUTTON_GREEN , LOCALE_FILEBROWSER_PREVPAGE },
{ NEUTRINO_ICON_BUTTON_YELLOW, LOCALE_AUDIOPLAYER_STOP },
{ NEUTRINO_ICON_BUTTON_OKAY , LOCALE_AUDIOPLAYER_PLAY },
{ NEUTRINO_ICON_BUTTON_HOME , LOCALE_MENU_BACK, }
};
CUpnpBrowserGui::CUpnpBrowserGui()
{
m_socket = new CUPnPSocket();
m_frameBuffer = CFrameBuffer::getInstance();
m_playing_entry_is_shown = false;
Init();
dline = NULL;
image = NULL;
sigc::slot0<void> reinit = sigc::mem_fun(this, &CUpnpBrowserGui::Init);
CNeutrinoApp::getInstance()->OnAfterSetupFonts.connect(reinit);
CFrameBuffer::getInstance()->OnAfterSetPallette.connect(reinit);
}
void CUpnpBrowserGui::Init()
{
topbox.enableFrame(true, 2);
topbox.setCorner(RADIUS_LARGE);
topbox.setColorAll(COL_MENUCONTENT_PLUS_6, COL_MENUHEAD_PLUS_0, COL_MENUCONTENTDARK_PLUS_0, COL_MENUHEAD_TEXT);
topbox.setTextFont(g_Font[SNeutrinoSettings::FONT_TYPE_MENU_INFO]);
topbox.enableColBodyGradient(g_settings.theme.menu_Head_gradient, COL_INFOBAR_SHADOW_PLUS_1, g_settings.theme.menu_Head_gradient_direction);
ibox.enableFrame(true, 2);
ibox.setCorner(RADIUS_LARGE);
ibox.setColorAll(topbox.getColorFrame(), COL_MENUCONTENTDARK_PLUS_0);
ibox.setTextFont(g_Font[SNeutrinoSettings::FONT_TYPE_EVENTLIST_ITEMLARGE]);
ibox.enableColBodyGradient(g_settings.theme.menu_Hint_gradient, COL_INFOBAR_SHADOW_PLUS_1, g_settings.theme.menu_Hint_gradient_direction);
timebox.enableFrame(true, 2);
timebox.setCorner(RADIUS_LARGE);
timebox.setColorAll(ibox.getColorFrame(), ibox.getColorBody());
timebox.setTextFont(g_Font[SNeutrinoSettings::FONT_TYPE_EVENTLIST_ITEMLARGE]);
timebox.enableColBodyGradient(g_settings.theme.menu_Hint_gradient, COL_INFOBAR_SHADOW_PLUS_1, g_settings.theme.menu_Hint_gradient_direction);
m_width = m_frameBuffer->getScreenWidthRel();
m_height = m_frameBuffer->getScreenHeightRel();
m_sheight = g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL]->getHeight();
m_theight = g_Font[SNeutrinoSettings::FONT_TYPE_MENU_TITLE]->getHeight();
m_buttonHeight = m_theight;
m_mheight = g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getHeight();
m_fheight = g_Font[SNeutrinoSettings::FONT_TYPE_FILEBROWSER_ITEM]->getHeight();
m_title_height = m_mheight*2 + 20 + m_sheight + 4;
m_info_height = m_mheight*2;
m_listmaxshow = (m_height - m_info_height - m_title_height - m_theight - 2*m_buttonHeight) / (m_fheight);
m_height = m_theight + m_info_height + m_title_height + 2*m_buttonHeight + m_listmaxshow * m_fheight; // recalc height
footer.setColorBody(COL_INFOBAR_SHADOW_PLUS_1);
footer.setHeight(m_buttonHeight);
m_x=getScreenStartX(m_width);
if (m_x < ConnectLineBox_Width)
m_x = ConnectLineBox_Width;
m_y=getScreenStartY(m_height);
}
CUpnpBrowserGui::~CUpnpBrowserGui()
{
delete m_socket;
if (dline){
delete dline; dline = NULL;
}
if (image)
delete image, image = NULL;
}
int CUpnpBrowserGui::exec(CMenuTarget* parent, const std::string & /*actionKey*/)
{
CAudioPlayer::getInstance()->init();
if (parent)
parent->hide();
/* stop playback, disable playback start */
CNeutrinoApp::getInstance()->stopPlayBack(true);
m_frameBuffer->showFrame("mp3.jpg");
// tell neutrino we're in upnp mode
CNeutrinoApp::getInstance()->handleMsg(NeutrinoMessages::CHANGEMODE , NeutrinoMessages::mode_upnp);
// remember last mode
m_LastMode=(CNeutrinoApp::getInstance()->getLastMode());
// Stop sectionsd
g_Sectionsd->setPauseScanning(true);
m_deviceliststart=0;
m_selecteddevice=0;
timeout = 0;
selectDevice();
if (CAudioPlayer::getInstance()->getState() != CBaseDec::STOP)
CAudioPlayer::getInstance()->stop();
// Start Sectionsd
g_Sectionsd->setPauseScanning(false);
m_frameBuffer->stopFrame();
m_frameBuffer->Clear();
CZapit::getInstance()->EnablePlayback(true);
CNeutrinoApp::getInstance()->handleMsg(NeutrinoMessages::CHANGEMODE , m_LastMode);
g_RCInput->postMsg(NeutrinoMessages::SHOW_INFOBAR, 0);
return menu_return::RETURN_REPAINT;
}
void CUpnpBrowserGui::splitProtocol(std::string &protocol, std::string &prot, std::string &network, std::string &mime, std::string &additional)
{
std::string::size_type pos;
std::string::size_type startpos = 0;
pos = protocol.find(":", startpos);
if (pos != std::string::npos)
{
prot = protocol.substr(startpos, pos-startpos);
startpos = pos + 1;
pos = protocol.find(":", startpos);
if (pos != std::string::npos)
{
network = protocol.substr(startpos, pos-startpos);
startpos = pos + 1;
pos = protocol.find(":", startpos);
if (pos != std::string::npos)
{
mime = protocol.substr(startpos, pos-startpos);
startpos = pos + 1;
pos = protocol.find(":", startpos);
if (pos != std::string::npos)
{
additional = protocol.substr(startpos, pos-startpos);
}
}
}
}
//printf("%s -> %s - %s - %s - %s\n", protocol.c_str(), prot.c_str(), network.c_str(), mime.c_str(), additional.c_str());
}
bool CUpnpBrowserGui::discoverDevices()
{
if (!m_devices.empty())
return true;
CHintBox *scanBox = new CHintBox(LOCALE_MESSAGEBOX_INFO, g_Locale->getText(LOCALE_UPNPBROWSER_SCANNING)); // UTF-8
scanBox->paint();
try {
m_devices = m_socket->Discover("urn:schemas-upnp-org:service:ContentDirectory:1");
}
catch (std::runtime_error error)
{
delete scanBox;
ShowMsg(LOCALE_MESSAGEBOX_INFO, error.what(), CMessageBox::mbrBack, CMessageBox::mbBack, NEUTRINO_ICON_INFO);
return false;
}
delete scanBox;
if (m_devices.empty())
{
ShowMsg(LOCALE_MESSAGEBOX_INFO, LOCALE_UPNPBROWSER_NOSERVERS, CMessageBox::mbrBack, CMessageBox::mbBack, NEUTRINO_ICON_INFO);
return false;
}
return true;
}
bool CUpnpBrowserGui::getResults(std::string id, unsigned int start, unsigned int count, std::list<UPnPAttribute> &results)
{
std::list<UPnPAttribute>attribs;
std::stringstream sindex;
std::stringstream scount;
sindex << start;
scount << count;
attribs.push_back(UPnPAttribute("ObjectID", id));
attribs.push_back(UPnPAttribute("BrowseFlag", "BrowseDirectChildren"));
attribs.push_back(UPnPAttribute("Filter", "*"));
attribs.push_back(UPnPAttribute("StartingIndex", sindex.str()));
attribs.push_back(UPnPAttribute("RequestedCount", scount.str()));
attribs.push_back(UPnPAttribute("SortCriteria", ""));
try
{
results=m_devices[m_selecteddevice].SendSOAP("urn:schemas-upnp-org:service:ContentDirectory:1", "Browse", attribs);
}
catch (std::runtime_error error)
{
ShowMsg(LOCALE_MESSAGEBOX_INFO, error.what(), CMessageBox::mbrBack, CMessageBox::mbBack, NEUTRINO_ICON_INFO);
return false;
}
return true;
}
std::vector<UPnPEntry> *CUpnpBrowserGui::decodeResult(std::string result)
{
xmlNodePtr root, node, snode;
std::vector<UPnPEntry> *entries;
xmlDocPtr parser = parseXml(result.c_str(),"UTF-8");
root = xmlDocGetRootElement(parser);
if (!root) {
xmlFreeDoc(parser);
return NULL;
}
entries = new std::vector<UPnPEntry>;
for (node=xmlChildrenNode(root); node; node=xmlNextNode(node))
{
bool isdir;
std::string title, artist = "", album = "", albumArtURI = "", id, children;
const char *type, *p;
if (!strcmp(xmlGetName(node), "container"))
{
std::vector<UPnPResource> resources;
isdir=true;
for (snode=xmlChildrenNode(node); snode; snode=xmlNextNode(snode))
{
type=xmlGetName(snode);
p = strchr(type,':');
if (p)
type=p+1;
if (!strcmp(type,"title"))
{
p=xmlGetData(snode);
if (!p)
p = "";
title=std::string(p);
}
}
p = xmlGetAttribute(node, "id");
if (!p)
p = "";
id=std::string(p);
p = xmlGetAttribute(node, "childCount");
if (!p)
p = "";
children=std::string(p);
UPnPEntry entry={id, isdir, title, artist, album, albumArtURI, children, "", "", resources, -1, CFile::FILE_DIR};
entries->push_back(entry);
}
if (!strcmp(xmlGetName(node), "item"))
{
std::vector<UPnPResource> resources;
int preferred = -1;
std::string protocol, prot, network, mime, additional;
CFile::FileType ftype = CFile::FILE_UNKNOWN;
isdir=false;
for (snode=xmlChildrenNode(node); snode; snode=xmlNextNode(snode))
{
std::string duration, url, size;
unsigned int i;
type=xmlGetName(snode);
p = strchr(type,':');
if (p)
type=p+1;
if (!strcmp(type,"title"))
{
p=xmlGetData(snode);
if (!p)
p = "";
title=std::string(p);
}
else if (!strcmp(type,"artist"))
{
p=xmlGetData(snode);
if (!p)
p = "";
artist=std::string(p);
}
else if (!strcmp(type,"album"))
{
p=xmlGetData(snode);
if (!p)
p = "";
album=std::string(p);
}
else if (!strcmp(type,"albumArtURI"))
{
p=xmlGetData(snode);
if (!p)
p = "";
albumArtURI=std::string(p);
}
else if (!strcmp(type,"res"))
{
p = xmlGetData(snode);
if (!p)
p = "";
url=std::string(p);
p = xmlGetAttribute(snode, "size");
if (!p)
p = "0";
size=std::string(p);
p = xmlGetAttribute(snode, "duration");
if (!p)
p = "";
duration=std::string(p);
p = xmlGetAttribute(snode, "protocolInfo");
if (!p)
p = "";
protocol=std::string(p);
UPnPResource resource = {url, protocol, size, duration};
resources.push_back(resource);
}
int pref=0;
preferred=-1;
for (i=0; i<resources.size(); i++)
{
protocol=resources[i].protocol;
splitProtocol(protocol, prot, network, mime, additional);
if (prot != "http-get")
continue;
if (mime.substr(0,6) == "image/" && pref < 1)
{
preferred=i;
}
if (mime == "image/jpeg" && pref < 1)
{
preferred=i;
pref=1;
}
if (mime == "image/gif" && pref < 2)
{
preferred=i;
pref=2;
}
if (mime == "audio/mpeg" && pref < 3)
{
preferred=i;
pref=3;
ftype = CFile::FILE_MP3;
}
if ((mime == "audio/ogg" || mime == "audio/x-ogg") && pref < 4)
{
ftype = CFile::FILE_OGG;
preferred=i;
pref=4;
}
if (mime == "audio/x-flac" && pref < 5)
{
preferred=i;
pref=5;
ftype = CFile::FILE_FLAC;
}
if (mime == "audio/x-wav" && pref < 6)
{
preferred=i;
pref=6;
ftype = CFile::FILE_WAV;
}
if (mime.substr(0,6) == "video/" && pref < 7)
{
preferred=i;
pref=7;
}
if (mime == "video/x-flv" && pref < 8)
{
preferred=i;
pref=8;
}
if (mime == "video/mp4" && pref < 9)
{
preferred=i;
pref=9;
}
}
}
p = xmlGetAttribute(node, "id");
if (!p)
p = "";
id=std::string(p);
p = xmlGetAttribute(node, "childCount");
if (!p)
p = "";
children=std::string(p);
UPnPEntry entry={id, isdir, title, artist, album, albumArtURI, children, prot, mime, resources, preferred, ftype};
entries->push_back(entry);
}
}
xmlFreeDoc(parser);
return entries;
}
void CUpnpBrowserGui::updateDeviceSelection(int newpos)
{
if (newpos < 0) /* do not explode if called with -1 arg... */
return;
if((int) m_selecteddevice != newpos) {
int prev_selected = m_selecteddevice;
unsigned int oldliststart = m_deviceliststart;
m_selecteddevice = newpos;
m_deviceliststart = (m_selecteddevice/m_listmaxshow)*m_listmaxshow;
if (oldliststart != m_deviceliststart)
paintDevices();
else {
paintDevice(prev_selected - m_deviceliststart);
paintDevice(m_selecteddevice - m_deviceliststart);
}
}
}
void CUpnpBrowserGui::selectDevice()
{
bool loop = true;
bool refresh = true;
neutrino_msg_t msg;
neutrino_msg_data_t data;
if (!discoverDevices())
return;
CAudioMute::getInstance()->enableMuteIcon(false);
while (loop)
{
if (refresh)
{
paintDevices();
refresh=false;
}
g_RCInput->getMsg(&msg, &data, 10); // 1 sec timeout to update play/stop state display
neutrino_msg_t msg_repeatok = msg & ~CRCInput::RC_Repeat;
if (msg == CRCInput::RC_timeout)
{
// nothing
}
else if (msg == CRCInput::RC_home)
{
loop=false;
}
else if (msg_repeatok == (neutrino_msg_t) g_settings.key_list_start) {
updateDeviceSelection(0);
}
else if (msg_repeatok == (neutrino_msg_t) g_settings.key_list_end) {
updateDeviceSelection(m_devices.size()-1);
}
else if (msg_repeatok == CRCInput::RC_up || (int)msg == g_settings.key_pageup ||
msg_repeatok == CRCInput::RC_down || (int)msg == g_settings.key_pagedown)
{
int new_selected = UpDownKey(m_devices, msg_repeatok, m_listmaxshow, m_selecteddevice);
updateDeviceSelection(new_selected);
}
else if (msg == CRCInput::RC_right || msg == CRCInput::RC_ok)
{
m_folderplay = false;
selectItem("0");
refresh=true;
}
else if (msg == CRCInput::RC_blue)
{
m_devices.clear();
if (!discoverDevices())
return;
refresh=true;
}
else if (msg == NeutrinoMessages::RECORD_START ||
msg == NeutrinoMessages::ZAPTO ||
msg == NeutrinoMessages::STANDBY_ON ||
msg == NeutrinoMessages::LEAVE_ALL ||
msg == NeutrinoMessages::SHUTDOWN ||
msg == NeutrinoMessages::SLEEPTIMER)
{
loop=false;
g_RCInput->postMsg(msg, data);
}
#if 0
else if (msg == NeutrinoMessages::EVT_TIMER)
{
CNeutrinoApp::getInstance()->handleMsg(msg, data);
}
else if (msg > CRCInput::RC_MaxRC)
#endif
else
{
printf("msg: %x\n", (int) msg);
if (CNeutrinoApp::getInstance()->handleMsg(msg, data) & messages_return::cancel_all)
loop = false;
}
}
CAudioMute::getInstance()->enableMuteIcon(true);
}
void CUpnpBrowserGui::playnext(void)
{
std::vector<UPnPEntry> *entries = NULL;
while (true)
{
timeout = 0;
std::list<UPnPAttribute>results;
std::list<UPnPAttribute>::iterator i;
printf("playnext: getResults m_playfolder %s m_playid %d\n", m_playfolder.c_str(), m_playid);
if (!getResults(m_playfolder, m_playid, 1, results)) {
m_folderplay = false;
return;
}
for (i=results.begin(); i!=results.end(); ++i)
{
if (i->first=="NumberReturned")
{
if (atoi(i->second.c_str()) != 1)
{
m_folderplay = false;
return;
}
}
else if (i->first=="Result")
{
entries=decodeResult(i->second);
}
}
//m_playid++;
if ((entries != NULL) && (!(*entries)[0].isdir))
{
int preferred=(*entries)[0].preferred;
if (preferred != -1)
{
std::string &mime = (*entries)[0].mime;
if (mime.substr(0,6) == "audio/") {
m_playing_entry = (*entries)[0];
m_playing_entry_is_shown = false;
playAudio((*entries)[0].resources[preferred].url, (*entries)[0].type);
}
else if (mime.substr(0,6) == "video/") {
playVideo((*entries)[0].title, (*entries)[0].resources[preferred].url);
m_folderplay = false; // FIXME else no way to stop in video folder
}
else if (mime.substr(0,6) == "image/") {
if (m_folderplay)
timeout = time(NULL) + g_settings.picviewer_slide_time;
showPicture((*entries)[0].resources[preferred].url);
}
return;
}
} else {
neutrino_msg_t msg;
neutrino_msg_data_t data;
g_RCInput->getMsg(&msg, &data, 10); // 1 sec timeout to update play/stop state display
if (msg == CRCInput::RC_home)
{
m_folderplay = false;
break;
}
}
}
delete entries;
m_frameBuffer->Clear();
}
bool CUpnpBrowserGui::getItems(std::string id, unsigned int index, std::vector<UPnPEntry> * &entries, unsigned int &total)
{
bool tfound = false;
bool rfound = false;
bool nfound = false;
unsigned int returned = 0;
std::list<UPnPAttribute>results;
std::list<UPnPAttribute>::iterator i;
delete entries;
entries = NULL;
printf("getItems: getResults: index %d count %d\n", index, m_listmaxshow);
if (!getResults(id, index, m_listmaxshow, results))
return false;
for (i=results.begin(); i!=results.end(); ++i) {
if (i->first=="NumberReturned") {
returned=atoi(i->second.c_str());
nfound=true;
} else if (i->first=="TotalMatches") {
total=atoi(i->second.c_str());
tfound=true;
} else if (i->first=="Result") {
entries=decodeResult(i->second);
rfound=true;
}
}
if (!entries || !nfound || !tfound || !rfound || returned != entries->size() || returned == 0)
return false;
return true;
}
bool CUpnpBrowserGui::updateItemSelection(std::string id, std::vector<UPnPEntry> * &entries, int newpos, unsigned int &selected, unsigned int &liststart)
{
if((int) selected != newpos) {
int prev_selected = selected;
unsigned int oldliststart = liststart;
selected = newpos;
liststart = (selected/m_listmaxshow)*m_listmaxshow;
printf("updateItemSelection: list start old %u new %d selected old %d new %d\n", oldliststart, liststart, prev_selected, selected);
if (oldliststart != liststart) {
unsigned int total;
if (!getItems(id, liststart, entries, total))
return false;
paintItems(entries, selected - liststart, total - liststart, liststart);
} else {
paintItem(entries, prev_selected - liststart, selected - liststart);
paintItem(entries, selected - liststart, selected - liststart);
}
}
return true;
}
bool CUpnpBrowserGui::selectItem(std::string id)
{
bool loop = true;
bool endall = false;
bool refresh = true;
neutrino_msg_t msg;
neutrino_msg_data_t data;
std::vector<UPnPEntry> *entries = NULL;
unsigned int liststart = 0;
unsigned int selected = 0;
unsigned int total = 0;
printf("selectItem: [%s]\n", id.c_str());
if (!getItems(id, liststart, entries, total))
return endall;
while (loop) {
updateTimes();
if (refresh) {
printf("selectItem: refresh, timeout = %d\n", (int) timeout);
if (!timeout)
paintItems(entries, selected - liststart, total - liststart, liststart);
refresh=false;
}
g_RCInput->getMsg(&msg, &data, 10); // 1 sec timeout to update play/stop state display
neutrino_msg_t msg_repeatok = msg & ~CRCInput::RC_Repeat;
if (msg == CRCInput::RC_timeout) {
// nothing
}
else if (msg == CRCInput::RC_home) {
loop=false;
endall=true;
}
else if (!timeout && (msg == CRCInput::RC_left)) {
loop=false;
}
else if (!timeout && (msg_repeatok == (neutrino_msg_t) g_settings.key_list_start)) {
updateItemSelection(id, entries, 0, selected, liststart);
}
else if (!timeout && (msg_repeatok == (neutrino_msg_t) g_settings.key_list_end)) {
updateItemSelection(id, entries, total-1, selected, liststart);
}
else if (!timeout && (msg_repeatok == CRCInput::RC_up || (int) msg == g_settings.key_pageup)) {
int step = ((int) msg == g_settings.key_pageup) ? m_listmaxshow : 1; // browse or step 1
int new_selected = selected - step;
if (new_selected < 0) {
if (selected != 0 && step != 1)
new_selected = 0;
else
new_selected = total - 1;
}
updateItemSelection(id, entries, new_selected, selected, liststart);
}
else if (!timeout && (msg_repeatok == CRCInput::RC_down || (int) msg == g_settings.key_pagedown)) {
int step = ((int) msg == g_settings.key_pagedown) ? m_listmaxshow : 1; // browse or step 1
int new_selected = selected + step;
if (new_selected >= (int) total) {
if ((total - m_listmaxshow -1 < selected) && (selected != (total - 1)) && (step != 1))
new_selected = total - 1;
else if (((total / m_listmaxshow) + 1) * m_listmaxshow == total + m_listmaxshow) // last page has full entries
new_selected = 0;
else
new_selected = ((step == (int) m_listmaxshow) && (new_selected < (int) (((total / m_listmaxshow)+1) * m_listmaxshow))) ? (total - 1) : 0;
}
updateItemSelection(id, entries, new_selected, selected, liststart);
}
else if (!timeout && (msg == CRCInput::RC_ok || msg == CRCInput::RC_right)) {
if ((selected - liststart) >= (*entries).size())
continue;
if ((*entries)[selected - liststart].isdir) {
endall=selectItem((*entries)[selected - liststart].id);
if (endall)
loop=false;
refresh=true;
} else {
m_folderplay = false;
int preferred=(*entries)[selected - liststart].preferred;
if (preferred != -1)
{
std::string &mime = (*entries)[selected - liststart].mime;
if (mime.substr(0,6) == "audio/")
{
m_playing_entry = (*entries)[selected - liststart];
m_playing_entry_is_shown = false;
playAudio((*entries)[selected - liststart].resources[preferred].url, (*entries)[selected - liststart].type);
}
else if (mime.substr(0,6) == "video/")
{
m_frameBuffer->Clear();
playVideo((*entries)[selected - liststart].title, (*entries)[selected - liststart].resources[preferred].url);
m_frameBuffer->showFrame("mp3.jpg");
refresh = true;
}
else if (mime.substr(0,6) == "image/")
{
videoDecoder->setBlank(true);
showPicture((*entries)[selected - liststart].resources[preferred].url);
m_playid = selected;
while (true)
{
g_RCInput->getMsg(&msg, &data, 10); // 1 sec timeout
if (msg == CRCInput::RC_home || msg == CRCInput::RC_ok)
break;
else if (msg == CRCInput::RC_right || msg == CRCInput::RC_down) {
m_playfolder = id;
m_playid = (m_playid + 1)%total;
playnext();
}
else if (msg == CRCInput::RC_left || msg == CRCInput::RC_up) {
m_playfolder = id;
m_playid--;
if (m_playid < 0)
m_playid = total - 1;
playnext();
} else
CNeutrinoApp::getInstance()->handleMsg(msg, data);
}
m_frameBuffer->Clear();
videoDecoder->setBlank(false);
refresh = true;
}
}
}
}
else if (msg == CRCInput::RC_play) {
if ((selected - liststart) >= (*entries).size())
continue;
m_folderplay = true;
m_playfolder = (*entries)[selected - liststart].id;
m_playid = 0;
playnext();
m_playid++;
}
else if (msg == CRCInput::RC_yellow) {
if (CAudioPlayer::getInstance()->getState() != CBaseDec::STOP)
CAudioPlayer::getInstance()->stop();
m_folderplay = false;
}
else if (m_folderplay && msg == (neutrino_msg_t) CRCInput::RC_stop) {
timeout = 0;
m_folderplay = false;
m_frameBuffer->Clear();
refresh = true;
}
else if (m_folderplay && msg == (neutrino_msg_t) CRCInput::RC_prev) {
timeout = 0;
m_playid -= 2;
if (m_playid < 0)
m_playid = 0;
}
else if (m_folderplay && msg == (neutrino_msg_t) CRCInput::RC_next) {
timeout = 0;
if (CAudioPlayer::getInstance()->getState() != CBaseDec::STOP)
CAudioPlayer::getInstance()->stop();
}
else if (msg == NeutrinoMessages::RECORD_START ||
msg == NeutrinoMessages::ZAPTO ||
msg == NeutrinoMessages::STANDBY_ON ||
msg == NeutrinoMessages::LEAVE_ALL ||
msg == NeutrinoMessages::SHUTDOWN ||
msg == NeutrinoMessages::SLEEPTIMER)
{
loop = false;
g_RCInput->postMsg(msg, data);
}
#if 0
else if (msg == NeutrinoMessages::EVT_TIMER)
{
CNeutrinoApp::getInstance()->handleMsg(msg, data);
}
else if (msg > CRCInput::RC_MaxRC)
#endif
else
{
if (CNeutrinoApp::getInstance()->handleMsg(msg, data) & messages_return::cancel_all)
loop = false;
//refresh=true;
}
if (m_folderplay && ((!timeout || (timeout <= time(NULL))) && (CAudioPlayer::getInstance()->getState() == CBaseDec::STOP))) {
playnext();
m_playid++;
}
}
delete entries;
timeout = 0;
m_frameBuffer->Clear();
return endall;
}
void CUpnpBrowserGui::paintDeviceInfo()
{
CVFD::getInstance()->showMenuText(0, m_devices[m_selecteddevice].friendlyname.c_str(), -1, true);
// Info
std::string tmp;
// first line
tmp = m_devices[m_selecteddevice].manufacturer + " " +
m_devices[m_selecteddevice].manufacturerurl + "\n";
// second line
tmp += m_devices[m_selecteddevice].modelname + " " +
m_devices[m_selecteddevice].modelnumber + " " +
m_devices[m_selecteddevice].modeldescription + "\n";
// third line
tmp += m_devices[m_selecteddevice].modelurl;
topbox.setDimensionsAll(m_x, m_y, m_width, m_title_height-10);
topbox.setText(tmp, CTextBox::AUTO_WIDTH);
topbox.paint0();
}
void CUpnpBrowserGui::paintDevice(unsigned int _pos)
{
int ypos = m_y + m_title_height + m_theight + _pos*m_fheight;
fb_pixel_t color;
fb_pixel_t bgcolor;
unsigned int pos = m_deviceliststart + _pos;
if (pos == m_selecteddevice)
{
color = COL_MENUCONTENT_TEXT_PLUS_2;
bgcolor = COL_MENUCONTENT_PLUS_2;
paintDeviceInfo();
}
else
{
color = COL_MENUCONTENT_TEXT;
bgcolor = COL_MENUCONTENT_PLUS_0;
}
m_frameBuffer->paintBoxRel(m_x, ypos, m_width - 15, m_fheight, bgcolor);
if (pos >= m_devices.size())
return;
char sNr[20];
sprintf(sNr, "%2d", pos + 1);
std::string num = sNr;
std::string name = m_devices[pos].friendlyname;
int w = g_Font[SNeutrinoSettings::FONT_TYPE_FILEBROWSER_ITEM]->getRenderWidth(name) + 5;
g_Font[SNeutrinoSettings::FONT_TYPE_FILEBROWSER_ITEM]->RenderString(m_x + 10, ypos + m_fheight, m_width - 30 - w,
num, color, m_fheight);
g_Font[SNeutrinoSettings::FONT_TYPE_FILEBROWSER_ITEM]->RenderString(m_x + m_width - 15 - w, ypos + m_fheight,
w, name, color, m_fheight);
}
void CUpnpBrowserGui::paintDevices()
{
int ypos, top;
// LCD
CVFD::getInstance()->setMode(CVFD::MODE_MENU_UTF8, "Select UPnP Device");
// Head
CComponentsHeaderLocalized header(m_x, m_y + m_title_height, m_width, m_theight, LOCALE_UPNPBROWSER_HEAD, NEUTRINO_ICON_UPNP);
if (CNeutrinoApp::getInstance()->isMuted()) //TODO: consider mute mode on runtime
header.addContextButton(NEUTRINO_ICON_BUTTON_MUTE_SMALL);
else
header.removeContextButtons();
header.paint(CC_SAVE_SCREEN_NO);
// Items
for (unsigned int count=0; count<m_listmaxshow; count++)
paintDevice(count);
ypos = m_y + m_title_height + m_theight;
int sb = m_fheight * m_listmaxshow;
m_frameBuffer->paintBoxRel(m_x + m_width - 15, ypos, 15, sb, COL_MENUCONTENT_PLUS_1);
int sbc = ((m_devices.size() - 1) / m_listmaxshow) + 1;
int sbs = ((m_selecteddevice) / m_listmaxshow);
m_frameBuffer->paintBoxRel(m_x + m_width - 13, ypos + 2 + sbs*(sb-4)/sbc, 11, (sb-4)/sbc, COL_MENUCONTENT_PLUS_3);
// Foot
top = m_y + (m_height - m_info_height - 2 * m_buttonHeight);
footer.paintButtons(m_x, top, m_width, m_buttonHeight, 1, &RescanButton, m_width/2);
paintItem2DetailsLine (-1); // clear it
}
void CUpnpBrowserGui::paintItem(std::vector<UPnPEntry> *entries, unsigned int pos, unsigned int selected)
{
int ypos = m_y + m_title_height + m_theight + pos*m_fheight;
fb_pixel_t color;
fb_pixel_t bgcolor;
if (pos == selected)
{
color = COL_MENUCONTENT_TEXT_PLUS_2;
bgcolor = COL_MENUCONTENT_PLUS_2;
}
else
{
color = COL_MENUCONTENT_TEXT;
bgcolor = COL_MENUCONTENT_PLUS_0;
}
m_frameBuffer->paintBoxRel(m_x, ypos, m_width - 15, m_fheight, bgcolor);
if (pos >= (*entries).size())
return;
UPnPEntry *entry = &(*entries)[pos];
if (pos == selected)
{
paintItemInfo(entry);
paintDetails(entry);
if (entry->isdir)
paintItem2DetailsLine (-1); // clear it
else
paintItem2DetailsLine (pos);
}
int preferred=entry->preferred;
std::string info;
std::string fileicon;
if (entry->isdir)
{
info = "<DIR>";
fileicon = NEUTRINO_ICON_FOLDER;
}
else
{
if (preferred != -1)
{
info = entry->resources[preferred].duration;
fileicon = NEUTRINO_ICON_MP3;
}
else
{
info = "(none)";
fileicon = NEUTRINO_ICON_FILE;
}
}
std::string name = entry->title;
char tmp_time[] = "00:00:00.0";
int w = g_Font[SNeutrinoSettings::FONT_TYPE_FILEBROWSER_ITEM]->getRenderWidth(tmp_time);
int icon_w = 0;
int icon_h = 0;
int icon_o = 0;
m_frameBuffer->getIconSize(fileicon.c_str(), &icon_w, &icon_h);
if (icon_w && icon_h)
{
icon_o = icon_w + 10;
m_frameBuffer->paintIcon(fileicon, m_x + 10, ypos + (m_fheight - icon_h) / 2);
}
g_Font[SNeutrinoSettings::FONT_TYPE_FILEBROWSER_ITEM]->RenderString(m_x + m_width - 15 - 10 - w, ypos + m_fheight, w, info, color, m_fheight);
g_Font[SNeutrinoSettings::FONT_TYPE_FILEBROWSER_ITEM]->RenderString(m_x + 10 + icon_o, ypos + m_fheight, m_width - icon_o - 15 - 2*10 - w, name, color, m_fheight);
}
void CUpnpBrowserGui::paintItemInfo(UPnPEntry *entry)
{
std::string tmp;
std::stringstream ts;
int preferred=entry->preferred;
// LCD
CVFD::getInstance()->showMenuText(0, entry->title.c_str(), -1, true);
// first line
ts << "Resources: " << entry->resources.size() << " Selected: " << preferred+1 << " ";
tmp = ts.str();
if (preferred != -1)
tmp = tmp + "Duration: " + entry->resources[preferred].duration;
else
tmp = tmp + "No resource for Item";
tmp += "\n";
// second line
if (entry->isdir)
tmp += "Directory";
else
{
tmp += "";
if (preferred != -1)
tmp += "Protocol: " + entry->proto + ", MIME-Type: " + entry->mime;
}
tmp += "\n";
//third line
if (!entry->isdir && preferred != -1)
tmp += "URL: " + entry->resources[preferred].url;
static std::string lastname = "", tmpname = "";
if(!entry->albumArtURI.empty()){
if(lastname != entry->albumArtURI){
tmpname = lastname = entry->albumArtURI.c_str();
tmpname = g_PicViewer->DownloadImage(tmpname);
int h_image = ibox.getHeight()- SHADOW_OFFSET - ibox.getCornerRadius();
int y_image = ibox.getYPos() + ibox.getHeight()/2 - h_image/2;
if (!image){
image = new CComponentsPicture(100, y_image, tmpname, NULL, CC_SHADOW_OFF, COL_MENUCONTENTDARK_PLUS_0);
}
image->setPicture(tmpname);
image->setHeight(h_image, true);
int x_image = ibox.getXPos() + ibox.getWidth()- image->getWidth()- SHADOW_OFFSET - ibox.getCornerRadius();
image->setXPos(x_image);
}
}else{
if (image){
delete image; image = NULL;
}
}
topbox.setText(tmp, CTextBox::AUTO_WIDTH);
topbox.paint0();
}
void CUpnpBrowserGui::paintItems(std::vector<UPnPEntry> *entry, unsigned int selected, unsigned int max, unsigned int offset)
{
printf("CUpnpBrowserGui::paintItem:s selected %d max %d offset %d\n", selected, max, offset);
int ypos, top;
//block infoclock
CInfoClock::getInstance()->block();
// LCD
CVFD::getInstance()->setMode(CVFD::MODE_MENU_UTF8, "Select UPnP Entry");
// Head
std::string name = g_Locale->getText(LOCALE_UPNPBROWSER_HEAD);
name += " : ";
name += m_devices[m_selecteddevice].friendlyname;
CComponentsHeader header(m_x, m_y + m_title_height, m_width, m_theight, name, NEUTRINO_ICON_UPNP);
if (CNeutrinoApp::getInstance()->isMuted())
header.setContextButton(NEUTRINO_ICON_BUTTON_MUTE_SMALL);
header.paint(CC_SAVE_SCREEN_NO);
// Items
for (unsigned int count=0; count<m_listmaxshow; count++)
paintItem(entry, count, selected);
ypos = m_y + m_title_height + m_theight;
int sb = m_fheight * m_listmaxshow;
m_frameBuffer->paintBoxRel(m_x + m_width - 15, ypos, 15, sb, COL_MENUCONTENT_PLUS_1);
int sbc = ((max + offset - 1) / m_listmaxshow) + 1;
int sbs = ((selected + offset) / m_listmaxshow);
int sbh = 0;
if ((sbc > 0) && (sbc > sb-4))
sbh = 2;
m_frameBuffer->paintBoxRel(m_x + m_width - 13, ypos + 2 + sbs*((sb-4)/sbc+sbh), 11, (sb-4)/sbc + sbh, COL_MENUCONTENT_PLUS_3);
// Foot buttons
top = m_y + (m_height - m_info_height - 2 * m_buttonHeight);
size_t numbuttons = sizeof(BrowseButtons)/sizeof(BrowseButtons[0]);
footer.paintButtons(m_x, top, m_width, m_buttonHeight, numbuttons, BrowseButtons, m_width/numbuttons);
}
void CUpnpBrowserGui::paintDetails(UPnPEntry *entry, bool use_playing)
{
// Foot info
int i_height = 2 * m_buttonHeight;
ibox.setDimensionsAll(m_x, footer.getYPos()+ footer.getHeight()+SHADOW_OFFSET, m_width-i_height-SHADOW_OFFSET, i_height);
timebox.setDimensionsAll(m_x + m_width - i_height, ibox.getYPos(), i_height, i_height);
printf("paintDetails: use_playing %d shown %d\n", use_playing, m_playing_entry_is_shown);
if ((!use_playing) && entry->isdir){
ibox.kill();
m_playing_entry_is_shown = false;
}else{
string text = "";
if (use_playing){
if (!m_playing_entry_is_shown){
m_playing_entry_is_shown = true;
text = m_playing_entry.title;
text += !m_playing_entry.artist.empty() ? " - " + m_playing_entry.artist : "";
text += "\n" + m_playing_entry.album;
ibox.setText(text, CTextBox::AUTO_WIDTH);
ibox.paint0();
}
}else{
if (!entry)
return;
m_playing_entry_is_shown = false;
text = entry->title;
text += !entry->artist.empty() ? " - " + entry->artist : "";
text += "\n" + entry->album;
ibox.setText(text, CTextBox::AUTO_WIDTH);
ibox.paint0();
if (image)
image->paint0();
}
timebox.paint0();
}
}
void CUpnpBrowserGui::paintItem2DetailsLine (int pos)
{
if (pos < 0)
return;
int xpos = m_x - ConnectLineBox_Width;
int ypos1 = m_y + m_title_height+0 + m_theight + pos*m_fheight;
int ypos2 = ibox.getYPos()+ ibox.getHeight()-ibox.getHeight()/2;
int ypos1a = ypos1 + (m_fheight/2);
if (!dline)
dline = new CComponentsDetailLine();
dline->setDimensionsAll(xpos, ypos1a, ypos2, m_fheight/2, ibox.getHeight()-RADIUS_LARGE*3);
dline->paint();
}
void CUpnpBrowserGui::updateTimes(const bool force)
{
if (CAudioPlayer::getInstance()->getState() != CBaseDec::STOP){
bool updatePlayed = force;
if ((m_time_played != CAudioPlayer::getInstance()->getTimePlayed())){
m_time_played = CAudioPlayer::getInstance()->getTimePlayed();
updatePlayed = true;
}
printf("updateTimes: force %d updatePlayed %d\n", force, updatePlayed);
char play_time[8];
snprintf(play_time, 7, "%ld:%02ld", m_time_played / 60, m_time_played % 60);
if (updatePlayed){
timebox.setText(play_time, CTextBox::CENTER);
timebox.paint0();
}
}
}
void CUpnpBrowserGui::playAudio(std::string name, int type)
{
CNeutrinoApp::getInstance()->handleMsg(NeutrinoMessages::CHANGEMODE, NeutrinoMessages::mode_audio);
CAudiofile mp3(name, (CFile::FileType) type);
CAudioPlayer::getInstance()->play(&mp3, g_settings.audioplayer_highprio == 1);
CNeutrinoApp::getInstance()->handleMsg(NeutrinoMessages::CHANGEMODE, NeutrinoMessages::mode_upnp | NeutrinoMessages::norezap);
}
void CUpnpBrowserGui::showPicture(std::string name)
{
CNeutrinoApp::getInstance()->handleMsg(NeutrinoMessages::CHANGEMODE, NeutrinoMessages::mode_pic);
g_PicViewer->SetScaling((CPictureViewer::ScalingMode)g_settings.picviewer_scaling);
g_PicViewer->SetVisible(g_settings.screen_StartX, g_settings.screen_EndX, g_settings.screen_StartY, g_settings.screen_EndY);
if (g_settings.video_Format==3)
g_PicViewer->SetAspectRatio(16.0/9);
else
g_PicViewer->SetAspectRatio(4.0/3);
g_PicViewer->ShowImage(name, false);
g_PicViewer->Cleanup();
CNeutrinoApp::getInstance()->handleMsg(NeutrinoMessages::CHANGEMODE, NeutrinoMessages::mode_upnp | NeutrinoMessages::norezap);
}
void CUpnpBrowserGui::playVideo(std::string name, std::string url)
{
CNeutrinoApp::getInstance()->handleMsg(NeutrinoMessages::CHANGEMODE, NeutrinoMessages::mode_ts);
if (CAudioPlayer::getInstance()->getState() != CBaseDec::STOP)
CAudioPlayer::getInstance()->stop();
m_frameBuffer->stopFrame();
CMoviePlayerGui::getInstance().SetFile(name, url);
CMoviePlayerGui::getInstance().exec(NULL, "upnp");
CNeutrinoApp::getInstance()->handleMsg(NeutrinoMessages::CHANGEMODE, NeutrinoMessages::mode_upnp | NeutrinoMessages::norezap);
}