MythTV  0.26-pre
osd.cpp
Go to the documentation of this file.
00001 // Qt
00002 #include <QCoreApplication>
00003 
00004 // libmyth
00005 #include "mythlogging.h"
00006 
00007 // libmythui
00008 #include "mythmainwindow.h"
00009 #include "mythuihelper.h"
00010 #include "mythpainter.h"
00011 #include "mythuiimage.h"
00012 #include "mythuiprogressbar.h"
00013 #include "mythdialogbox.h"
00014 #include "mythuitext.h"
00015 #include "mythuibutton.h"
00016 #include "mythuieditbar.h"
00017 #include "mythuistatetype.h"
00018 
00019 // libmythtv
00020 #include "channelutil.h"
00021 #include "teletextscreen.h"
00022 #include "subtitlescreen.h"
00023 #include "interactivescreen.h"
00024 #include "osd.h"
00025 #include "Bluray/bdringbuffer.h"
00026 #include "Bluray/bdoverlayscreen.h"
00027 
00028 #define LOC     QString("OSD: ")
00029 
00030 QEvent::Type OSDHideEvent::kEventType =
00031     (QEvent::Type) QEvent::registerEventType();
00032 
00033 ChannelEditor::ChannelEditor(QObject *retobject, const char *name)
00034   : MythScreenType((MythScreenType*)NULL, name)
00035 {
00036     m_retObject    = retobject;
00037     m_callsignEdit = NULL;
00038     m_channumEdit  = NULL;
00039     m_channameEdit = NULL;
00040     m_xmltvidEdit  = NULL;
00041 }
00042 
00043 bool ChannelEditor::Create(void)
00044 {
00045     if (!XMLParseBase::LoadWindowFromXML("osd.xml", "ChannelEditor", this))
00046         return false;
00047 
00048     MythUIButton *probeButton = NULL;
00049     MythUIButton *okButton    = NULL;
00050 
00051     bool err = false;
00052     UIUtilE::Assign(this, m_callsignEdit, "callsign", &err);
00053     UIUtilE::Assign(this, m_channumEdit,  "channum",  &err);
00054     UIUtilE::Assign(this, m_channameEdit, "channame", &err);
00055     UIUtilE::Assign(this, m_xmltvidEdit,  "XMLTV",    &err);
00056     UIUtilE::Assign(this, probeButton,    "probe",    &err);
00057     UIUtilE::Assign(this, okButton,       "ok",       &err);
00058 
00059     if (err)
00060     {
00061         LOG(VB_GENERAL, LOG_ERR, "Cannot load screen 'ChannelEditor'");
00062         return false;
00063     }
00064 
00065     BuildFocusList();
00066     connect(okButton,    SIGNAL(Clicked()), SLOT(Confirm()));
00067     connect(probeButton, SIGNAL(Clicked()), SLOT(Probe()));
00068     SetFocusWidget(okButton);
00069 
00070     return true;
00071 }
00072 
00073 void ChannelEditor::Confirm(void)
00074 {
00075     sendResult(1);
00076 }
00077 
00078 void ChannelEditor::Probe(void)
00079 {
00080     sendResult(2);
00081 }
00082 
00083 void ChannelEditor::SetText(QHash<QString,QString>&map)
00084 {
00085     if (map.contains("callsign"))
00086         m_callsignEdit->SetText(map.value("callsign"));
00087     if (map.contains("channum"))
00088         m_channumEdit->SetText(map.value("channum"));
00089     if (map.contains("channame"))
00090         m_channameEdit->SetText(map.value("channame"));
00091     if (map.contains("XMLTV"))
00092         m_xmltvidEdit->SetText(map.value("XMLTV"));
00093 }
00094 
00095 void ChannelEditor::GetText(QHash<QString,QString>&map)
00096 {
00097     map["callsign"] = m_callsignEdit->GetText();
00098     map["channum"]  = m_channumEdit->GetText();
00099     map["channame"] = m_channameEdit->GetText();
00100     map["XMLTV"]    = m_xmltvidEdit->GetText();
00101 }
00102 
00103 bool ChannelEditor::keyPressEvent(QKeyEvent *event)
00104 {
00105     if (GetFocusWidget()->keyPressEvent(event))
00106         return true;
00107 
00108     bool handled = false;
00109     QStringList actions;
00110     handled = GetMythMainWindow()->TranslateKeyPress("qt", event, actions);
00111 
00112     for (int i = 0; i < actions.size() && !handled; i++)
00113     {
00114         QString action = actions[i];
00115         if (action == "ESCAPE" )
00116         {
00117             sendResult(3);
00118             handled = true;
00119         }
00120     }
00121 
00122     if (!handled && MythScreenType::keyPressEvent(event))
00123         handled = true;
00124 
00125     return handled;
00126 }
00127 
00128 void ChannelEditor::sendResult(int result)
00129 {
00130     if (!m_retObject)
00131         return;
00132 
00133     QString  message = "";
00134     switch (result)
00135     {
00136         case 1:
00137             message = "DIALOG_EDITOR_OK_0";
00138             break;
00139         case 2:
00140             message = "DIALOG_EDITOR_PROBE_0";
00141             break;
00142         case 3:
00143             message = "DIALOG_EDITOR_QUIT_0";
00144             break;
00145     }
00146 
00147     DialogCompletionEvent *dce = new DialogCompletionEvent("", result,
00148                                                            "", message);
00149     QCoreApplication::postEvent(m_retObject, dce);
00150 }
00151 
00152 OSD::OSD(MythPlayer *player, QObject *parent, MythPainter *painter)
00153   : m_parent(player), m_ParentObject(parent), m_CurrentPainter(painter),
00154     m_Rect(QRect()), m_Effects(true), m_FadeTime(kOSDFadeTime), m_Dialog(NULL),
00155     m_PulsedDialogText(QString()), m_NextPulseUpdate(QDateTime()),
00156     m_Refresh(false),   m_UIScaleOverride(false),
00157     m_SavedWMult(1.0f), m_SavedHMult(1.0f),   m_SavedUIRect(QRect()),
00158     m_fontStretch(100), m_savedFontStretch(100),
00159     m_FunctionalType(kOSDFunctionalType_Default), m_FunctionalWindow(QString())
00160 {
00161     SetTimeouts(3000, 5000, 10000);
00162 }
00163 
00164 OSD::~OSD()
00165 {
00166     TearDown();
00167 }
00168 
00169 void OSD::TearDown(void)
00170 {
00171     foreach(MythScreenType* screen, m_Children)
00172         delete screen;
00173     m_Children.clear();
00174     m_Dialog = NULL;
00175 }
00176 
00177 bool OSD::Init(const QRect &rect, float font_aspect)
00178 {
00179     m_Rect = rect;
00180     m_fontStretch = (int)((font_aspect * 100) + 0.5f);
00181     OverrideUIScale();
00182     LoadWindows();
00183     RevertUIScale();
00184 
00185     if (!m_Children.size())
00186     {
00187         LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to load any windows.");
00188         return false;
00189     }
00190 
00191     LOG(VB_PLAYBACK, LOG_INFO, LOC +
00192         QString("Loaded OSD: size %1x%2 offset %3+%4")
00193             .arg(m_Rect.width()).arg(m_Rect.height())
00194             .arg(m_Rect.left()).arg(m_Rect.top()));
00195     HideAll(false);
00196     return true;
00197 }
00198 
00199 void OSD::SetPainter(MythPainter *painter)
00200 {
00201     if (painter == m_CurrentPainter)
00202         return;
00203 
00204     m_CurrentPainter = painter;
00205     QMapIterator<QString, MythScreenType*> it(m_Children);
00206     while (it.hasNext())
00207     {
00208         it.next();
00209         it.value()->SetPainter(m_CurrentPainter);
00210     }
00211 }
00212 
00213 void OSD::OverrideUIScale(void)
00214 {
00215     QRect uirect = GetMythMainWindow()->GetUIScreenRect();
00216     if (uirect == m_Rect)
00217         return;
00218 
00219     m_savedFontStretch = GetMythUI()->GetFontStretch();
00220     GetMythUI()->SetFontStretch(m_fontStretch);
00221 
00222     int width, height;
00223     MythUIHelper::getMythUI()->GetScreenSettings(width,  m_SavedWMult,
00224                                                  height, m_SavedHMult);
00225     QSize theme_size = MythUIHelper::getMythUI()->GetBaseSize();
00226     m_SavedUIRect = uirect;
00227     LOG(VB_GENERAL, LOG_INFO, LOC + QString("Base theme size: %1x%2")
00228                .arg(theme_size.width()).arg(theme_size.height()));
00229     float tmp_wmult = (float)m_Rect.size().width() / (float)theme_size.width();
00230     float tmp_hmult = (float)m_Rect.size().height() /
00231                       (float)theme_size.height();
00232     LOG(VB_GENERAL, LOG_INFO, LOC + QString("Scaling factors: %1x%2")
00233                .arg(tmp_wmult).arg(tmp_hmult));
00234     m_UIScaleOverride = true;
00235     GetMythMainWindow()->SetScalingFactors(tmp_wmult, tmp_hmult);
00236     GetMythMainWindow()->SetUIScreenRect(m_Rect);
00237 }
00238 
00239 void OSD::RevertUIScale(void)
00240 {
00241     if (m_UIScaleOverride)
00242     {
00243         GetMythUI()->SetFontStretch(m_savedFontStretch);
00244         GetMythMainWindow()->SetScalingFactors(m_SavedWMult, m_SavedHMult);
00245         GetMythMainWindow()->SetUIScreenRect(m_SavedUIRect);
00246     }
00247     m_UIScaleOverride = false;
00248 }
00249 
00250 bool OSD::Reinit(const QRect &rect, float font_aspect)
00251 {
00252     m_Refresh = true;
00253     int new_stretch = (int)((font_aspect * 100) + 0.5f);
00254     if ((rect == m_Rect) && (new_stretch == m_fontStretch))
00255         return true;
00256 
00257     HideAll(false);
00258     TearDown();
00259     if (!Init(rect, font_aspect))
00260     {
00261         LOG(VB_GENERAL, LOG_ERR, LOC + QString("Failed to re-init OSD."));
00262         return false;
00263     }
00264     return true;
00265 }
00266 
00267 bool OSD::IsVisible(void)
00268 {
00269     foreach(MythScreenType* child, m_Children)
00270         if (child->IsVisible() &&
00271             child->objectName() != OSD_WIN_SUBTITLE &&
00272             child->objectName() != OSD_WIN_TELETEXT &&
00273             child->objectName() != OSD_WIN_BDOVERLAY &&
00274             child->objectName() != OSD_WIN_INTERACT)
00275             return true;
00276 
00277     return false;
00278 }
00279 
00280 void OSD::HideAll(bool keepsubs, MythScreenType* except)
00281 {
00282     QMutableMapIterator<QString, MythScreenType*> it(m_Children);
00283     while (it.hasNext())
00284     {
00285         it.next();
00286         bool match1 = keepsubs &&
00287                      (it.key() == OSD_WIN_SUBTITLE  ||
00288                       it.key() == OSD_WIN_TELETEXT);
00289         bool match2 = it.key() == OSD_WIN_BDOVERLAY ||
00290                       it.key() == OSD_WIN_INTERACT  ||
00291                       it.value() == except;
00292         if (!(match1 || match2))
00293             HideWindow(it.key());
00294     }
00295 }
00296 
00297 void OSD::LoadWindows(void)
00298 {
00299     static const char* default_windows[7] = {
00300         "osd_message", "osd_input", "program_info", "browse_info", "osd_status",
00301         "osd_program_editor", "osd_debug"};
00302 
00303     for (int i = 0; i < 7; i++)
00304     {
00305         const char* window = default_windows[i];
00306         MythOSDWindow *win = new MythOSDWindow(NULL, window, true);
00307         if (win)
00308         {
00309             win->SetPainter(m_CurrentPainter);
00310             if (win->Create())
00311             {
00312                 PositionWindow(win);
00313                 LOG(VB_PLAYBACK, LOG_INFO, LOC +
00314                     QString("Loaded window %1").arg(window));
00315                 m_Children.insert(window, win);
00316             }
00317         }
00318         else
00319         {
00320             LOG(VB_GENERAL, LOG_ERR, LOC + QString("Failed to load window %1")
00321                 .arg(window));
00322             delete win;
00323         }
00324     }
00325 }
00326 
00327 void OSD::SetValues(const QString &window, QHash<QString,int> &map,
00328                     OSDTimeout timeout)
00329 {
00330     MythScreenType *win = GetWindow(window);
00331     if (!win)
00332         return;
00333 
00334     bool found = false;
00335     if (map.contains("position"))
00336     {
00337         MythUIProgressBar *bar = dynamic_cast<MythUIProgressBar *> (win->GetChild("position"));
00338         if (bar)
00339         {
00340             bar->SetVisible(true);
00341             bar->SetStart(0);
00342             bar->SetTotal(1000);
00343             bar->SetUsed(map.value("position"));
00344             found = true;
00345         }
00346     }
00347     if (map.contains("relposition"))
00348     {
00349         MythUIProgressBar *bar = dynamic_cast<MythUIProgressBar *> (win->GetChild("relposition"));
00350         if (bar)
00351         {
00352             bar->SetVisible(true);
00353             bar->SetStart(0);
00354             bar->SetTotal(1000);
00355             bar->SetUsed(map.value("relposition"));
00356             found = true;
00357         }
00358     }
00359 
00360     if (found)
00361         SetExpiry(window, timeout);
00362 }
00363 
00364 void OSD::SetValues(const QString &window, QHash<QString,float> &map,
00365                     OSDTimeout timeout)
00366 {
00367     MythScreenType *win = GetWindow(window);
00368     if (!win)
00369         return;
00370 
00371     bool found = false;
00372     if (map.contains("position"))
00373     {
00374         MythUIEditBar *edit = dynamic_cast<MythUIEditBar *> (win->GetChild("editbar"));
00375         if (edit)
00376             edit->SetPosition(map.value("position"));
00377     }
00378 
00379     if (found)
00380         SetExpiry(window, timeout);
00381 }
00382 
00383 void OSD::SetText(const QString &window, QHash<QString,QString> &map,
00384                   OSDTimeout timeout)
00385 {
00386     MythScreenType *win = GetWindow(window);
00387     if (!win)
00388         return;
00389 
00390     if (map.contains("numstars"))
00391     {
00392         MythUIStateType *state = dynamic_cast<MythUIStateType *> (win->GetChild("ratingstate"));
00393         if (state)
00394             state->DisplayState(map["numstars"]);
00395     }
00396     if (map.contains("tvstate"))
00397     {
00398         MythUIStateType *state = dynamic_cast<MythUIStateType *> (win->GetChild("tvstate"));
00399         if (state)
00400             state->DisplayState(map["tvstate"]);
00401     }
00402     if (map.contains("videocodec"))
00403     {
00404         MythUIStateType *state = dynamic_cast<MythUIStateType *> (win->GetChild("videocodec"));
00405         if (state)
00406             state->DisplayState(map["videocodec"]);
00407     }
00408     if (map.contains("videodescrip"))
00409     {
00410         MythUIStateType *state = dynamic_cast<MythUIStateType *> (win->GetChild("videodescrip"));
00411         if (state)
00412             state->DisplayState(map["videodescrip"]);
00413     }
00414     if (map.contains("audiocodec"))
00415     {
00416         MythUIStateType *state = dynamic_cast<MythUIStateType *> (win->GetChild("audiocodec"));
00417         if (state)
00418             state->DisplayState(map["audiocodec"]);
00419     }
00420     if (map.contains("audiochannels"))
00421     {
00422         MythUIStateType *state = dynamic_cast<MythUIStateType *> (win->GetChild("audiochannels"));
00423         if (state)
00424             state->DisplayState(map["audiochannels"]);
00425     }
00426     if (map.contains("chanid"))
00427     {
00428         MythUIImage *icon = dynamic_cast<MythUIImage *> (win->GetChild("iconpath"));
00429         if (icon)
00430         {
00431             icon->Reset();
00432 
00433             uint chanid = map["chanid"].toUInt();
00434             QString iconpath;
00435             if (map.contains("iconpath"))
00436                 iconpath = map["iconpath"];
00437             else
00438                 iconpath = ChannelUtil::GetIcon(chanid);
00439 
00440             if (!iconpath.isEmpty())
00441             {
00442                 QString iconurl =
00443                                 gCoreContext->GetMasterHostPrefix("ChannelIcons",
00444                                                                   iconpath);
00445 
00446                 icon->SetFilename(iconurl);
00447                 icon->Load(false);
00448             }
00449         }
00450     }
00451     if (map.contains("inetref"))
00452     {
00453         MythUIImage *cover = dynamic_cast<MythUIImage *> (win->GetChild("coverart"));
00454         if (cover && map.contains("coverartpath"))
00455         {
00456             QString coverpath = map["coverartpath"];
00457             cover->SetFilename(coverpath);
00458             cover->Load(false);
00459         }
00460         MythUIImage *fanart = dynamic_cast<MythUIImage *> (win->GetChild("fanart"));
00461         if (fanart && map.contains("fanartpath"))
00462         {
00463             QString fanartpath = map["fanartpath"];
00464             fanart->SetFilename(fanartpath);
00465             fanart->Load(false);
00466         }
00467         MythUIImage *banner = dynamic_cast<MythUIImage *> (win->GetChild("banner"));
00468         if (banner && map.contains("bannerpath"))
00469         {
00470             QString bannerpath = map["bannerpath"];
00471             banner->SetFilename(bannerpath);
00472             banner->Load(false);
00473         }
00474         MythUIImage *screenshot = dynamic_cast<MythUIImage *> (win->GetChild("screenshot"));
00475         if (screenshot && map.contains("screenshotpath"))
00476         {
00477             QString screenshotpath = map["screenshotpath"];
00478             screenshot->SetFilename(screenshotpath);
00479             screenshot->Load(false);
00480         }
00481     }
00482     if (map.contains("nightmode"))
00483     {
00484         MythUIStateType *state = dynamic_cast<MythUIStateType *> (win->GetChild("nightmode"));
00485         if (state)
00486             state->DisplayState(map["nightmode"]);
00487     }
00488     if (map.contains("mediatype"))
00489     {
00490         MythUIStateType *state = dynamic_cast<MythUIStateType *> (win->GetChild("mediatype"));
00491         if (state)
00492             state->DisplayState(map["mediatype"]);
00493     }
00494 
00495     MythUIProgressBar *bar =
00496         dynamic_cast<MythUIProgressBar *>(win->GetChild("elapsedpercent"));
00497     if (bar)
00498     {
00499         int startts = map["startts"].toInt();
00500         int endts   = map["endts"].toInt();
00501         int nowts   = QDateTime::currentDateTime().toTime_t();
00502         if (startts > nowts)
00503         {
00504             bar->SetUsed(0);
00505         }
00506         else if (endts < nowts)
00507         {
00508             bar->SetUsed(1000);
00509         }
00510         else
00511         {
00512             int duration = endts - startts;
00513             if (duration > 0)
00514                 bar->SetUsed(1000 * (nowts - startts) / duration);
00515             else
00516                 bar->SetUsed(0);
00517         }
00518         bar->SetVisible(startts > 0);
00519         bar->SetStart(0);
00520         bar->SetTotal(1000);
00521     }
00522 
00523     win->SetVisible(true);
00524 
00525     if (win == m_Dialog)
00526     {
00527         ChannelEditor *edit = dynamic_cast<ChannelEditor*>(m_Dialog);
00528         if (edit)
00529             edit->SetText(map);
00530     }
00531     else
00532         win->SetTextFromMap(map);
00533 
00534     SetExpiry(window, timeout);
00535 }
00536 
00537 void OSD::SetRegions(const QString &window, frm_dir_map_t &map,
00538                      long long total)
00539 {
00540     MythScreenType *win = GetWindow(window);
00541     if (!win)
00542         return;
00543 
00544     MythUIEditBar *bar = dynamic_cast<MythUIEditBar*>(win->GetChild("editbar"));
00545     if (!bar)
00546         return;
00547 
00548     bar->ClearRegions();
00549     if (!map.size() || total < 1)
00550     {
00551         bar->Display();
00552         return;
00553     }
00554 
00555     long long start = -1;
00556     long long end   = -1;
00557     bool first = true;
00558     QMapIterator<uint64_t, MarkTypes> it(map);
00559     while (it.hasNext())
00560     {
00561         bool error = false;
00562         it.next();
00563         if (it.value() == MARK_CUT_START)
00564         {
00565             start = it.key();
00566             if (end > -1)
00567                 error = true;
00568         }
00569         else if (it.value() == MARK_CUT_END)
00570         {
00571             if (first)
00572                 start = 0;
00573             if (start < 0)
00574                 error = true;
00575             end = it.key();
00576         }
00577         else if (it.value() == MARK_PLACEHOLDER)
00578         {
00579             start = end = it.key();
00580         }
00581         first = false;
00582 
00583         if (error)
00584         {
00585             LOG(VB_GENERAL, LOG_ERR, LOC + "deleteMap discontinuity");
00586             start = -1;
00587             end   = -1;
00588         }
00589 
00590         if (start >=0 && end >= 0)
00591         {
00592             bar->AddRegion((float)((double)start/(double)total),
00593                            (float)((double)end/(double)total));
00594             start = -1;
00595             end   = -1;
00596         }
00597     }
00598     if (start > -1 && end < 0)
00599         bar->AddRegion((float)((double)start/(double)total), 1.0f);
00600 
00601     bar->Display();
00602 }
00603 
00604 bool OSD::DrawDirect(MythPainter* painter, QSize size, bool repaint)
00605 {
00606     if (!painter)
00607         return false;
00608 
00609     bool visible = false;
00610     bool redraw  = m_Refresh;
00611     m_Refresh    = false;
00612     QTime now = QTime::currentTime();
00613 
00614     CheckExpiry();
00615     QMap<QString,MythScreenType*>::const_iterator it;
00616     for (it = m_Children.begin(); it != m_Children.end(); ++it)
00617     {
00618         if (it.value()->IsVisible())
00619         {
00620             visible = true;
00621             it.value()->Pulse();
00622             if (m_Effects && m_ExpireTimes.contains(it.value()))
00623             {
00624                 QTime expires = m_ExpireTimes.value(it.value()).time();
00625                 int left = now.msecsTo(expires);
00626                 if (left < m_FadeTime)
00627                     (*it)->SetAlpha((255 * left) / m_FadeTime);
00628             }
00629             if (it.value()->NeedsRedraw())
00630                 redraw = true;
00631         }
00632     }
00633 
00634     redraw |= repaint;
00635 
00636     if (redraw && visible)
00637     {
00638         QRect cliprect = QRect(QPoint(0, 0), size);
00639         painter->Begin(NULL);
00640         for (it = m_Children.begin(); it != m_Children.end(); ++it)
00641         {
00642             if (it.value()->IsVisible())
00643             {
00644                 it.value()->Draw(painter, 0, 0, 255, cliprect);
00645                 it.value()->SetAlpha(255);
00646                 it.value()->ResetNeedsRedraw();
00647             }
00648         }
00649         painter->End();
00650     }
00651 
00652     return visible;
00653 }
00654 
00655 QRegion OSD::Draw(MythPainter* painter, QPaintDevice *device, QSize size,
00656                   QRegion &changed, int alignx, int aligny)
00657 {
00658     bool redraw     = m_Refresh;
00659     QRegion visible = QRegion();
00660     QRegion dirty   = m_Refresh ? QRegion(QRect(QPoint(0,0), m_Rect.size())) :
00661                                   QRegion();
00662     m_Refresh       = false;
00663 
00664     if (!painter || !device)
00665         return visible;
00666 
00667     QTime now = QTime::currentTime();
00668     CheckExpiry();
00669 
00670     // first update for alpha pulse and fade
00671     QMap<QString,MythScreenType*>::const_iterator it;
00672     for (it = m_Children.begin(); it != m_Children.end(); ++it)
00673     {
00674         if (it.value()->IsVisible())
00675         {
00676             QRect vis = it.value()->GetArea().toQRect();
00677             if (visible.isEmpty())
00678                 visible = QRegion(vis);
00679             else
00680                 visible = visible.united(vis);
00681 
00682             it.value()->Pulse();
00683             if (m_Effects && m_ExpireTimes.contains(it.value()))
00684             {
00685                 QTime expires = m_ExpireTimes.value(it.value()).time();
00686                 int left = now.msecsTo(expires);
00687                 if (left < m_FadeTime)
00688                     (*it)->SetAlpha((255 * left) / m_FadeTime);
00689             }
00690         }
00691 
00692         if (it.value()->NeedsRedraw())
00693         {
00694             QRegion area = it.value()->GetDirtyArea();
00695             dirty = dirty.united(area);
00696             redraw = true;
00697         }
00698     }
00699 
00700     if (redraw)
00701     {
00702         // clear the dirty area
00703         painter->Clear(device, dirty);
00704 
00705         // set redraw for any widgets that may now need a partial repaint
00706         for (it = m_Children.begin(); it != m_Children.end(); ++it)
00707         {
00708             if (it.value()->IsVisible() && !it.value()->NeedsRedraw() &&
00709                 dirty.intersects(it.value()->GetArea().toQRect()))
00710             {
00711                 it.value()->SetRedraw();
00712             }
00713         }
00714 
00715         // and finally draw
00716         QRect cliprect = dirty.boundingRect();
00717         painter->Begin(device);
00718         painter->SetClipRegion(dirty);
00719         // TODO painting in reverse may be more efficient...
00720         for (it = m_Children.begin(); it != m_Children.end(); ++it)
00721         {
00722             if (it.value()->NeedsRedraw())
00723             {
00724                 if (it.value()->IsVisible())
00725                     it.value()->Draw(painter, 0, 0, 255, cliprect);
00726                 it.value()->SetAlpha(255);
00727                 it.value()->ResetNeedsRedraw();
00728             }
00729         }
00730         painter->End();
00731     }
00732 
00733     changed = dirty;
00734 
00735     if (visible.isEmpty() || (!alignx && !aligny))
00736         return visible;
00737 
00738     // assist yuv blending with some friendly alignments
00739     QRegion aligned;
00740     QVector<QRect> rects = visible.rects();
00741     for (int i = 0; i < rects.size(); i++)
00742     {
00743         QRect r   = rects[i];
00744         int left  = r.left() & ~(alignx - 1);
00745         int top   = r.top()  & ~(aligny - 1);
00746         int right = (r.left() + r.width());
00747         int bot   = (r.top() + r.height());
00748         if (right & (alignx - 1))
00749             right += alignx - (right & (alignx - 1));
00750         if (bot % aligny)
00751             bot += aligny - (bot % aligny);
00752         aligned = aligned.united(QRegion(left, top, right - left, bot - top));
00753     }
00754 
00755     return aligned.intersected(QRect(QPoint(0,0), size));
00756 }
00757 
00758 void OSD::CheckExpiry(void)
00759 {
00760     QDateTime now = QDateTime::currentDateTime();
00761     QMutableHashIterator<MythScreenType*, QDateTime> it(m_ExpireTimes);
00762     while (it.hasNext())
00763     {
00764         it.next();
00765         if (it.value() < now)
00766         {
00767             if (it.key() == m_Dialog)
00768                 DialogQuit();
00769             else
00770                 HideWindow(m_Children.key(it.key()));
00771         }
00772         else if (it.key() == m_Dialog)
00773         {
00774             if (!m_PulsedDialogText.isEmpty() && now > m_NextPulseUpdate)
00775             {
00776                 QString newtext = m_PulsedDialogText;
00777                 MythDialogBox *dialog = dynamic_cast<MythDialogBox*>(m_Dialog);
00778                 if (dialog)
00779                 {
00780                     QString replace = QObject::tr("%n second(s)", NULL,
00781                                                   now.secsTo(it.value()));
00782                     dialog->SetText(newtext.replace("%d", replace));
00783                 }
00784                 MythConfirmationDialog *cdialog = dynamic_cast<MythConfirmationDialog*>(m_Dialog);
00785                 if (cdialog)
00786                 {
00787                     QString replace = QString::number(now.secsTo(it.value()));
00788                     cdialog->SetMessage(newtext.replace("%d", replace));
00789                 }
00790                 m_NextPulseUpdate = now.addSecs(1);
00791             }
00792         }
00793     }
00794 }
00795 
00796 void OSD::SetExpiry(const QString &window, enum OSDTimeout timeout,
00797                     int custom_timeout)
00798 {
00799     if (timeout == kOSDTimeout_Ignore && !custom_timeout)
00800         return;
00801 
00802     MythScreenType *win = GetWindow(window);
00803     int time = custom_timeout ? custom_timeout : m_Timeouts[timeout];
00804     if ((time > 0) && win)
00805     {
00806         QDateTime expires = QDateTime::currentDateTime().addMSecs(time);
00807         m_ExpireTimes.insert(win, expires);
00808     }
00809     else if ((time < 0) && win)
00810     {
00811         if (m_ExpireTimes.contains(win))
00812             m_ExpireTimes.remove(win);
00813     }
00814 }
00815 
00816 void OSD::SetTimeouts(int _short, int _medium, int _long)
00817 {
00818     m_Timeouts[kOSDTimeout_None]  = -1;
00819     m_Timeouts[kOSDTimeout_Short] = _short;
00820     m_Timeouts[kOSDTimeout_Med]   = _medium;
00821     m_Timeouts[kOSDTimeout_Long]  = _long;
00822 }
00823 
00824 bool OSD::IsWindowVisible(const QString &window)
00825 {
00826     if (!m_Children.contains(window))
00827         return false;
00828 
00829     return m_Children.value(window)->IsVisible(/*true*/);
00830 }
00831 
00832 void OSD::ResetWindow(const QString &window)
00833 {
00834     if (!m_Children.contains(window))
00835         return;
00836 
00837     m_Children.value(window)->Reset();
00838 }
00839 
00840 void OSD::PositionWindow(MythScreenType *window)
00841 {
00842     if (!window)
00843         return;
00844 
00845     MythRect rect = window->GetArea();
00846     rect.translate(m_Rect.left(), m_Rect.top());
00847     window->SetArea(rect);
00848 }
00849 
00850 void OSD::RemoveWindow(const QString &window)
00851 {
00852     if (!m_Children.contains(window))
00853         return;
00854 
00855     HideWindow(window);
00856     MythScreenType *child = m_Children.value(window);
00857     m_Children.remove(window);
00858     delete child;
00859 }
00860 
00861 MythScreenType *OSD::GetWindow(const QString &window)
00862 {
00863     if (m_Children.contains(window))
00864         return m_Children.value(window);
00865 
00866     MythScreenType *new_window = NULL;
00867 
00868     if (window == OSD_WIN_INTERACT)
00869     {
00870         InteractiveScreen *screen = new InteractiveScreen(m_parent, window);
00871         new_window = (MythScreenType*) screen;
00872     }
00873     else if (window == OSD_WIN_BDOVERLAY)
00874     {
00875         BDOverlayScreen *screen = new BDOverlayScreen(m_parent, window);
00876         new_window = (MythScreenType*) screen;
00877     }
00878     else
00879     {
00880         MythOSDWindow *screen = new MythOSDWindow(NULL, window, false);
00881         new_window = (MythScreenType*) screen;
00882     }
00883 
00884     if (new_window)
00885     {
00886         new_window->SetPainter(m_CurrentPainter);
00887         if (new_window->Create())
00888         {
00889             m_Children.insert(window, new_window);
00890             LOG(VB_PLAYBACK, LOG_INFO, LOC +
00891                 QString("Created window %1").arg(window));
00892             return new_window;
00893         }
00894     }
00895 
00896     LOG(VB_GENERAL, LOG_ERR, LOC + QString("Failed to create window %1")
00897             .arg(window));
00898     delete new_window;
00899     return NULL;
00900 }
00901 
00902 void OSD::SetFunctionalWindow(const QString window, enum OSDFunctionalType type)
00903 {
00904     if (m_FunctionalType != kOSDFunctionalType_Default &&
00905         m_FunctionalType != type)
00906         SendHideEvent();
00907 
00908     m_FunctionalWindow = window;
00909     m_FunctionalType   = type;
00910 }
00911 
00912 void OSD::HideWindow(const QString &window)
00913 {
00914     if (!m_Children.contains(window))
00915         return;
00916     m_Children.value(window)->SetVisible(false);
00917     m_Children.value(window)->Close(); // for InteractiveScreen
00918     SetExpiry(window, kOSDTimeout_None);
00919     m_Refresh = true;
00920 
00921     if (m_FunctionalType != kOSDFunctionalType_Default)
00922     {
00923         bool valid   = m_Children.contains(m_FunctionalWindow);
00924         bool visible = valid && m_Children.value(m_FunctionalWindow)->IsVisible(false);
00925         if (!valid || !visible)
00926         {
00927             SendHideEvent();
00928             m_FunctionalType = kOSDFunctionalType_Default;
00929             m_FunctionalWindow = QString();
00930         }
00931     }
00932 }
00933 
00934 void OSD::SendHideEvent(void)
00935 {
00936     OSDHideEvent *event = new OSDHideEvent(m_FunctionalType);
00937     QCoreApplication::postEvent(m_ParentObject, event);
00938 }
00939 
00940 bool OSD::HasWindow(const QString &window)
00941 {
00942     return m_Children.contains(window);
00943 }
00944 
00945 bool OSD::DialogVisible(QString window)
00946 {
00947     if (!m_Dialog || window.isEmpty())
00948         return m_Dialog;
00949 
00950     return m_Dialog->objectName() == window;
00951 }
00952 
00953 bool OSD::DialogHandleKeypress(QKeyEvent *e)
00954 {
00955     if (!m_Dialog)
00956         return false;
00957     return m_Dialog->keyPressEvent(e);
00958 }
00959 
00960 void OSD::DialogQuit(void)
00961 {
00962     if (!m_Dialog)
00963         return;
00964 
00965     RemoveWindow(m_Dialog->objectName());
00966     m_Dialog = NULL;
00967     m_PulsedDialogText = QString();
00968 }
00969 
00970 void OSD::DialogShow(const QString &window, const QString &text, int updatefor)
00971 {
00972     if (m_Dialog)
00973     {
00974         QString current = m_Dialog->objectName();
00975         if (current != window)
00976         {
00977             DialogQuit();
00978         }
00979         else
00980         {
00981             MythDialogBox *dialog = dynamic_cast<MythDialogBox*>(m_Dialog);
00982             if (dialog)
00983                 dialog->Reset();
00984 
00985             DialogSetText(text);
00986         }
00987     }
00988 
00989     if (!m_Dialog)
00990     {
00991         OverrideUIScale();
00992         MythScreenType *dialog;
00993         if (window == OSD_DLG_EDITOR)
00994             dialog = new ChannelEditor(m_ParentObject, window.toLatin1());
00995         else if (window == OSD_DLG_CONFIRM)
00996             dialog = new MythConfirmationDialog(NULL, text, false);
00997         else
00998             dialog = new MythDialogBox(text, NULL, window.toLatin1(), false, true);
00999 
01000         if (dialog)
01001         {
01002             dialog->SetPainter(m_CurrentPainter);
01003             if (dialog->Create())
01004             {
01005                 PositionWindow(dialog);
01006                 m_Dialog = dialog;
01007                 MythDialogBox *dbox = dynamic_cast<MythDialogBox*>(m_Dialog);
01008                 if (dbox)
01009                     dbox->SetReturnEvent(m_ParentObject, window);
01010                 MythConfirmationDialog *cbox = dynamic_cast<MythConfirmationDialog*>(m_Dialog);
01011                 if (cbox)
01012                 {
01013                     cbox->SetReturnEvent(m_ParentObject, window);
01014                     cbox->SetData("DIALOG_CONFIRM_X_X");
01015                 }
01016                 m_Children.insert(window, m_Dialog);
01017             }
01018         }
01019         else
01020         {
01021             RevertUIScale();
01022             delete dialog;
01023             return;
01024         }
01025         RevertUIScale();
01026     }
01027 
01028     if (updatefor)
01029     {
01030         m_NextPulseUpdate  = QDateTime::currentDateTime();
01031         m_PulsedDialogText = text;
01032         SetExpiry(window, kOSDTimeout_None, updatefor);
01033     }
01034 
01035     DialogBack();
01036     HideAll(true, m_Dialog);
01037     m_Dialog->SetVisible(true);
01038 }
01039 
01040 void OSD::DialogSetText(const QString &text)
01041 {
01042     MythDialogBox *dialog = dynamic_cast<MythDialogBox*>(m_Dialog);
01043     if (dialog)
01044         dialog->SetText(text);
01045 }
01046 
01047 void OSD::DialogBack(QString text, QVariant data, bool exit)
01048 {
01049     MythDialogBox *dialog = dynamic_cast<MythDialogBox*>(m_Dialog);
01050     if (dialog)
01051     {
01052         dialog->SetBackAction(text, data);
01053         if (exit)
01054             dialog->SetExitAction(text, data);
01055     }
01056 }
01057 
01058 void OSD::DialogAddButton(QString text, QVariant data, bool menu, bool current)
01059 {
01060     MythDialogBox *dialog = dynamic_cast<MythDialogBox*>(m_Dialog);
01061     if (dialog)
01062         dialog->AddButton(text, data, menu, current);
01063 }
01064 
01065 void OSD::DialogGetText(QHash<QString,QString> &map)
01066 {
01067     ChannelEditor *edit = dynamic_cast<ChannelEditor*>(m_Dialog);
01068     if (edit)
01069         edit->GetText(map);
01070 }
01071 
01072 TeletextScreen* OSD::InitTeletext(void)
01073 {
01074     TeletextScreen *tt = NULL;
01075     if (m_Children.contains(OSD_WIN_TELETEXT))
01076     {
01077         tt = (TeletextScreen*)m_Children.value(OSD_WIN_TELETEXT);
01078     }
01079     else
01080     {
01081         OverrideUIScale();
01082         tt = new TeletextScreen(m_parent, OSD_WIN_TELETEXT, m_fontStretch);
01083         if (tt)
01084         {
01085             tt->SetPainter(m_CurrentPainter);
01086             if (tt->Create())
01087             {
01088                 m_Children.insert(OSD_WIN_TELETEXT, tt);
01089                 LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Created window %1")
01090                     .arg(OSD_WIN_TELETEXT));
01091             }
01092             else
01093             {
01094                 delete tt;
01095                 tt = NULL;
01096             }
01097         }
01098         RevertUIScale();
01099     }
01100     if (!tt)
01101     {
01102         LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to create Teletext window");
01103         return NULL;
01104     }
01105 
01106     HideWindow(OSD_WIN_TELETEXT);
01107     tt->SetDisplaying(false);
01108     return tt;
01109 }
01110 
01111 void OSD::EnableTeletext(bool enable, int page)
01112 {
01113     TeletextScreen *tt = InitTeletext();
01114     if (!tt)
01115         return;
01116 
01117     tt->SetVisible(enable);
01118     tt->SetDisplaying(enable);
01119     if (enable)
01120     {
01121         tt->SetPage(page, -1);
01122         LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Enabled teletext page %1")
01123                                    .arg(page));
01124     }
01125     else
01126         LOG(VB_PLAYBACK, LOG_INFO, LOC + "Disabled teletext");
01127 }
01128 
01129 bool OSD::TeletextAction(const QString &action)
01130 {
01131     if (!HasWindow(OSD_WIN_TELETEXT))
01132         return false;
01133 
01134     TeletextScreen* tt = (TeletextScreen*)m_Children.value(OSD_WIN_TELETEXT);
01135     if (tt)
01136         return tt->KeyPress(action);
01137     return false;
01138 }
01139 
01140 void OSD::TeletextReset(void)
01141 {
01142     if (!HasWindow(OSD_WIN_TELETEXT))
01143         return;
01144 
01145     TeletextScreen* tt = InitTeletext();
01146     if (tt)
01147         tt->Reset();
01148 }
01149 
01150 void OSD::TeletextClear(void)
01151 {
01152     if (!HasWindow(OSD_WIN_TELETEXT))
01153         return;
01154 
01155     TeletextScreen* tt = (TeletextScreen*)m_Children.value(OSD_WIN_TELETEXT);
01156     if (tt)
01157         tt->ClearScreen();
01158 }
01159 
01160 SubtitleScreen* OSD::InitSubtitles(void)
01161 {
01162     SubtitleScreen *sub = NULL;
01163     if (m_Children.contains(OSD_WIN_SUBTITLE))
01164     {
01165         sub = (SubtitleScreen*)m_Children.value(OSD_WIN_SUBTITLE);
01166     }
01167     else
01168     {
01169         OverrideUIScale();
01170         sub = new SubtitleScreen(m_parent, OSD_WIN_SUBTITLE, m_fontStretch);
01171         if (sub)
01172         {
01173             sub->SetPainter(m_CurrentPainter);
01174             if (sub->Create())
01175             {
01176                 m_Children.insert(OSD_WIN_SUBTITLE, sub);
01177                 LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Created window %1")
01178                     .arg(OSD_WIN_SUBTITLE));
01179             }
01180             else
01181             {
01182                 delete sub;
01183                 sub = NULL;
01184             }
01185         }
01186         RevertUIScale();
01187     }
01188     if (!sub)
01189     {
01190         LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to create subtitle window");
01191         return NULL;
01192     }
01193     return sub;
01194 }
01195 
01196 void OSD::EnableSubtitles(int type, bool forced_only)
01197 {
01198     SubtitleScreen *sub = InitSubtitles();
01199     if (sub)
01200         sub->EnableSubtitles(type, forced_only);
01201 }
01202 
01203 void OSD::DisableForcedSubtitles(void)
01204 {
01205     if (!HasWindow(OSD_WIN_SUBTITLE))
01206         return;
01207 
01208     SubtitleScreen *sub = InitSubtitles();
01209     sub->DisableForcedSubtitles();
01210 }
01211 
01212 void OSD::ClearSubtitles(void)
01213 {
01214     if (!HasWindow(OSD_WIN_SUBTITLE))
01215         return;
01216 
01217     SubtitleScreen* sub = InitSubtitles();
01218     if (sub)
01219         sub->ClearAllSubtitles();
01220 }
01221 
01222 void OSD::DisplayDVDButton(AVSubtitle* dvdButton, QRect &pos)
01223 {
01224     if (!dvdButton)
01225         return;
01226 
01227     SubtitleScreen* sub = InitSubtitles();
01228     if (sub)
01229     {
01230         EnableSubtitles(kDisplayDVDButton);
01231         sub->DisplayDVDButton(dvdButton, pos);
01232     }
01233 }
01234 
01235 void OSD::DisplayBDOverlay(BDOverlay* overlay)
01236 {
01237     if (!overlay)
01238         return;
01239 
01240     BDOverlayScreen* bd = (BDOverlayScreen*)GetWindow(OSD_WIN_BDOVERLAY);
01241     if (bd)
01242         bd->DisplayBDOverlay(overlay);
01243 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends