00001
00002 #include <QCoreApplication>
00003
00004
00005 #include "mythlogging.h"
00006
00007
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
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
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
00703 painter->Clear(device, dirty);
00704
00705
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
00716 QRect cliprect = dirty.boundingRect();
00717 painter->Begin(device);
00718 painter->SetClipRegion(dirty);
00719
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
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();
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();
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 }