|
MythTV
0.26-pre
|
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 }
1.7.6.1