/* Neutrino-GUI - DBoxII-Project UPnP Browser (c) 2007 by Jochen Friedrich Homepage: http://dbox.cyberphoria.org/ Kommentar: Diese GUI wurde von Grund auf neu programmiert und sollte nun vom Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert auf der Client-Server Idee, diese GUI ist also von der direkten DBox- Steuerung getrennt. Diese wird dann von Daemons uebernommen. 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, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include extern cVideo * videoDecoder; #ifdef ConnectLineBox_Width #undef ConnectLineBox_Width #endif #define ConnectLineBox_Width 15 const struct button_label RescanButton = {NEUTRINO_ICON_BUTTON_BLUE , LOCALE_UPNPBROWSER_RESCAN}; const struct button_label StopButton = {NEUTRINO_ICON_BUTTON_YELLOW, LOCALE_AUDIOPLAYER_STOP}; const struct button_label PUpButton = {NEUTRINO_ICON_BUTTON_RED , LOCALE_FILEBROWSER_NEXTPAGE}; const struct button_label PDownButton = {NEUTRINO_ICON_BUTTON_GREEN , LOCALE_FILEBROWSER_PREVPAGE}; //------------------------------------------------------------------------ CUpnpBrowserGui::CUpnpBrowserGui() { m_socket = new CUPnPSocket(); m_frameBuffer = CFrameBuffer::getInstance(); m_playing_entry_is_shown = false; } //------------------------------------------------------------------------ CUpnpBrowserGui::~CUpnpBrowserGui() { delete m_socket; } //------------------------------------------------------------------------ int CUpnpBrowserGui::exec(CMenuTarget* parent, const std::string & /*actionKey*/) { CAudioPlayer::getInstance()->init(); if (parent) { parent->hide(); } g_Zapit->stopPlayBack(); videoDecoder->ShowPicture(DATADIR "/neutrino/icons/mp3.jpg"); // tell neutrino we're in audio mode CNeutrinoApp::getInstance()->handleMsg( NeutrinoMessages::CHANGEMODE , NeutrinoMessages::mode_audio ); // remember last mode #if 0 CZapitClient::responseGetLastChannel firstchannel; g_Zapit->getLastChannel(firstchannel.channelNumber, firstchannel.mode); if ((firstchannel.mode == 'r') ? (CNeutrinoApp::getInstance()->zapto_radio_on_init_done) : (CNeutrinoApp::getInstance()->zapto_tv_on_init_done)) m_LastMode=(CNeutrinoApp::getInstance()->getLastMode() | NeutrinoMessages::norezap); else m_LastMode=(CNeutrinoApp::getInstance()->getLastMode()); #endif m_LastMode=(CNeutrinoApp::getInstance()->getLastMode()); m_width=(g_settings.screen_EndX - g_settings.screen_StartX) - ConnectLineBox_Width; m_height = (g_settings.screen_EndY - g_settings.screen_StartY); m_sheight = g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL]->getHeight(); m_buttonHeight = std::min(25, m_sheight); m_theight = g_Font[SNeutrinoSettings::FONT_TYPE_MENU_TITLE]->getHeight(); 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 m_x=getScreenStartX( m_width + ConnectLineBox_Width ) + ConnectLineBox_Width; m_y=getScreenStartY( m_height ); // Stop sectionsd g_Sectionsd->setPauseScanning(true); m_indexdevice=0; m_selecteddevice=0; selectDevice(); if (CAudioPlayer::getInstance()->getState() != CBaseDec::STOP) CAudioPlayer::getInstance()->stop(); //g_Zapit->setStandby(false); // Start Sectionsd g_Sectionsd->setPauseScanning(false); videoDecoder->StopPicture(); CNeutrinoApp::getInstance()->handleMsg( NeutrinoMessages::CHANGEMODE , m_LastMode ); g_RCInput->postMsg( NeutrinoMessages::SHOW_INFOBAR, 0 ); return menu_return::RETURN_EXIT_ALL; } //------------------------------------------------------------------------ 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()); } //------------------------------------------------------------------------ std::vector *CUpnpBrowserGui::decodeResult(std::string result) { XMLTreeParser *parser; XMLTreeNode *root, *node, *snode; std::vector *entries; parser = new XMLTreeParser("UTF-8"); parser->Parse(result.c_str(), result.size(), 1); root=parser->RootNode(); if (!root) { delete parser; return NULL; } entries = new std::vector; for (node=root->GetChild(); node; node=node->GetNext()) { bool isdir; std::string title, artist = "", album = "", id, children; const char *type, *p; if (!strcmp(node->GetType(), "container")) { std::vector resources; isdir=true; for (snode=node->GetChild(); snode; snode=snode->GetNext()) { type=snode->GetType(); p = strchr(type,':'); if (p) type=p+1; if (!strcmp(type,"title")) { p=snode->GetData(); if (!p) p = ""; title=std::string(p); } } p = node->GetAttributeValue("id"); if (!p) p = ""; id=std::string(p); p = node->GetAttributeValue("childCount"); if (!p) p = ""; children=std::string(p); UPnPEntry entry={id, isdir, title, artist, album, children, resources, -1}; entries->push_back(entry); } if (!strcmp(node->GetType(), "item")) { std::vector resources; int preferred = -1; std::string protocol, prot, network, mime, additional; isdir=false; for (snode=node->GetChild(); snode; snode=snode->GetNext()) { std::string duration, url, size; unsigned int i; type=snode->GetType(); p = strchr(type,':'); if (p) type=p+1; if (!strcmp(type,"title")) { p=snode->GetData(); if (!p) p = ""; title=std::string(p); } else if (!strcmp(type,"artist")) { p=snode->GetData(); if (!p) p = ""; artist=std::string(p); } else if (!strcmp(type,"album")) { p=snode->GetData(); if (!p) p = ""; album=std::string(p); } else if (!strcmp(type,"res")) { p = snode->GetData(); if (!p) p = ""; url=std::string(p); p = snode->GetAttributeValue("size"); if (!p) p = "0"; size=std::string(p); p = snode->GetAttributeValue("duration"); if (!p) p = ""; duration=std::string(p); p = snode->GetAttributeValue("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; iGetAttributeValue("id"); if (!p) p = ""; id=std::string(p); p = node->GetAttributeValue("childCount"); if (!p) p = ""; children=std::string(p); UPnPEntry entry={id, isdir, title, artist, album, children, resources, preferred}; entries->push_back(entry); } } delete parser; return entries; } //------------------------------------------------------------------------ void CUpnpBrowserGui::selectDevice() { bool loop = true; bool changed = true; neutrino_msg_t msg; neutrino_msg_data_t data; CHintBox *scanBox = new CHintBox(LOCALE_MESSAGEBOX_INFO, g_Locale->getText(LOCALE_UPNPBROWSER_SCANNING)); // UTF-8 scanBox->paint(); #if 0 try { m_devices = m_socket->Discover("urn:schemas-upnp-org:service:ContentDirectory:1"); } catch (std::runtime_error error) { delete scanBox; ShowMsgUTF(LOCALE_MESSAGEBOX_INFO, error.what(), CMessageBox::mbrBack, CMessageBox::mbBack, NEUTRINO_ICON_INFO); return; } #endif m_devices = m_socket->Discover("urn:schemas-upnp-org:service:ContentDirectory:1"); scanBox->hide(); if (!m_devices.size()) { ShowLocalizedMessage(LOCALE_MESSAGEBOX_INFO, LOCALE_UPNPBROWSER_NOSERVERS, CMessageBox::mbrBack, CMessageBox::mbBack, NEUTRINO_ICON_INFO); delete scanBox; return; } while (loop) { if (changed) { paintDevice(); changed=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 == CRCInput::RC_up && m_selecteddevice > 0) { m_selecteddevice--; if (m_selecteddevice < m_indexdevice) m_indexdevice-=m_listmaxshow; changed=true; } else if (msg_repeatok == CRCInput::RC_down && m_selecteddevice + 1 < m_devices.size()) { m_selecteddevice++; if (m_selecteddevice + 1 > m_indexdevice + m_listmaxshow) m_indexdevice+=m_listmaxshow; changed=true; } else if ( msg == CRCInput::RC_right || msg == CRCInput::RC_ok) { m_folderplay = false; selectItem("0"); changed=true; } else if ( msg == CRCInput::RC_blue) { scanBox->paint(); #if 0 try { m_devices = m_socket->Discover("urn:schemas-upnp-org:service:ContentDirectory:1"); } catch (std::runtime_error error) { delete scanBox; ShowMsgUTF(LOCALE_MESSAGEBOX_INFO, error.what(), CMessageBox::mbrBack, CMessageBox::mbBack, NEUTRINO_ICON_INFO); return; } #endif m_devices = m_socket->Discover("urn:schemas-upnp-org:service:ContentDirectory:1"); scanBox->hide(); if (!m_devices.size()) { ShowLocalizedMessage(LOCALE_MESSAGEBOX_INFO, LOCALE_UPNPBROWSER_NOSERVERS, CMessageBox::mbrBack, CMessageBox::mbBack, NEUTRINO_ICON_INFO); delete scanBox; return; } changed=true; } else if (msg == NeutrinoMessages::RECORD_START || msg == NeutrinoMessages::ZAPTO || msg == NeutrinoMessages::STANDBY_ON || msg == NeutrinoMessages::SHUTDOWN || msg == NeutrinoMessages::SLEEPTIMER) { loop=false; g_RCInput->postMsg(msg, data); } else if (msg == NeutrinoMessages::EVT_TIMER) { CNeutrinoApp::getInstance()->handleMsg( msg, data ); } else { if ( CNeutrinoApp::getInstance()->handleMsg( msg, data ) & messages_return::cancel_all ) loop = false; changed=true; } } delete scanBox; } //------------------------------------------------------------------------ void CUpnpBrowserGui::playnext(void) { while (true) { std::listattribs; std::listresults; std::list::iterator i; std::stringstream sindex; std::vector *entries = NULL; bool rfound = false; bool nfound = false; bool tfound = false; sindex << m_playid; attribs.push_back(UPnPAttribute("ObjectID", m_playfolder)); attribs.push_back(UPnPAttribute("BrowseFlag", "BrowseDirectChildren")); attribs.push_back(UPnPAttribute("Filter", "*")); attribs.push_back(UPnPAttribute("StartingIndex", sindex.str())); attribs.push_back(UPnPAttribute("RequestedCount", "1")); attribs.push_back(UPnPAttribute("SortCriteria", "")); #if 0 try { results=m_devices[m_selecteddevice].SendSOAP("urn:schemas-upnp-org:service:ContentDirectory:1", "Browse", attribs); } catch (std::runtime_error error) { ShowMsgUTF(LOCALE_MESSAGEBOX_INFO, error.what(), CMessageBox::mbrBack, CMessageBox::mbBack, NEUTRINO_ICON_INFO); m_folderplay = false; return; } #endif results=m_devices[m_selecteddevice].SendSOAP("urn:schemas-upnp-org:service:ContentDirectory:1", "Browse", attribs); for (i=results.begin(); i!=results.end(); i++) { if (i->first=="NumberReturned") { if (atoi(i->second.c_str()) != 1) { m_folderplay = false; return; } nfound=true; } if (i->first=="TotalMatches") { tfound=true; } if (i->first=="Result") { entries=decodeResult(i->second); rfound=true; } } m_playid++; if ((entries != NULL) && (!(*entries)[0].isdir)) { int preferred=(*entries)[0].preferred; if (preferred != -1) { std::string protocol, prot, network, mime, additional; protocol=(*entries)[0].resources[preferred].protocol; splitProtocol(protocol, prot, network, mime, additional); if (mime == "audio/mpeg") { m_playing_entry = (*entries)[0]; m_playing_entry_is_shown = false; CAudiofile mp3((*entries)[0].resources[preferred].url, CFile::FILE_MP3); CAudioPlayer::getInstance()->play(&mp3, g_settings.audioplayer_highprio == 1); return; } else if (mime == "audio/x-vorbis+ogg") { m_playing_entry = (*entries)[0]; m_playing_entry_is_shown = false; CAudiofile mp3((*entries)[0].resources[preferred].url, CFile::FILE_OGG); CAudioPlayer::getInstance()->play(&mp3, g_settings.audioplayer_highprio == 1); 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; } } } } //------------------------------------------------------------------------ bool CUpnpBrowserGui::selectItem(std::string id) { bool loop = true; bool endall = false; bool changed = true; bool rchanged = true; neutrino_msg_t msg; neutrino_msg_data_t data; std::vector *entries; unsigned int index, selected, dirnum; index=0; selected=0; dirnum=0; entries=NULL; while (loop) { updateTimes(); if (rchanged) { if (entries) delete entries; entries=NULL; std::listattribs; std::listresults; std::list::iterator i; std::stringstream sindex; std::stringstream scount; unsigned int returned = 0; bool rfound = false; bool nfound = false; bool tfound = false; sindex << index; scount << m_listmaxshow; 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", "")); #if 0 try { results=m_devices[m_selecteddevice].SendSOAP("urn:schemas-upnp-org:service:ContentDirectory:1", "Browse", attribs); } catch (std::runtime_error error) { ShowMsgUTF(LOCALE_MESSAGEBOX_INFO, error.what(), CMessageBox::mbrBack, CMessageBox::mbBack, NEUTRINO_ICON_INFO); if (entries) delete entries; return endall; } #endif results=m_devices[m_selecteddevice].SendSOAP("urn:schemas-upnp-org:service:ContentDirectory:1", "Browse", attribs); for (i=results.begin(); i!=results.end(); i++) { if (i->first=="NumberReturned") { returned=atoi(i->second.c_str()); nfound=true; } if (i->first=="TotalMatches") { dirnum=atoi(i->second.c_str()); tfound=true; } if (i->first=="Result") { entries=decodeResult(i->second); rfound=true; } } if (!entries) return endall; if (!nfound || !tfound || !rfound) { delete entries; return endall; } if (returned != entries->size()) { delete entries; return endall; } if (returned == 0) { delete entries; return endall; } rchanged=false; changed=true; } if (changed) { paintItem(entries, selected - index, dirnum - index, index); changed=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 (msg == CRCInput::RC_left) { loop=false; } else if (msg_repeatok == CRCInput::RC_up && selected > 0) { selected--; if (selected < index) { index-=m_listmaxshow; rchanged=true; } changed=true; } else if (msg == CRCInput::RC_green && selected > 0) { if (index > 0) { index-=m_listmaxshow; selected-=m_listmaxshow; rchanged=true; } else selected=0; changed=true; } else if (msg_repeatok == CRCInput::RC_down && selected + 1 < dirnum) { selected++; if (selected + 1 > index + m_listmaxshow) { index+=m_listmaxshow; rchanged=true; } changed=true; } else if (msg == CRCInput::RC_red && selected + 1 < dirnum) { if (index < ((dirnum - 1) / m_listmaxshow) * m_listmaxshow) { index+=m_listmaxshow; selected+=m_listmaxshow; if (selected + 1 >= dirnum) selected=dirnum - 1; rchanged=true; } else selected=dirnum - 1; changed=true; } else if (msg == CRCInput::RC_right) { if ((*entries)[selected - index].isdir) { endall=selectItem((*entries)[selected - index].id); if (endall) loop=false; } changed=true; } else if (msg == CRCInput::RC_ok) { if (!(*entries)[selected - index].isdir) { m_folderplay = false; int preferred=(*entries)[selected - index].preferred; if (preferred != -1) { std::string protocol, prot, network, mime, additional; protocol=(*entries)[selected - index].resources[preferred].protocol; splitProtocol(protocol, prot, network, mime, additional); if (mime == "audio/mpeg") { CAudiofile mp3((*entries)[selected - index].resources[preferred].url, CFile::FILE_MP3); CAudioPlayer::getInstance()->play(&mp3, g_settings.audioplayer_highprio == 1); } else if (mime == "audio/x-vorbis+ogg") { CAudiofile mp3((*entries)[selected - index].resources[preferred].url, CFile::FILE_OGG); CAudioPlayer::getInstance()->play(&mp3, g_settings.audioplayer_highprio == 1); } m_playing_entry = (*entries)[selected - index]; #if 0 // TODO ! // #ifdef ENABLE_PICTUREVIEWER else if ((mime == "image/gif") || (mime == "image/jpeg")) { CPictureViewer *viewer = new CPictureViewer(); bool loop=true; viewer->SetScaling((CPictureViewer::ScalingMode)g_settings.picviewer_scaling); viewer->SetVisible(g_settings.screen_StartX, g_settings.screen_EndX, g_settings.screen_StartY, g_settings.screen_EndY); if (g_settings.video_Format==1) viewer->SetAspectRatio(16.0/9); else viewer->SetAspectRatio(4.0/3); m_frameBuffer->setMode(720, 576, 16); m_frameBuffer->setTransparency(0); viewer->ShowImage((*entries)[selected - index].resources[preferred].url, true); while (loop) { g_RCInput->getMsg(&msg, &data, 10); // 1 sec timeout to update play/stop state display if ( msg == CRCInput::RC_home) loop=false; } m_frameBuffer->setMode(720, 576, 8 * sizeof(fb_pixel_t)); m_frameBuffer->setBlendLevel(g_settings.gtx_alpha1, g_settings.gtx_alpha2); m_frameBuffer->Clear(); delete viewer; } // #endif #endif } } else { m_folderplay = true; m_playfolder = (*entries)[selected - index].id; m_playid = 0; playnext(); } changed=true; } else if ( msg == CRCInput::RC_yellow) { if (CAudioPlayer::getInstance()->getState() != CBaseDec::STOP) CAudioPlayer::getInstance()->stop(); m_folderplay = false; } else if (msg == NeutrinoMessages::RECORD_START || msg == NeutrinoMessages::ZAPTO || msg == NeutrinoMessages::STANDBY_ON || msg == NeutrinoMessages::SHUTDOWN || msg == NeutrinoMessages::SLEEPTIMER) { loop = false; g_RCInput->postMsg(msg, data); } else if (msg == NeutrinoMessages::EVT_TIMER) { CNeutrinoApp::getInstance()->handleMsg( msg, data ); } else { if ( CNeutrinoApp::getInstance()->handleMsg( msg, data ) & messages_return::cancel_all ) loop = false; changed=true; } if (m_folderplay && (CAudioPlayer::getInstance()->getState() == CBaseDec::STOP)) playnext(); } if (entries) delete entries; return endall; } //------------------------------------------------------------------------ void CUpnpBrowserGui::paintDevicePos(unsigned int pos) { int ypos = m_y + m_title_height + m_theight + pos*m_fheight; uint8_t color; fb_pixel_t bgcolor; if (pos == m_selecteddevice) { color = COL_MENUCONTENT + 2; bgcolor = COL_MENUCONTENT_PLUS_2; } else { color = COL_MENUCONTENT; bgcolor = COL_MENUCONTENT_PLUS_0; } m_frameBuffer->paintBoxRel(m_x, ypos, m_width - 15, m_fheight, bgcolor); if (pos + m_indexdevice >= m_devices.size()) return; char sNr[20]; sprintf(sNr, "%2d", pos + 1); std::string num = sNr; std::string name = m_devices[pos + m_indexdevice].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, true); // UTF-8 g_Font[SNeutrinoSettings::FONT_TYPE_FILEBROWSER_ITEM]->RenderString(m_x + m_width - 15 - w, ypos + m_fheight, w, name, color, m_fheight, true); // UTF-8 } //------------------------------------------------------------------------ void CUpnpBrowserGui::paintItemPos(std::vector *entry, unsigned int pos, unsigned int selected) { int ypos = m_y + m_title_height + m_theight + pos*m_fheight; uint8_t color; fb_pixel_t bgcolor; if (pos == selected) { color = COL_MENUCONTENT + 2; bgcolor = COL_MENUCONTENT_PLUS_2; paintDetails(entry, pos); if ((*entry)[pos].isdir) paintItem2DetailsLine (-1, pos); // clear it else paintItem2DetailsLine (pos, pos); } else { color = COL_MENUCONTENT; bgcolor = COL_MENUCONTENT_PLUS_0; } m_frameBuffer->paintBoxRel(m_x, ypos, m_width - 15, m_fheight, bgcolor); if (pos >= entry->size()) return; int preferred=(*entry)[pos].preferred; std::string info; std::string fileicon; if ((*entry)[pos].isdir) { info = ""; fileicon = NEUTRINO_ICON_FOLDER; } else { if (preferred != -1) { info = (*entry)[pos].resources[preferred].duration; fileicon = NEUTRINO_ICON_MP3; } else { info = "(none)"; fileicon = NEUTRINO_ICON_FILE; } } std::string name = (*entry)[pos].title; char tmp_time[] = "00:00:00.0"; int w = g_Font[SNeutrinoSettings::FONT_TYPE_FILEBROWSER_ITEM]->getRenderWidth(tmp_time); m_frameBuffer->paintIcon(fileicon, m_x + 5 , ypos + (m_fheight - 16) / 2); g_Font[SNeutrinoSettings::FONT_TYPE_FILEBROWSER_ITEM]->RenderString(m_x + m_width - 15 - w, ypos + m_fheight, w, info, color, m_fheight); g_Font[SNeutrinoSettings::FONT_TYPE_FILEBROWSER_ITEM]->RenderString(m_x + 30, ypos + m_fheight, m_width - 50 - w, name, color, m_fheight, true); // UTF-8 } //------------------------------------------------------------------------ void CUpnpBrowserGui::paintDevice() { std::string tmp; int w, xstart, ypos, top; int c_rad_mid = RADIUS_MID; // LCD CVFD::getInstance()->setMode(CVFD::MODE_MENU_UTF8, "Select UPnP Device"); CVFD::getInstance()->showMenuText(0, m_devices[m_selecteddevice].friendlyname.c_str(), -1, true); // Info m_frameBuffer->paintBoxRel(m_x, m_y, m_width, m_title_height - 10, COL_MENUCONTENT_PLUS_6, c_rad_mid); m_frameBuffer->paintBoxRel(m_x + 2, m_y + 2, m_width - 4, m_title_height - 14, COL_MENUCONTENTSELECTED_PLUS_0, c_rad_mid); // first line tmp = m_devices[m_selecteddevice].manufacturer + " " + m_devices[m_selecteddevice].manufacturerurl; w = g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getRenderWidth(tmp, true); // UTF-8 xstart = (m_width - w) / 2; if (xstart < 10) xstart = 10; g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(m_x + xstart, m_y + 4 + 1*m_mheight, m_width - 20, tmp, COL_MENUCONTENTSELECTED, 0, true); // UTF-8 // second line tmp = m_devices[m_selecteddevice].modelname + " " + m_devices[m_selecteddevice].modelnumber + " " + m_devices[m_selecteddevice].modeldescription; w = g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getRenderWidth(tmp, true); // UTF-8 xstart = (m_width - w) / 2; if (xstart < 10) xstart = 10; g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(m_x + xstart, m_y + 4 + 2*m_mheight, m_width - 20, tmp, COL_MENUCONTENTSELECTED, 0, true); // UTF-8 // third line tmp = m_devices[m_selecteddevice].modelurl; w = g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getRenderWidth(tmp, true); // UTF-8 xstart = (m_width - w) / 2; if (xstart < 10) xstart = 10; g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(m_x + xstart, m_y + 4 + 3*m_mheight, m_width - 20, tmp, COL_MENUCONTENTSELECTED, 0, true); // UTF-8 // Head tmp = g_Locale->getText(LOCALE_UPNPBROWSER_HEAD); m_frameBuffer->paintBoxRel(m_x, m_y + m_title_height, m_width, m_theight, COL_MENUHEAD_PLUS_0, c_rad_mid, CORNER_TOP); m_frameBuffer->paintIcon(NEUTRINO_ICON_UPNP, m_x + 7, m_y + m_title_height + 6); g_Font[SNeutrinoSettings::FONT_TYPE_MENU_TITLE]->RenderString(m_x + 35, m_y + m_theight + m_title_height + 0, m_width - 45, tmp, COL_MENUHEAD, 0, true); // UTF-8 ypos = m_y + m_title_height; if (m_theight > 26) ypos = (m_theight - 26) / 2 + m_y + m_title_height; m_frameBuffer->paintIcon(NEUTRINO_ICON_BUTTON_DBOX, m_x + m_width - 30, ypos); #if 0 if ( CNeutrinoApp::getInstance()->isMuted() ) { xpos = m_x + m_width - 75; ypos = m_y + m_title_height; if (m_theight > 32) ypos = (m_theight - 32) / 2 + m_y + m_title_height; m_frameBuffer->paintIcon(NEUTRINO_ICON_BUTTON_MUTE, xpos, ypos); } #endif // Items for (unsigned int count=0; countpaintBoxRel(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); int ButtonWidth = (m_width - 20) / 4; m_frameBuffer->paintBoxRel(m_x, top, m_width, 1 * m_buttonHeight, COL_MENUHEAD_PLUS_0, c_rad_mid, CORNER_BOTTOM); m_frameBuffer->paintHLine(m_x, m_x + m_width, top, COL_INFOBAR_SHADOW_PLUS_0); ::paintButtons(m_frameBuffer, g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL], g_Locale, m_x + 10, top + 4, ButtonWidth, 1, &RescanButton); clearItem2DetailsLine(); // clear it } //------------------------------------------------------------------------ void CUpnpBrowserGui::paintItem(std::vector *entry, unsigned int selected, unsigned int max, unsigned int offset) { std::string tmp; std::stringstream ts; int w, xstart, ypos, top; int preferred=(*entry)[selected].preferred; // LCD CVFD::getInstance()->setMode(CVFD::MODE_MENU_UTF8, "Select UPnP Entry"); CVFD::getInstance()->showMenuText(0, (*entry)[selected].title.c_str(), -1, true); // Info m_frameBuffer->paintBoxRel(m_x, m_y, m_width, m_title_height - 10, COL_MENUCONTENT_PLUS_6); m_frameBuffer->paintBoxRel(m_x + 2, m_y + 2, m_width - 4, m_title_height - 14, COL_MENUCONTENTSELECTED_PLUS_0); // first line ts << "Resources: " << (*entry)[selected].resources.size() << " Selected: " << preferred+1 << " "; tmp = ts.str(); if (preferred != -1) tmp = tmp + "Duration: " + (*entry)[selected].resources[preferred].duration; else tmp = tmp + "No resource for Item"; w = g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getRenderWidth(tmp, true); // UTF-8 if (w > m_width - 20) w = m_width - 20; xstart = (m_width - w) / 2; if (xstart < 10) xstart = 10; g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(m_x + xstart, m_y + 4 + 1*m_mheight, m_width - 20, tmp, COL_MENUCONTENTSELECTED, 0, true); // UTF-8 // second line if ((*entry)[selected].isdir) tmp = "Directory"; else { tmp = ""; if (preferred != -1) { std::string proto, network, mime, info; splitProtocol((*entry)[selected].resources[preferred].protocol, proto, network, mime, info); tmp = "Protocol: " + proto + ", MIME-Type: " + mime; } } w = g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getRenderWidth(tmp, true); // UTF-8 if (w > m_width - 20) w = m_width - 20; xstart = (m_width - w) / 2; if (xstart < 10) xstart = 10; g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(m_x + xstart, m_y + 4 + 2*m_mheight, m_width - 20, tmp, COL_MENUCONTENTSELECTED, 0, true); // UTF-8 //third line tmp = ""; if (!(*entry)[selected].isdir) { if (preferred != -1) { tmp = "URL: " + (*entry)[selected].resources[preferred].url; } } w = g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getRenderWidth(tmp, true); // UTF-8 if (w > m_width - 20) w = m_width - 20; xstart = (m_width - w) / 2; if (xstart < 10) xstart = 10; g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(m_x + xstart, m_y + 4 + 3*m_mheight, m_width - 20, tmp, COL_MENUCONTENTSELECTED, 0, true); // UTF-8 // Head tmp = g_Locale->getText(LOCALE_UPNPBROWSER_HEAD); m_frameBuffer->paintBoxRel(m_x, m_y + m_title_height, m_width, m_theight, COL_MENUHEAD_PLUS_0); m_frameBuffer->paintIcon(NEUTRINO_ICON_UPNP, m_x + 7, m_y + m_title_height + 6); g_Font[SNeutrinoSettings::FONT_TYPE_MENU_TITLE]->RenderString(m_x + 35, m_y + m_theight + m_title_height + 0, m_width - 45, tmp, COL_MENUHEAD, 0, true); // UTF-8 ypos = m_y + m_title_height; if (m_theight > 26) ypos = (m_theight - 26) / 2 + m_y + m_title_height; m_frameBuffer->paintIcon(NEUTRINO_ICON_BUTTON_DBOX, m_x + m_width - 30, ypos); #if 0 if ( CNeutrinoApp::getInstance()->isMuted() ) { xpos = m_x + m_width - 75; ypos = m_y + m_title_height; if (m_theight > 32) ypos = (m_theight - 32) / 2 + m_y + m_title_height; m_frameBuffer->paintIcon(NEUTRINO_ICON_BUTTON_MUTE, xpos, ypos); } #endif // Items for (unsigned int count=0; countpaintBoxRel(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); int ButtonWidth = (m_width - 20) / 4; m_frameBuffer->paintBoxRel(m_x, top, m_width, 1 * m_buttonHeight+2, COL_MENUHEAD_PLUS_0); m_frameBuffer->paintHLine(m_x, m_x + m_width, top, COL_INFOBAR_SHADOW_PLUS_0); ::paintButtons(m_frameBuffer, g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL], g_Locale, m_x + 10, top + 4, ButtonWidth, 1, &StopButton); ::paintButtons(m_frameBuffer, g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL], g_Locale, m_x + ButtonWidth + 10, top + 4, ButtonWidth, 1, &PUpButton); ::paintButtons(m_frameBuffer, g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL], g_Locale, m_x + 2 * ButtonWidth + 10, top + 4, ButtonWidth, 1, &PDownButton); m_frameBuffer->paintIcon(NEUTRINO_ICON_BUTTON_OKAY, m_x + 3 * ButtonWidth + 10, top + 1); g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL]->RenderString(m_x + 3 * ButtonWidth + 40, top + 19 + 4, ButtonWidth - 40, g_Locale->getText(LOCALE_AUDIOPLAYER_PLAY), COL_INFOBAR, 0, true); // UTF-8 } //------------------------------------------------------------------------ void CUpnpBrowserGui::paintDetails(std::vector *entry, unsigned int index, bool use_playing) { // Foot info int top = m_y + (m_height - m_info_height - 1 * m_buttonHeight) + 2; if ((!use_playing) && ((*entry)[index].isdir)) { m_frameBuffer->paintBackgroundBoxRel(m_x, top + 2, m_width, 2 * m_buttonHeight); } else { // char cNoch[50]; // UTF-8 // char cSeit[50]; // UTF-8 if (use_playing) { if (!m_playing_entry_is_shown) { m_frameBuffer->paintBoxRel(m_x, top + 2, m_width-2, 2 * m_buttonHeight, COL_MENUCONTENTDARK_PLUS_0); m_playing_entry_is_shown = true; g_Font[SNeutrinoSettings::FONT_TYPE_FILEBROWSER_ITEM]->RenderString(m_x + 4, top + 1 * m_buttonHeight + 4, m_x + m_width - 8, m_playing_entry.title + " - " + m_playing_entry.artist, COL_INFOBAR, 0, true); // UTF-8 g_Font[SNeutrinoSettings::FONT_TYPE_FILEBROWSER_ITEM]->RenderString(m_x + 4, top + 2 * m_buttonHeight + 4, m_x + m_width - 8, m_playing_entry.album, COL_INFOBAR, 0, true); // UTF-8 } } else { if (entry == NULL) return; m_frameBuffer->paintBoxRel(m_x, top + 2, m_width-2, 2 * m_buttonHeight, COL_MENUCONTENTDARK_PLUS_0); m_playing_entry_is_shown = false; g_Font[SNeutrinoSettings::FONT_TYPE_FILEBROWSER_ITEM]->RenderString(m_x + 4, top + 1 * m_buttonHeight + 4, m_x + m_width - 8, (*entry)[index].title + " - " + (*entry)[index].artist, COL_INFOBAR, 0, true); // UTF-8 g_Font[SNeutrinoSettings::FONT_TYPE_FILEBROWSER_ITEM]->RenderString(m_x + 4, top + 2 * m_buttonHeight + 4, m_x + m_width - 8, (*entry)[index].album, COL_INFOBAR, 0, true); // UTF-8 } //// printf("title = %s\n", (*entry)[selected].title.c_str()); // printf("artist = %s\n", (*entry)[selected].artist.c_str()); // printf("album = %s\n", (*entry)[selected].album.c_str()); // printf("children = %s\n", (*entry)[selected].children.c_str()); // printf("id = %s\n", (*entry)[selected].id.c_str()); #if 0 struct tm *pStartZeit = localtime(&chanlist[index]->currentEvent.startTime); unsigned seit = ( time(NULL) - chanlist[index]->currentEvent.startTime ) / 60; sprintf( cSeit, g_Locale->getText(LOCALE_CHANNELLIST_SINCE), pStartZeit->tm_hour, pStartZeit->tm_min); //, seit ); int seit_len = g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST_DESCR]->getRenderWidth(cSeit, true); // UTF-8 int noch = ( chanlist[index]->currentEvent.startTime + chanlist[index]->currentEvent.duration - time(NULL) ) / 60; if ( (noch< 0) || (noch>=10000) ) noch= 0; sprintf( cNoch, "(%d / %d min)", seit, noch ); int noch_len = g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST_NUMBER]->getRenderWidth(cNoch, true); // UTF-8 std::string text1= chanlist[index]->currentEvent.description; std::string text2= chanlist[index]->currentEvent.text; int xstart = 10; if (g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST]->getRenderWidth(text1) > (width - 30 - seit_len) ) { // zu breit, Umbruch versuchen... int pos; do { pos = text1.find_last_of("[ -.]+"); if ( pos!=-1 ) text1 = text1.substr( 0, pos ); } while ( ( pos != -1 ) && (g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST]->getRenderWidth(text1) > (width - 30 - seit_len) ) ); std::string text3= chanlist[index]->currentEvent.description.substr(text1.length()+ 1); if (!(text2.empty())) text3 += " . "; xstart += g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST]->getRenderWidth(text3); g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST]->RenderString(x+ 10, y+ height+ 5+ 2* fheight, width - 30- noch_len, text3, COL_MENUCONTENTDARK); } if (!(text2.empty())) { while ( text2.find_first_of("[ -.+*#?=!$%&/]+") == 0 ) text2 = text2.substr( 1 ); text2 = text2.substr( 0, text2.find('\n') ); g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST_DESCR]->RenderString(x+ xstart, y+ height+ 5+ 2* fheight, width- xstart- 20- noch_len, text2, COL_MENUCONTENTDARK); } g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST]->RenderString(x+ 10, y+ height+ 5+ fheight, width - 30 - seit_len, text1, COL_MENUCONTENTDARK); g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST_DESCR]->RenderString (x+ width- 10- seit_len, y+ height+ 5+ fheight , seit_len, cSeit, COL_MENUCONTENTDARK, 0, true); // UTF-8 g_Font[SNeutrinoSettings::FONT_TYPE_CHANNELLIST_NUMBER]->RenderString(x+ width- 10- noch_len, y+ height+ 5+ 2* fheight- 2, noch_len, cNoch, COL_MENUCONTENTDARK, 0, true); // UTF-8 #endif } } //------------------------------------------------------------------------ // // -- Decoreline to connect ChannelDisplayLine with ChannelDetail display // -- 2002-03-17 rasc // void CUpnpBrowserGui::clearItem2DetailsLine () { paintItem2DetailsLine (-1, 0); } //------------------------------------------------------------------------ void CUpnpBrowserGui::paintItem2DetailsLine (int pos, unsigned int /*ch_index*/) { int xpos = m_x - ConnectLineBox_Width; int ypos1 = m_y + m_title_height+0 + m_theight + pos*m_fheight; int ypos2 = m_y + (m_height - m_info_height - 1 * m_buttonHeight) + 2; int ypos1a = ypos1 + (m_fheight/2)-2; int ypos2a = ypos2 + (m_info_height/2)-2; fb_pixel_t col1 = COL_MENUCONTENT_PLUS_6; fb_pixel_t col2 = COL_MENUCONTENT_PLUS_1; // Clear m_frameBuffer->paintBackgroundBoxRel(xpos, m_y + m_title_height, ConnectLineBox_Width, m_height+m_info_height-(m_y + m_title_height)); if (pos < 0) { m_frameBuffer->paintBackgroundBoxRel(m_x, m_y + (m_height - m_info_height - 1 * m_buttonHeight) + 2, m_width, m_info_height); } // paint Line if detail info (and not valid list pos) if (pos >= 0) { // 1. col thick line m_frameBuffer->paintBoxRel(xpos+ConnectLineBox_Width-4, ypos1, 4, m_fheight, col1); m_frameBuffer->paintBoxRel(xpos+ConnectLineBox_Width-4, ypos2, 4, m_info_height, col1); m_frameBuffer->paintBoxRel(xpos+ConnectLineBox_Width-15, ypos1a, 4, ypos2a-ypos1a, col1); m_frameBuffer->paintBoxRel(xpos+ConnectLineBox_Width-15, ypos1a, 12, 4, col1); m_frameBuffer->paintBoxRel(xpos+ConnectLineBox_Width-15, ypos2a, 12, 4, col1); // 2. col small line m_frameBuffer->paintBoxRel(xpos+ConnectLineBox_Width-4, ypos1, 1, m_fheight, col2); m_frameBuffer->paintBoxRel(xpos+ConnectLineBox_Width-4, ypos2, 1, m_info_height, col2); m_frameBuffer->paintBoxRel(xpos+ConnectLineBox_Width-15, ypos1a, 1, ypos2a-ypos1a+4, col2); m_frameBuffer->paintBoxRel(xpos+ConnectLineBox_Width-15, ypos1a, 12, 1, col2); m_frameBuffer->paintBoxRel(xpos+ConnectLineBox_Width-12, ypos2a, 8, 1, col2); // -- small Frame around infobox m_frameBuffer->paintBoxRel(m_x , ypos2, 2, m_info_height, col1); m_frameBuffer->paintBoxRel(m_x+m_width-2, ypos2, 2, m_info_height, col1); m_frameBuffer->paintBoxRel(m_x , ypos2, m_width-2, 2, col1); m_frameBuffer->paintBoxRel(m_x , ypos2+m_info_height-2, m_width-2, 2, col1); } } //------------------------------------------------------------------------ void CUpnpBrowserGui::updateTimes(const bool force) { int top; if (CAudioPlayer::getInstance()->getState() != CBaseDec::STOP) { bool updatePlayed = force; if ((m_time_played != CAudioPlayer::getInstance()->getTimePlayed())) { m_time_played = CAudioPlayer::getInstance()->getTimePlayed(); updatePlayed = true; } char play_time[8]; snprintf(play_time, 7, "%ld:%02ld", m_time_played / 60, m_time_played % 60); char tmp_time[] = "000:00"; int w = g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL]->getRenderWidth(tmp_time); if (updatePlayed) { paintDetails(NULL, 0, true); top = m_y + (m_height - m_info_height - 1 * m_buttonHeight) + m_buttonHeight + 4; m_frameBuffer->paintBoxRel(m_x + m_width - w - 15, top + 1, w + 4, m_buttonHeight, COL_MENUCONTENTDARK_PLUS_0); g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL]->RenderString(m_x + m_width - w - 11, top + 1 + m_buttonHeight, w, play_time, COL_MENUHEAD); } } }