00001
00002 #include <cmath>
00003 #include <unistd.h>
00004
00005
00006 #include <iostream>
00007 #include <algorithm>
00008 using namespace std;
00009
00010
00011 #include <qstring.h>
00012 #include <qimage.h>
00013 #include <qpixmap.h>
00014 #include <qbitmap.h>
00015 #include <qdir.h>
00016 #include <qfile.h>
00017 #include <qcolor.h>
00018 #include <qregexp.h>
00019
00020
00021 #include "ttfont.h"
00022 #include "osd.h"
00023 #include "osdtypes.h"
00024 #include "osdsurface.h"
00025 #include "mythcontext.h"
00026 #include "textsubtitleparser.h"
00027 #include "libmyth/oldsettings.h"
00028 #include "udpnotify.h"
00029 #include "compat.h"
00030
00031 #include "osdtypeteletext.h"
00032 #include "osdlistbtntype.h"
00033
00034 static char *cc708_default_font_names[16];
00035 static bool cc708_defaults_initialized = false;
00036 static QMutex cc708_init_lock;
00037 static void initialize_osd_fonts(void);
00038
00039 static float sq(float a) { return a*a; }
00040
00041 #define LOC QString("OSD: ")
00042 #define LOC_ERR QString("OSD, Error: ")
00043
00044 OSD::OSD()
00045 : QObject(),
00046 needPillarBox(false),
00047 themepath(FindTheme(gContext->GetSetting("OSDTheme"))),
00048 wscale(1.0f),
00049 m_themeinfo(new ThemeInfo(themepath)),
00050 m_setsvisible(false),
00051 totalfadetime(0), timeType(0),
00052 timeFormat(""), setList(new vector<OSDSet*>),
00053 editarrowleft(NULL), editarrowright(NULL),
00054 changed(false), runningTreeMenu(NULL),
00055 treeMenuContainer(""),
00056 removeHTML(QRegExp("</?.+>"))
00057 {
00058 VERBOSE(VB_GENERAL, QString("OSD Theme Dimensions W: %1 H: %2").arg(m_themeinfo->BaseRes()->width()).arg(m_themeinfo->BaseRes()->height()));
00059
00060 m_themeaspect = (float)m_themeinfo->BaseRes()->width() / (float)m_themeinfo->BaseRes()->height();
00061 }
00062
00063 OSD::~OSD(void)
00064 {
00065 QMutexLocker locker(&osdlock);
00066
00067 QMap<QString, TTFFont *>::iterator fonts = fontMap.begin();
00068 for (; fonts != fontMap.end(); ++fonts)
00069 {
00070 if (*fonts)
00071 {
00072 delete *fonts;
00073 *fonts = NULL;
00074 }
00075 }
00076 fontMap.clear();
00077
00078 QMap<QString, OSDSet *>::iterator sets = setMap.begin();
00079 for (; sets != setMap.end(); ++sets)
00080 {
00081 if (*sets)
00082 {
00083 delete *sets;
00084 *sets = NULL;
00085 }
00086 }
00087 setMap.clear();
00088
00089 if (m_themeinfo)
00090 {
00091 delete m_themeinfo;
00092 m_themeinfo = NULL;
00093 }
00094
00095 if (editarrowleft)
00096 {
00097 delete editarrowleft;
00098 editarrowleft = NULL;
00099 }
00100
00101 if (editarrowright)
00102 {
00103 delete editarrowright;
00104 editarrowright = NULL;
00105 }
00106
00107 if (setList)
00108 {
00109 delete setList;
00110 setList = NULL;
00111 }
00112
00113 if (drawSurface)
00114 {
00115 delete drawSurface;
00116 drawSurface = NULL;
00117 }
00118 }
00119
00120 void OSD::Init(const QRect &osd_bounds, int frameRate,
00121 const QRect &vis_bounds, float visibleAspect, float fontScaling)
00122 {
00123 removeHTML.setMinimal(true);
00124
00125 fscale = fontScaling;
00126 osdBounds = osd_bounds;
00127 frameint = frameRate;
00128 hmult = vis_bounds.height() / (float)m_themeinfo->BaseRes()->height();
00129 wmult = vis_bounds.width() / (float)m_themeinfo->BaseRes()->width();
00130 xoffset = vis_bounds.left();
00131 yoffset = vis_bounds.top();
00132 displaywidth = vis_bounds.width();
00133 displayheight = vis_bounds.height();
00134 drawSurface = new OSDSurface(osd_bounds.width(), osd_bounds.height());
00135
00136 if (!cc708_defaults_initialized)
00137 initialize_osd_fonts();
00138
00139 for (uint i = 0; i < 16; i++)
00140 cc708fontnames[i] = cc708_default_font_names[i];
00141
00142 needPillarBox = visibleAspect > 1.51f;
00143 wscale = visibleAspect / m_themeaspect;
00144
00145 fscale *= (float) sqrt(2.0/(sq(wscale) + 1.0));
00146
00147 if (themepath.isEmpty())
00148 {
00149 VERBOSE(VB_IMPORTANT, "Couldn't find OSD theme: "
00150 <<gContext->GetSetting("OSDTheme"));
00151 InitDefaults();
00152 return;
00153 }
00154
00155 themepath += "/";
00156 if (!LoadTheme())
00157 {
00158 VERBOSE(VB_IMPORTANT, "Couldn't load OSD theme: "
00159 <<gContext->GetSetting("OSDTheme")<<" at "<<themepath);
00160 }
00161
00162 InitDefaults();
00163
00164
00165 Reinit(osd_bounds, frameRate, vis_bounds, visibleAspect, fontScaling);
00166
00167 }
00168
00169 void OSD::SetFrameInterval(int frint)
00170 {
00171 frameint = frint;
00172
00173 QMap<QString, OSDSet *>::iterator sets = setMap.begin();
00174 for (; sets != setMap.end(); ++sets)
00175 {
00176 OSDSet *set = (*sets);
00177 if (set)
00178 set->SetFrameInterval(frameint);
00179 }
00180 }
00181
00182 bool OSD::InitDefaults(void)
00183 {
00184 bool ok = true;
00185 ok &= InitCC608();
00186 ok &= InitCC708();
00187 ok &= InitTeletext();
00188 ok &= InitMenu();
00189 ok &= InitSubtitles();
00190 ok &= InitInteractiveTV();
00191 return ok;
00192 }
00193
00194
00195 bool OSD::InitCC608(void)
00196 {
00197 TTFFont *ccfont = GetFont("cc_font");
00198 if (!ccfont)
00199 {
00200 QString name = "cc_font";
00201 int fontsize = m_themeinfo->BaseRes()->height() / 27;
00202
00203 ccfont = LoadFont(gContext->GetSetting("OSDCCFont"), fontsize);
00204
00205 if (ccfont)
00206 fontMap[name] = ccfont;
00207 }
00208
00209 if (!ccfont)
00210 return false;
00211
00212 if (GetSet("cc_page"))
00213 return true;
00214
00215 QString name = "cc_page";
00216 OSDSet *container =
00217 new OSDSet(name, true,
00218 osdBounds.width(), osdBounds.height(),
00219 wmult, hmult, frameint);
00220 container->SetPriority(30);
00221 AddSet(container, name);
00222
00223 int sub_dispw = displaywidth;
00224 int sub_disph = displayheight;
00225 int sub_xoff = xoffset;
00226 int sub_yoff = yoffset;
00227 if (needPillarBox)
00228 {
00229
00230 sub_dispw = (int)(wscale * 4.0f*displayheight/3.0f);
00231 sub_disph = displayheight;
00232 sub_xoff = xoffset + (displaywidth-sub_dispw)/2;
00233 sub_yoff = yoffset;
00234 }
00235
00236 OSDTypeCC *ccpage =
00237 new OSDTypeCC(name, ccfont, sub_xoff, sub_yoff,
00238 sub_dispw, sub_disph, wmult, hmult);
00239 container->AddType(ccpage);
00240 return true;
00241 }
00242
00243
00244 bool OSD::InitCC708(void)
00245 {
00246 VERBOSE(VB_VBI, LOC + "InitCC708() -- begin");
00247
00248 QString name = "cc708_page";
00249 if (GetSet(name))
00250 {
00251 VERBOSE(VB_IMPORTANT, LOC + "InitCC708() -- end (already exists)");
00252 return true;
00253 }
00254
00255
00256 TTFFont* ccfonts[48];
00257 uint z = gContext->GetNumSetting("OSDCC708TextZoom", 100) *
00258 m_themeinfo->BaseRes()->height();
00259 uint fontsizes[3] = { z / 3600, z / 2900, z / 2200 };
00260 for (uint i = 0; i < 48; i++)
00261 {
00262 TTFFont *ccfont = GetFont(QString("cc708_font%1").arg(i));
00263 if (!ccfont)
00264 {
00265 QString name = QString("cc708_font%1").arg(i);
00266 int fontsize = fontsizes[i%3];
00267
00268 ccfont = LoadFont(cc708fontnames[i/3], fontsize);
00269 if (ccfont)
00270 fontMap[name] = ccfont;
00271
00272 if (!ccfont)
00273 {
00274 VERBOSE(VB_IMPORTANT, LOC_ERR + "A CC708 font is missing");
00275 return false;
00276 }
00277 }
00278 ccfonts[i] = ccfont;
00279 }
00280
00281
00282 OSDSet *container =
00283 new OSDSet(
00284 name, true, osdBounds.width(), osdBounds.height(),
00285 wmult, hmult, frameint);
00286 container->SetPriority(30);
00287
00288 AddSet(container, name);
00289 OSDType708CC *ccpage =
00290 new OSDType708CC(name, ccfonts, xoffset, yoffset,
00291 displaywidth, displayheight);
00292 container->AddType(ccpage);
00293
00294 VERBOSE(VB_VBI, LOC + "InitCC708() -- end");
00295 return true;
00296 }
00297
00298 bool OSD::InitTeletext(void)
00299 {
00300 if (GetSet("teletext"))
00301 return true;
00302
00303 QString name = "teletext";
00304 OSDSet *container =
00305 new OSDSet(name, true, osdBounds.width(), osdBounds.height(),
00306 wmult, hmult, frameint);
00307 container->SetAllowFade(false);
00308 container->SetWantsUpdates(true);
00309 AddSet(container, name);
00310 QRect area = QRect(20, 20, 620, 440);
00311 normalizeRect(area);
00312
00313 QString fontname = "teletextfont";
00314 TTFFont *font = GetFont(fontname);
00315 if (!font)
00316 {
00317 int fontsize = 440 / 26;
00318 font = LoadFont(gContext->GetSetting("OSDCCFont"), fontsize);
00319
00320 if (font)
00321 fontMap[fontname] = font;
00322 }
00323
00324 OSDTypeTeletext *ttpage = new OSDTypeTeletext(
00325 name, font, area, wmult, hmult, this);
00326
00327 container->SetPriority(30);
00328 container->AddType(ttpage);
00329 return true;
00330 }
00331
00332 void OSD::UpdateTeletext(void)
00333 {
00334 QMutexLocker locker(&osdlock);
00335
00336 OSDSet *container = GetSet("teletext");
00337 if (!container)
00338 return;
00339
00340 OSDType *type = container->GetType("teletext");
00341 OSDTypeTeletext *ttpage = dynamic_cast<OSDTypeTeletext*>(type);
00342 if (ttpage)
00343 {
00344 container->Display(1);
00345 m_setsvisible = true;
00346 changed = true;
00347 }
00348 }
00349
00350 void OSD::SetTextSubtitles(const QStringList &lines)
00351 {
00352 const uint SUBTITLE_FONT_SIZE = 20;
00353 const float SUBTITLE_LINE_SPACING = 1.1;
00354 const uint MAX_CHARACTERS_PER_ROW = 50;
00355
00356 const uint BOTTOM_PAD = SUBTITLE_FONT_SIZE;
00357
00358 OSDSet *subtitleSet = GetSet("subtitles");
00359 if (!subtitleSet)
00360 return;
00361
00362
00363 QString subText = "";
00364 int subLines = 0;
00365 QStringList::const_iterator it = lines.begin();
00366 for (; it != lines.end(); ++it)
00367 {
00368 QString tmp = *it;
00369 const QString line = tmp.remove((const QRegExp&) removeHTML);
00370
00371 if (line.length() <= MAX_CHARACTERS_PER_ROW)
00372 {
00373 subText.append(line);
00374 subText.append("\n");
00375 ++subLines;
00376 continue;
00377 }
00378
00379
00380 QStringList words = QStringList::split(" ", line);
00381 QString newString = "";
00382
00383 do
00384 {
00385 QString word = words.first();
00386 words.pop_front();
00387
00388 uint totLen = newString.length() + word.length() + 1;
00389 if (totLen > MAX_CHARACTERS_PER_ROW)
00390 {
00391
00392 subText.append(newString + "\n");
00393 ++subLines;
00394 newString = "";
00395 }
00396 newString.append(word + " ");
00397 }
00398 while (!words.empty());
00399
00400 subText.append(newString);
00401 subText.append("\n");
00402 ++subLines;
00403 }
00404
00405 ClearAll("subtitles");
00406
00407 QString name = "text_subtitles";
00408
00409
00410
00411
00412
00413
00414 const int totalSpaceBetweenLines = (subLines - 1) * 5;
00415 const int subtitleTotalHeight =
00416 subLines * SUBTITLE_FONT_SIZE + totalSpaceBetweenLines;
00417
00418
00419 QRect area(0, displayheight - (int)((subtitleTotalHeight + BOTTOM_PAD)*hmult),
00420 displaywidth, displayheight);
00421
00422 QString fontname = "text_subtitle_font";
00423 TTFFont *font = GetFont(fontname);
00424 if (!font)
00425 {
00426 font = LoadFont(gContext->GetSetting("OSDCCFont"), SUBTITLE_FONT_SIZE);
00427
00428 if (font)
00429 {
00430
00431 font->setOutline(true);
00432 fontMap[fontname] = font;
00433 }
00434 else
00435 {
00436 VERBOSE(VB_IMPORTANT, "Cannot load font for text subtitles.");
00437 return;
00438 }
00439 }
00440
00441 OSDTypeText *text = new OSDTypeText(name, font, "", area, wmult, hmult);
00442
00443 text->SetCentered(true);
00444 text->SetMultiLine(true);
00445 text->SetText(subText);
00446 text->SetSelected(false);
00447 text->SetLineSpacing(SUBTITLE_LINE_SPACING);
00448 subtitleSet->AddType(text);
00449 SetVisible(subtitleSet, 0);
00450 }
00451
00452 void OSD::ClearTextSubtitles()
00453 {
00454 HideSet("subtitles");
00455 ClearAll("subtitles");
00456 }
00457
00458 bool OSD::InitMenu(void)
00459 {
00460 if (GetSet("menu"))
00461 return true;
00462
00463 QString name = "menu";
00464 OSDSet *container =
00465 new OSDSet(name, true,
00466 osdBounds.width(), osdBounds.height(),
00467 wmult, hmult, frameint);
00468 AddSet(container, name);
00469
00470 QRect area = QRect(20, 40, 620, 300);
00471 QRect listarea = QRect(0, 0, 274, 260);
00472
00473 normalizeRect(area);
00474 normalizeRect(listarea);
00475 listarea.moveBy((int)(-xoffset*hmult+0.5), (int)(-yoffset*hmult+0.5));
00476
00477 OSDListTreeType *lb = new OSDListTreeType("menu", area, listarea, 10,
00478 wmult, hmult);
00479
00480 lb->SetItemRegColor(QColor("#505050"), QColor("#000000"), 100);
00481 lb->SetItemSelColor(QColor("#52CA38"), QColor("#349838"), 255);
00482
00483 lb->SetSpacing(2);
00484 lb->SetMargin(3);
00485
00486 TTFFont *actfont = GetFont("infofont");
00487 TTFFont *inactfont = GetFont("infofont");
00488
00489 if (!actfont)
00490 {
00491 actfont = LoadFont(gContext->GetSetting("OSDFont"), 16);
00492
00493 if (actfont)
00494 fontMap["treemenulistfont"] = actfont;
00495 }
00496
00497 if (!actfont)
00498 {
00499 QMap<QString, TTFFont *>::Iterator it = fontMap.begin();
00500 actfont = it.data();
00501 }
00502
00503 if (!inactfont)
00504 inactfont = actfont;
00505
00506 lb->SetFontActive(actfont);
00507 lb->SetFontInactive(inactfont);
00508
00509 container->AddType(lb);
00510
00511 return true;
00512 }
00513
00514 bool OSD::InitSubtitles(void)
00515 {
00516
00517 if (GetSet("subtitles"))
00518 return true;
00519
00520 QString name = "subtitles";
00521 OSDSet *container =
00522 new OSDSet(name, true,
00523 osdBounds.width(), osdBounds.height(),
00524 wmult, hmult, frameint);
00525
00526 container->SetPriority(30);
00527 AddSet(container, name);
00528 return true;
00529 }
00530
00531 bool OSD::InitInteractiveTV(void)
00532 {
00533
00534 if (GetSet("interactive"))
00535 return true;
00536 QString name = "interactive";
00537 OSDSet *container =
00538 new OSDSet(name, true,
00539 osdBounds.width(), osdBounds.height(),
00540 wmult, hmult, frameint);
00541 container->SetPriority(25);
00542 container->Display(true);
00543 AddSet(container, name);
00544 return true;
00545 }
00546
00547 void OSD::Reinit(const QRect &totalBounds, int frameRate,
00548 const QRect &visibleBounds,
00549 float visibleAspect, float fontScaling)
00550 {
00551 QMutexLocker locker(&osdlock);
00552
00553 QRect oldB = osdBounds;
00554
00555 osdBounds = totalBounds;
00556 xoffset = visibleBounds.left();
00557 yoffset = visibleBounds.top();
00558 displaywidth = visibleBounds.width();
00559 displayheight = visibleBounds.height();
00560 wmult = displaywidth / (float)m_themeinfo->BaseRes()->width();
00561 hmult = displayheight / (float)m_themeinfo->BaseRes()->height();
00562 needPillarBox = visibleAspect > 1.51f;
00563 frameint = (frameRate <= 0) ? frameRate : frameint;
00564
00565 float themeaspect = (float)m_themeinfo->BaseRes()->width() / (float)m_themeinfo->BaseRes()->height();
00566
00567 wscale = visibleAspect / themeaspect;
00568 fscale = fontScaling;
00569
00570 fscale *= (float) sqrt(2.0/(sq(wscale) + 1.0));
00571
00572 QMap<QString, TTFFont *>::iterator fonts = fontMap.begin();
00573 for (; fonts != fontMap.end(); ++fonts)
00574 {
00575 TTFFont *font = (*fonts);
00576 if (font)
00577 font->Reinit(wscale, hmult * fscale);
00578 }
00579
00580 QMap<QString, OSDSet *>::iterator sets = setMap.begin();
00581 for (; sets != setMap.end(); ++sets)
00582 {
00583 if (!(*sets))
00584 continue;
00585
00586 int sub_xoff = xoffset;
00587 int sub_yoff = yoffset;
00588 int sub_dispw = displaywidth;
00589 int sub_disph = displayheight;
00590 if ((*sets)->GetName() == "cc_page" && needPillarBox)
00591 {
00592
00593 sub_dispw = (int)(wscale * 4.0f*displayheight/3.0f);
00594 sub_disph = displayheight;
00595 sub_xoff = xoffset + (displaywidth-sub_dispw)/2;
00596 sub_yoff = yoffset;
00597 }
00598 (*sets)->Reinit(osdBounds.width(), osdBounds.height(),
00599 sub_xoff, sub_yoff, sub_dispw, sub_disph,
00600 wmult, hmult, frameint);
00601 }
00602
00603 if (true || oldB != osdBounds)
00604 {
00605 delete drawSurface;
00606 drawSurface = new OSDSurface(osdBounds.width(), osdBounds.height());
00607 }
00608 else
00609 {
00610 drawSurface->ClearUsed();
00611 }
00612 }
00613
00614 QString OSD::FindTheme(QString name)
00615 {
00616 QString testdir = MythContext::GetConfDir() + "/osd/" + name;
00617
00618 QDir dir(testdir);
00619 if (dir.exists())
00620 return testdir;
00621
00622 testdir = gContext->GetShareDir() + "themes/" + name;
00623 dir.setPath(testdir);
00624 if (dir.exists())
00625 return testdir;
00626
00627 testdir = "../libNuppelVideo/" + name;
00628 dir.setPath(testdir);
00629 if (dir.exists())
00630 return testdir;
00631
00632 return "";
00633 }
00634
00635 TTFFont *OSD::LoadFont(QString name, int size)
00636 {
00637 QString fullname = MythContext::GetConfDir() + "/" + name;
00638 TTFFont *font = new TTFFont((char *)fullname.ascii(), size,
00639 wscale, hmult*fscale);
00640
00641 if (font->isValid())
00642 return font;
00643
00644 delete font;
00645 fullname = gContext->GetShareDir() + name;
00646
00647 font = new TTFFont((char *)fullname.ascii(), size,
00648 wscale, hmult*fscale);
00649
00650 if (font->isValid())
00651 return font;
00652
00653 delete font;
00654 if (themepath != "")
00655 {
00656 fullname = themepath + "/" + name;
00657 font = new TTFFont((char *)fullname.ascii(), size,
00658 wscale, hmult*fscale);
00659 if (font->isValid())
00660 return font;
00661
00662 delete font;
00663 }
00664
00665 fullname = name;
00666 font = new TTFFont((char *)fullname.ascii(), size,
00667 wscale, hmult*fscale);
00668
00669 if (font->isValid())
00670 return font;
00671
00672 VERBOSE(VB_IMPORTANT, QString("Unable to find font: %1\n\t\t\t"
00673 "No OSD will be displayed.").arg(name));
00674
00675 delete font;
00676 font = NULL;
00677
00678 return font;
00679 }
00680
00681 QString OSD::getFirstText(QDomElement &element)
00682 {
00683 for (QDomNode dname = element.firstChild(); !dname.isNull();
00684 dname = dname.nextSibling())
00685 {
00686 QDomText t = dname.toText();
00687 if (!t.isNull())
00688 return t.data();
00689 }
00690 return "";
00691 }
00692
00693 void OSD::parseFont(QDomElement &element)
00694 {
00695 QString name;
00696 QString fontfile = gContext->GetSetting("OSDFont");
00697 int size = -1;
00698 int sizeSmall = -1;
00699 int sizeBig = -1;
00700 bool outline = false;
00701 QPoint shadowOffset = QPoint(0, 0);
00702 int color = 255;
00703 QColor color_normal, color_outline, color_shadow;
00704
00705 name = element.attribute("name", "");
00706 if (name.isNull() || name.isEmpty())
00707 {
00708 VERBOSE(VB_IMPORTANT, "Font needs a name");
00709 return;
00710 }
00711
00712 for (QDomNode child = element.firstChild(); !child.isNull();
00713 child = child.nextSibling())
00714 {
00715 QDomElement info = child.toElement();
00716 if (!info.isNull())
00717 {
00718 if (info.tagName() == "size")
00719 {
00720 size = getFirstText(info).toInt();
00721 }
00722 else if (info.tagName() == "size:small")
00723 {
00724 sizeSmall = getFirstText(info).toInt();
00725 }
00726 else if (info.tagName() == "size:big")
00727 {
00728 sizeBig = getFirstText(info).toInt();
00729 }
00730 else if (info.tagName() == "color")
00731 {
00732 color = getFirstText(info).toInt();
00733
00734 if (info.hasAttribute("normal"))
00735 color_normal = parseColor(info.attribute("normal"));
00736
00737 if (info.hasAttribute("outline"))
00738 color_outline = parseColor(info.attribute("outline"));
00739
00740 if (info.hasAttribute("shadow"))
00741 color_shadow = parseColor(info.attribute("shadow"));
00742 }
00743 else if (info.tagName() == "outline")
00744 {
00745 if (getFirstText(info).lower() == "yes")
00746 outline = true;
00747 }
00748 else if (info.tagName() == "shadow")
00749 {
00750 shadowOffset = parsePoint(getFirstText(info));
00751 shadowOffset.setX((int)(shadowOffset.x() * wmult));
00752 shadowOffset.setY((int)(shadowOffset.y() * hmult));
00753 }
00754 else if (info.tagName() == "filename")
00755 {
00756 fontfile = getFirstText(info);
00757 }
00758 else
00759 {
00760 VERBOSE(VB_IMPORTANT, "Unknown tag "
00761 << info.tagName() << " in font");
00762 continue;
00763 }
00764 }
00765 }
00766
00767 TTFFont *font = GetFont(name);
00768 if (font)
00769 {
00770 VERBOSE(VB_IMPORTANT, "Error: already have a font called: " << name);
00771 return;
00772 }
00773
00774 QString fontSizeType = gContext->GetSetting("OSDThemeFontSizeType",
00775 "default");
00776 if (fontSizeType == "small")
00777 {
00778 if (sizeSmall > 0)
00779 size = sizeSmall;
00780 }
00781 else if (fontSizeType == "big")
00782 {
00783 if (sizeBig > 0)
00784 size = sizeBig;
00785 }
00786
00787 if (size <= 0)
00788 {
00789 VERBOSE(VB_IMPORTANT, "Error: font size specified as: " << size);
00790 size = 10;
00791 }
00792
00793 font = LoadFont(fontfile, size);
00794 if (!font)
00795 {
00796 VERBOSE(VB_IMPORTANT, "Couldn't load font: " << fontfile);
00797 return;
00798 }
00799
00800 font->setColor(color);
00801 font->setOutline(outline);
00802 font->setShadow(shadowOffset.x(), shadowOffset.y());
00803
00804 if (color_normal.isValid())
00805 font->setColor(color_normal, kTTF_Normal);
00806
00807 if (color_outline.isValid())
00808 font->setColor(color_outline, kTTF_Outline);
00809
00810 if (color_shadow.isValid())
00811 font->setColor(color_shadow, kTTF_Shadow);
00812
00813 fontMap[name] = font;
00814 }
00815
00816 void OSD::parseBox(OSDSet *container, QDomElement &element)
00817 {
00818 QString name = element.attribute("name", "");
00819 if (name.isNull() || name.isEmpty())
00820 {
00821 VERBOSE(VB_IMPORTANT, "Box needs a name");
00822 return;
00823 }
00824
00825 QRect area(0, 0, 0, 0);
00826
00827 for (QDomNode child = element.firstChild(); !child.isNull();
00828 child = child.nextSibling())
00829 {
00830 QDomElement info = child.toElement();
00831 if (!info.isNull())
00832 {
00833 if (info.tagName() == "area")
00834 {
00835 area = parseRect(getFirstText(info));
00836 normalizeRect(area);
00837 }
00838 else
00839 {
00840 VERBOSE(VB_IMPORTANT, "Unknown tag in box: " << info.tagName());
00841 return;
00842 }
00843 }
00844 }
00845
00846 OSDTypeBox *box = new OSDTypeBox(name, area, wmult, hmult);
00847 container->AddType(box);
00848 }
00849
00850 void OSD::parseImage(OSDSet *container, QDomElement &element)
00851 {
00852 QString name = element.attribute("name", "");
00853 if (name.isNull() || name.isEmpty())
00854 {
00855 VERBOSE(VB_IMPORTANT, "Image needs a name");
00856 return;
00857 }
00858
00859 QString filename = "";
00860 QPoint pos = QPoint(0, 0);
00861
00862 QPoint scale = QPoint(-1, -1);
00863
00864 for (QDomNode child = element.firstChild(); !child.isNull();
00865 child = child.nextSibling())
00866 {
00867 QDomElement info = child.toElement();
00868 if (!info.isNull())
00869 {
00870 if (info.tagName() == "filename")
00871 {
00872 filename = getFirstText(info);
00873 }
00874 else if (info.tagName() == "position")
00875 {
00876 pos = parsePoint(getFirstText(info));
00877 pos.setX((int)(pos.x() * wmult + xoffset));
00878 pos.setY((int)(pos.y() * hmult + yoffset));
00879 }
00880 else if (info.tagName() == "staticsize")
00881 {
00882 scale = parsePoint(getFirstText(info));
00883 }
00884 else
00885 {
00886 VERBOSE(VB_IMPORTANT, QString("Unknown: %1 in image")
00887 .arg(info.tagName()));
00888 return;
00889 }
00890 }
00891 }
00892
00893 if (filename != "")
00894 filename = themepath + filename;
00895
00896 OSDTypeImage *image = new OSDTypeImage(name, filename, pos, wmult, hmult,
00897 scale.x(), scale.y());
00898 container->AddType(image);
00899 }
00900
00901 void OSD::parseTextArea(OSDSet *container, QDomElement &element)
00902 {
00903 QRect area = QRect(0, 0, 0, 0);
00904 QString font = "", altfont = "";
00905 QString statictext = "";
00906 QString defaulttext = "";
00907 bool multiline = false;
00908 bool scroller = false;
00909 int scrollx = 0;
00910 int scrolly = 0;
00911 float linespacing = 1.5;
00912
00913 QString name = element.attribute("name", "");
00914 if (name.isNull() || name.isEmpty())
00915 {
00916 VERBOSE(VB_IMPORTANT, "Text area needs a name");
00917 return;
00918 }
00919
00920 for (QDomNode child = element.firstChild(); !child.isNull();
00921 child = child.nextSibling())
00922 {
00923 QDomElement info = child.toElement();
00924 if (!info.isNull())
00925 {
00926 if (info.tagName() == "area")
00927 {
00928 area = parseRect(getFirstText(info));
00929 normalizeRect(area);
00930 }
00931 else if (info.tagName() == "font")
00932 {
00933 font = getFirstText(info);
00934 }
00935 else if (info.tagName() == "altfont")
00936 {
00937 altfont = getFirstText(info);
00938 }
00939 else if (info.tagName() == "multiline")
00940 {
00941 if (getFirstText(info).lower() == "yes")
00942 multiline = true;
00943 }
00944 else if (info.tagName() == "statictext")
00945 {
00946 statictext = getFirstText(info);
00947 }
00948 else if (info.tagName() == "value")
00949 {
00950 defaulttext = getFirstText(info);
00951 }
00952 else if (info.tagName() == "scroller")
00953 {
00954 if (getFirstText(info).lower() == "yes")
00955 scroller = true;
00956 }
00957 else if (info.tagName() == "linespacing")
00958 {
00959 linespacing = getFirstText(info).toFloat();
00960 }
00961 else if (info.tagName() == "scrollmovement")
00962 {
00963 QPoint pos = parsePoint(getFirstText(info));
00964 pos.setX((int)(pos.x() * wmult));
00965 pos.setY((int)(pos.y() * hmult));
00966
00967 scrollx = pos.x();
00968 scrolly = pos.y();
00969 }
00970 else
00971 {
00972 VERBOSE(VB_IMPORTANT, "Unknown tag in textarea: "
00973 << info.tagName());
00974 return;
00975 }
00976 }
00977 }
00978
00979 TTFFont *ttffont = GetFont(font);
00980 if (!ttffont)
00981 {
00982 VERBOSE(VB_IMPORTANT, "Unknown font: " << font
00983 << " in textarea: " << name);
00984 return;
00985 }
00986
00987 OSDTypeText *text = new OSDTypeText(name, ttffont, "", area, wmult, hmult);
00988 container->AddType(text);
00989
00990 text->SetMultiLine(multiline);
00991 text->SetLineSpacing(linespacing);
00992
00993 if (altfont != "")
00994 {
00995 ttffont = GetFont(altfont);
00996 if (!ttffont)
00997 {
00998 VERBOSE(VB_IMPORTANT, "Unknown altfont: " << altfont
00999 << " in textarea: " << name);
01000 }
01001 else
01002 text->SetAltFont(ttffont);
01003 }
01004
01005 if (statictext != "")
01006 text->SetText(statictext);
01007 if (defaulttext != "")
01008 text->SetDefaultText(defaulttext);
01009
01010 QString align = element.attribute("align", "");
01011 if (!align.isNull() && !align.isEmpty())
01012 {
01013 if (align.lower() == "center")
01014 text->SetCentered(true);
01015 else if (align.lower() == "right")
01016 text->SetRightJustified(true);
01017 }
01018
01019 QString entry = element.attribute("entry", "");
01020 if (!entry.isEmpty())
01021 {
01022 int entrynum = entry.toInt();
01023 text->SetEntryNum(entrynum);
01024 text->SetSelected(entrynum == 0);
01025 }
01026
01027 QString button = element.attribute("button", "");
01028 if (!button.isEmpty() && (button.lower() == "yes"))
01029 text->SetButton(true);
01030
01031 if (scroller)
01032 {
01033 if (scrollx == 0 && scrolly == 0)
01034 {
01035 VERBOSE(VB_IMPORTANT,
01036 "Text area set as scrolling, but no movement");
01037 scrollx = -5;
01038 }
01039
01040 text->SetScrolling(scrollx, scrolly);
01041 }
01042 }
01043
01044 void OSD::parseSlider(OSDSet *container, QDomElement &element)
01045 {
01046 QRect area = QRect(0, 0, 0, 0);
01047 QString filename = "";
01048 QString altfilename = "";
01049
01050 QString name = element.attribute("name", "");
01051 if (name.isNull() || name.isEmpty())
01052 {
01053 VERBOSE(VB_IMPORTANT, "Slider needs a name");
01054 return;
01055 }
01056
01057 QString type = element.attribute("type", "");
01058 if (type.isNull() || type.isEmpty())
01059 {
01060 VERBOSE(VB_IMPORTANT, "Slider needs a type");
01061 return;
01062 }
01063
01064 for (QDomNode child = element.firstChild(); !child.isNull();
01065 child = child.nextSibling())
01066 {
01067 QDomElement info = child.toElement();
01068 if (!info.isNull())
01069 {
01070 if (info.tagName() == "area")
01071 {
01072 area = parseRect(getFirstText(info));
01073 normalizeRect(area);
01074 }
01075 else if (info.tagName() == "filename")
01076 {
01077 filename = getFirstText(info);
01078 }
01079 else if (info.tagName() == "altfilename")
01080 {
01081 altfilename = getFirstText(info);
01082 }
01083 else
01084 {
01085 VERBOSE(VB_IMPORTANT, QString("Unknown: %1 in image")
01086 .arg(info.tagName()));
01087 return;
01088 }
01089 }
01090 }
01091
01092 if (filename == "")
01093 {
01094 VERBOSE(VB_IMPORTANT, "Slider needs a filename");
01095 return;
01096 }
01097
01098 filename = themepath + filename;
01099
01100 if (type.lower() == "fill")
01101 {
01102 OSDTypeFillSlider *slider = new OSDTypeFillSlider(
01103 name, filename, area, wmult, hmult);
01104 container->AddType(slider);
01105 }
01106 else if (type.lower() == "edit")
01107 {
01108 if (altfilename == "")
01109 {
01110 VERBOSE(VB_IMPORTANT, "Edit slider needs an altfilename");
01111 return;
01112 }
01113
01114 altfilename = themepath + altfilename;
01115
01116 OSDTypeEditSlider *tes = new OSDTypeEditSlider(
01117 name, filename, altfilename, area, wmult, hmult);
01118 container->AddType(tes);
01119 }
01120 else if (type.lower() == "position")
01121 {
01122 OSDTypePosSlider *pos = new OSDTypePosSlider(
01123 name, filename, area, wmult, hmult);
01124 container->AddType(pos);
01125 }
01126 }
01127
01128 void OSD::parseEditArrow(OSDSet *container, QDomElement &element)
01129 {
01130 container = container;
01131
01132 QString name = element.attribute("name", "");
01133 if (name.isNull() || name.isEmpty())
01134 {
01135 VERBOSE(VB_IMPORTANT, "editarrow needs a name");
01136 return;
01137 }
01138
01139 if (name != "left" && name != "right")
01140 {
01141 VERBOSE(VB_IMPORTANT, "editarrow name needs "
01142 "to be either 'left' or 'right'");
01143 return;
01144 }
01145
01146 QRect area(0, 0, 0, 0);
01147 QString filename = "";
01148
01149 for (QDomNode child = element.firstChild(); !child.isNull();
01150 child = child.nextSibling())
01151 {
01152 QDomElement info = child.toElement();
01153 if (!info.isNull())
01154 {
01155 if (info.tagName() == "area")
01156 {
01157 area = parseRect(getFirstText(info));
01158 normalizeRect(area);
01159 }
01160 else if (info.tagName() == "filename")
01161 {
01162 filename = getFirstText(info);
01163 }
01164 else
01165 {
01166 VERBOSE(VB_IMPORTANT, "Unknown tag in editarrow: "
01167 << info.tagName());
01168 return;
01169 }
01170 }
01171 }
01172
01173 if (filename == "")
01174 {
01175 VERBOSE(VB_IMPORTANT, "editarrow needs a filename");
01176 return;
01177 }
01178
01179 editarrowRect = area;
01180
01181 QString setname = "arrowimage";
01182
01183 filename = themepath + filename;
01184
01185 OSDTypeImage *image = new OSDTypeImage(
01186 setname, filename, QPoint(0, 0), wmult, hmult);
01187
01188 if (name == "left")
01189 editarrowleft = image;
01190 else
01191 editarrowright = image;
01192 }
01193
01194 void OSD::parsePositionRects(OSDSet *container, QDomElement &element)
01195 {
01196 QString name = element.attribute("name", "");
01197 if (name.isNull() || name.isEmpty())
01198 {
01199 VERBOSE(VB_IMPORTANT, "positionsrects needs a name");
01200 return;
01201 }
01202
01203 OSDTypePositionRectangle *rects = new OSDTypePositionRectangle(name);
01204
01205 for (QDomNode child = element.firstChild(); !child.isNull();
01206 child = child.nextSibling())
01207 {
01208 QDomElement info = child.toElement();
01209 if (!info.isNull())
01210 {
01211 if (info.tagName() == "area")
01212 {
01213 QRect area = parseRect(getFirstText(info));
01214 normalizeRect(area);
01215
01216 rects->AddPosition(area, wmult, hmult);
01217 }
01218 else
01219 {
01220 VERBOSE(VB_IMPORTANT, "Unknown tag in editarrow: "
01221 << info.tagName());
01222 return;
01223 }
01224 }
01225 }
01226
01227 container->AddType(rects);
01228 }
01229
01230 void OSD::parsePositionImage(OSDSet *container, QDomElement &element)
01231 {
01232 QString name = element.attribute("name", "");
01233 if (name.isNull() || name.isEmpty())
01234 {
01235 VERBOSE(VB_IMPORTANT, "positionimage needs a name");
01236 return;
01237 }
01238
01239 QString filename = "";
01240 QPoint scale = QPoint(-1, -1);
01241
01242 OSDTypePositionImage *image = new OSDTypePositionImage(name);
01243
01244 for (QDomNode child = element.firstChild(); !child.isNull();
01245 child = child.nextSibling())
01246 {
01247 QDomElement info = child.toElement();
01248 if (!info.isNull())
01249 {
01250 if (info.tagName() == "filename")
01251 {
01252 filename = getFirstText(info);
01253 }
01254 else if (info.tagName() == "position")
01255 {
01256 QPoint pos = parsePoint(getFirstText(info));
01257 pos.setX((int)(pos.x() * wmult + xoffset));
01258 pos.setY((int)(pos.y() * hmult + yoffset));
01259
01260 image->AddPosition(pos, wmult, hmult);
01261 }
01262 else if (info.tagName() == "staticsize")
01263 {
01264 scale = parsePoint(getFirstText(info));
01265 }
01266 else
01267 {
01268 VERBOSE(VB_IMPORTANT, QString("Unknown: %1 in positionimage")
01269 .arg(info.tagName()));
01270 return;
01271 }
01272 }
01273 }
01274
01275 if (filename != "")
01276 filename = themepath + filename;
01277
01278 image->SetStaticSize(scale.x(), scale.y());
01279 image->Load(filename, wmult, hmult, scale.x(), scale.y());
01280
01281 container->AddType(image);
01282 }
01283
01284 void OSD::parseListTree(OSDSet *container, QDomElement &element)
01285 {
01286 QRect area = QRect(0,0,0,0);
01287 QRect listsize = QRect(0,0,0,0);
01288 int leveloffset = 0;
01289 QString fontActive;
01290 QString fontInactive;
01291 bool showArrow = true;
01292 bool showScrollArrows = false;
01293 QColor grUnselectedBeg(Qt::black);
01294 QColor grUnselectedEnd(80,80,80);
01295 uint grUnselectedAlpha(100);
01296 QColor grSelectedBeg(82,202,56);
01297 QColor grSelectedEnd(52,152,56);
01298 uint grSelectedAlpha(255);
01299 int spacing = 2;
01300 int margin = 3;
01301
01302 QString name = element.attribute("name", "");
01303 if (name.isNull() || name.isEmpty())
01304 {
01305 VERBOSE(VB_IMPORTANT, "listtree needs a name");
01306 return;
01307 }
01308
01309 for (QDomNode child = element.firstChild(); !child.isNull();
01310 child = child.nextSibling())
01311 {
01312 QDomElement info = child.toElement();
01313 if (!info.isNull())
01314 {
01315 if (info.tagName() == "area")
01316 {
01317 area = parseRect(getFirstText(info));
01318 normalizeRect(area);
01319 }
01320 else if (info.tagName() == "listsize")
01321 {
01322 listsize = parseRect(getFirstText(info));
01323 normalizeRect(listsize);
01324 listsize.moveBy(-xoffset, -yoffset);
01325 }
01326 else if (info.tagName() == "leveloffset")
01327 {
01328 leveloffset = getFirstText(info).toInt();
01329 }
01330 else if (info.tagName() == "fcnfont")
01331 {
01332 QString fontName = info.attribute("name", "");
01333 QString fontFcn = info.attribute("function", "");
01334
01335 if (fontFcn.lower() == "active")
01336 fontActive = fontName;
01337 else if (fontFcn.lower() == "inactive")
01338 fontInactive = fontName;
01339 else
01340 {
01341 VERBOSE(VB_IMPORTANT, "Unknown font function "
01342 "for listtree area: " << fontFcn);
01343 return;
01344 }
01345 }
01346 else if (info.tagName() == "showarrow")
01347 {
01348 if (getFirstText(info).lower() == "no")
01349 showArrow = false;
01350 }
01351 else if (info.tagName() == "showscrollarrows")
01352 {
01353 if (getFirstText(info).lower() == "yes")
01354 showScrollArrows = true;
01355 }
01356 else if (info.tagName() == "gradient")
01357 {
01358 if (info.attribute("type","").lower() == "selected")
01359 {
01360 grSelectedBeg = QColor(info.attribute("start"));
01361 grSelectedEnd = QColor(info.attribute("end"));
01362 grSelectedAlpha = info.attribute("alpha","255").toUInt();
01363 }
01364 else if (info.attribute("type","").lower() == "unselected")
01365 {
01366 grUnselectedBeg = QColor(info.attribute("start"));
01367 grUnselectedEnd = QColor(info.attribute("end"));
01368 grUnselectedAlpha = info.attribute("alpha","100").toUInt();
01369 }
01370 else
01371 {
01372 VERBOSE(VB_IMPORTANT,
01373 "Unknown type for gradient in listtree area");
01374 return;
01375 }
01376
01377 if (!grSelectedBeg.isValid() || !grSelectedEnd.isValid() ||
01378 !grUnselectedBeg.isValid() || !grUnselectedEnd.isValid())
01379 {
01380 VERBOSE(VB_IMPORTANT,
01381 "Unknown color for gradient in listtree area");
01382 return;
01383 }
01384
01385 if (grSelectedAlpha > 255 || grUnselectedAlpha > 255)
01386 {
01387 VERBOSE(VB_IMPORTANT,
01388 "Incorrect alpha for gradient in listtree area");
01389 return;
01390 }
01391 }
01392 else if (info.tagName() == "spacing") {
01393 spacing = getFirstText(info).toInt();
01394 }
01395 else if (info.tagName() == "margin") {
01396 margin = getFirstText(info).toInt();
01397 }
01398 else
01399 {
01400 VERBOSE(VB_IMPORTANT, "Unknown tag in listtree area: "
01401 << info.tagName());
01402 return;
01403 }
01404 }
01405 }
01406
01407 TTFFont *fpActive = GetFont(fontActive);
01408 if (!fpActive)
01409 {
01410 VERBOSE(VB_IMPORTANT, "Unknown font: " << fontActive << " in listtree");
01411 return;
01412 }
01413
01414 TTFFont *fpInactive = GetFont(fontInactive);
01415 if (!fpInactive)
01416 {
01417 VERBOSE(VB_IMPORTANT, "Unknown font: "
01418 << fontInactive << " in listtree");
01419 return;
01420 }
01421
01422 OSDListTreeType *lb = new OSDListTreeType(
01423 name, area, listsize, leveloffset, wmult, hmult);
01424 lb->SetFontActive(fpActive);
01425 lb->SetFontInactive(fpInactive);
01426 lb->SetItemRegColor(grUnselectedBeg, grUnselectedEnd, grUnselectedAlpha);
01427 lb->SetItemSelColor(grSelectedBeg, grSelectedEnd, grSelectedAlpha);
01428 lb->SetSpacing(spacing);
01429 lb->SetMargin(margin);
01430
01431 container->AddType(lb);
01432 }
01433
01434 void OSD::parseContainer(QDomElement &element)
01435 {
01436 QString name = element.attribute("name", "");
01437 if (name.isNull() || name.isEmpty())
01438 {
01439 VERBOSE(VB_IMPORTANT, "Container needs a name");
01440 return;
01441 }
01442
01443 OSDSet *container = GetSet(name);
01444 if (container)
01445 {
01446 VERBOSE(VB_IMPORTANT, "Container: " << name << " already exists");
01447 return;
01448 }
01449
01450 container = new OSDSet(name, true,
01451 osdBounds.width(), osdBounds.height(),
01452 wmult, hmult, frameint);
01453
01454 QString prio = element.attribute("priority", "");
01455 if (!prio.isNull() && !prio.isEmpty())
01456 {
01457 container->SetPriority(prio.toInt());
01458 }
01459
01460 AddSet(container, name);
01461
01462 QString movement = element.attribute("fademovement", "");
01463 if (!movement.isNull() && !movement.isEmpty())
01464 {
01465 QPoint movefade = parsePoint(movement);
01466 container->SetFadeMovement((int)(movefade.x() * wmult),
01467 (int)(movefade.y() * hmult));
01468 }
01469
01470 QString showwith = element.attribute("showwith", "");
01471 if (!showwith.isEmpty())
01472 container->SetShowWith(showwith);
01473
01474 for (QDomNode child = element.firstChild(); !child.isNull();
01475 child = child.nextSibling())
01476 {
01477 QDomElement info = child.toElement();
01478 if (!info.isNull())
01479 {
01480 if (info.tagName() == "image")
01481 {
01482 parseImage(container, info);
01483 }
01484 else if (info.tagName() == "textarea")
01485 {
01486 parseTextArea(container, info);
01487 }
01488 else if (info.tagName() == "slider")
01489 {
01490 parseSlider(container, info);
01491 }
01492 else if (info.tagName() == "box")
01493 {
01494 parseBox(container, info);
01495 }
01496 else if (info.tagName() == "editarrow")
01497 {
01498 parseEditArrow(container, info);
01499 }
01500 else if (info.tagName() == "positionrects")
01501 {
01502 parsePositionRects(container, info);
01503 }
01504 else if (info.tagName() == "positionimage")
01505 {
01506 parsePositionImage(container, info);
01507 }
01508 else if (info.tagName() == "listtreemenu")
01509 {
01510 parseListTree(container, info);
01511 }
01512 else
01513 {
01514 VERBOSE(VB_IMPORTANT, QString("Unknown container child: %1")
01515 .arg(info.tagName()));
01516 return;
01517 }
01518 }
01519 }
01520 }
01521
01522 bool OSD::LoadTheme(void)
01523 {
01524
01525 xoffset = 0;
01526 yoffset = 0;
01527 displaywidth = m_themeinfo->BaseRes()->width();
01528 displayheight = m_themeinfo->BaseRes()->height();
01529 hmult = 1.0f;
01530 wmult = 1.0f;
01531
01532
01533 QString themefile = themepath + "/osd.xml";
01534
01535 QDomDocument doc;
01536 QFile f(themefile);
01537
01538 if (!f.open(IO_ReadOnly))
01539 {
01540 VERBOSE(VB_IMPORTANT, "OSD::LoadTheme(): Can't open: " << themefile);
01541 return false;
01542 }
01543
01544 QString errorMsg;
01545 int errorLine = 0;
01546 int errorColumn = 0;
01547
01548 if (!doc.setContent(&f, false, &errorMsg, &errorLine, &errorColumn))
01549 {
01550 VERBOSE(VB_IMPORTANT, QString("Error parsing: %1\n\t\t\t"
01551 "at line: %2 column: %3\n\t\t\t%4")
01552 .arg(themefile).arg(errorLine).arg(errorColumn).arg(errorMsg));
01553 f.close();
01554 return false;
01555 }
01556
01557 f.close();
01558
01559 QDomElement docElem = doc.documentElement();
01560 for (QDomNode n = docElem.firstChild(); !n.isNull();
01561 n = n.nextSibling())
01562 {
01563 QDomElement e = n.toElement();
01564 if (!e.isNull())
01565 {
01566 if (e.tagName() == "timeformat")
01567 {
01568 timeFormat = getFirstText(e);
01569 if (timeFormat.upper() == "FROMSETTINGS")
01570 timeFormat = gContext->GetSetting("TimeFormat", "h:mm AP");
01571 }
01572 else if (e.tagName() == "fadeaway")
01573 {
01574 totalfadetime = (getFirstText(e).toInt() * 1000000) / 30;
01575 }
01576 else if (e.tagName() == "font")
01577 {
01578 parseFont(e);
01579 }
01580 else if (e.tagName() == "container")
01581 {
01582 parseContainer(e);
01583 }
01584 else
01585 {
01586 VERBOSE(VB_IMPORTANT, "Unknown element: " << e.tagName());
01587 continue;
01588 }
01589 }
01590 }
01591
01592 return true;
01593 }
01594
01595 void OSD::normalizeRect(QRect &rect)
01596 {
01597 rect.setWidth((int)(rect.width() * wmult));
01598 rect.setHeight((int)(rect.height() * hmult));
01599 rect.moveTopLeft(QPoint((int)(xoffset + rect.x() * wmult),
01600 (int)(yoffset + rect.y() * hmult)));
01601 rect = rect.normalize();
01602 }
01603
01604 QPoint OSD::parsePoint(QString text)
01605 {
01606 int x, y;
01607 QPoint retval(0, 0);
01608 if (sscanf(text.data(), "%d,%d", &x, &y) == 2)
01609 retval = QPoint(x, y);
01610 return retval;
01611 }
01612
01613 QColor OSD::parseColor(QString text)
01614 {
01615 QColor retval;
01616 QRegExp regexp("#([0-9a-fA-F]){6}");
01617 if (regexp.exactMatch(text))
01618 {
01619 int val;
01620 if (sscanf(text.data(), "#%x", &val) == 1)
01621 retval = QColor((val >> 16) & 0xff, (val >> 8) & 0xff, val & 0xff);
01622 }
01623 else
01624 {
01625 int r, g, b;
01626 if (sscanf(text.data(), "%d,%d,%d", &r, &g, &b) == 3)
01627 retval = QColor(r, g, b);
01628 }
01629 return retval;
01630 }
01631
01632 QRect OSD::parseRect(QString text)
01633 {
01634 int x, y, w, h;
01635 QRect retval(0, 0, 0, 0);
01636 if (sscanf(text.data(), "%d,%d,%d,%d", &x, &y, &w, &h) == 4)
01637 retval = QRect(x, y, w, h);
01638
01639 return retval;
01640 }
01641
01642 void OSD::ClearAll(const QString &name)
01643 {
01644 osdlock.lock();
01645 OSDSet *container = GetSet(name);
01646 if (container)
01647 container->Clear();
01648
01649 osdlock.unlock();
01650 }
01651
01652 void OSD::ClearAllText(const QString &name)
01653 {
01654 osdlock.lock();
01655 OSDSet *container = GetSet(name);
01656 if (container)
01657 container->ClearAllText();
01658
01659 osdlock.unlock();
01660 }
01661
01662 void OSD::SetText(const QString &name,
01663 QMap<QString, QString> &infoMap, int length)
01664 {
01665 HideAllExcept(name);
01666
01667 osdlock.lock();
01668 OSDSet *container = GetSet(name);
01669 if (container)
01670 {
01671 container->SetText(infoMap);
01672 if (length >= 0)
01673 container->DisplayFor(length * 1000000);
01674 else
01675 container->Display();
01676
01677 OSDTypeImage *cs = (OSDTypeImage *)container->GetType("channelicon");
01678 if (cs)
01679 {
01680 if ((infoMap.contains("iconpath")) && (infoMap["iconpath"] != ""))
01681 cs->Load(infoMap["iconpath"], wmult, hmult, 30, 30);
01682 else
01683 cs->Load(" ", wmult, hmult, 30, 30);
01684 }
01685
01686 m_setsvisible = true;
01687 changed = true;
01688 }
01689 osdlock.unlock();
01690 }
01691
01692 void OSD::SetInfoText(QMap<QString, QString> infoMap, int length)
01693 {
01694 osdlock.lock();
01695 OSDSet *container = GetSet("program_info");
01696 if (container)
01697 {
01698 container->SetText(infoMap);
01699
01700 OSDTypeImage *cs = (OSDTypeImage *)container->GetType("channelicon");
01701 if (cs)
01702 {
01703 if ((infoMap.contains("iconpath")) && (infoMap["iconpath"] != ""))
01704 cs->Load(infoMap["iconpath"], wmult, hmult, 30, 30);
01705 else
01706 cs->Load(" ", wmult, hmult, 30, 30);
01707 }
01708
01709 container->DisplayFor(length * 1000000);
01710 m_setsvisible = true;
01711 changed = true;
01712 }
01713 osdlock.unlock();
01714 }
01715
01716 void OSD::SetInfoText(const QString &text, const QString &subtitle,
01717 const QString &desc, const QString &category,
01718 const QString &start, const QString &end,
01719 const QString &callsign, const QString &iconpath,
01720 int length)
01721 {
01722 QString tmp = category;
01723 tmp = start;
01724 tmp = end;
01725
01726 bool hassubtitle = true;
01727
01728 osdlock.lock();
01729 OSDSet *container = GetSet("program_info");
01730 if (container)
01731 {
01732 OSDTypeText *type = (OSDTypeText *)container->GetType("title");
01733 if (type)
01734 type->SetText(text);
01735
01736 type = (OSDTypeText *)container->GetType("subtitle");
01737 if (type)
01738 type->SetText(subtitle);
01739 else
01740 hassubtitle = false;
01741
01742 type = (OSDTypeText *)container->GetType("description");
01743 if (type)
01744 {
01745 if (!hassubtitle && subtitle.length() > 1)
01746 {
01747 QString tmpdesc = "\"" + subtitle + "\"";
01748 if (desc.length() > 1)
01749 tmpdesc += ", " + desc;
01750 type->SetText(tmpdesc);
01751 }
01752 else
01753 type->SetText(desc);
01754 }
01755 type = (OSDTypeText *)container->GetType("callsign");
01756 if (type)
01757 type->SetText(callsign.left(5));
01758 OSDTypeImage *cs = (OSDTypeImage *)container->GetType("channelicon");
01759 if (cs)
01760 cs->Load(iconpath, wmult, hmult, 30, 30);
01761
01762 container->DisplayFor(length * 1000000);
01763 m_setsvisible = true;
01764 changed = true;
01765 }
01766 osdlock.unlock();
01767 }
01768
01769 void OSD::SetUpOSDClosedHandler(TV *tv)
01770 {
01771 OSDSet *container = GetSet("status");
01772
01773 if (container)
01774 connect((QObject *)container, SIGNAL(OSDClosed(int)), (QObject *)tv,
01775 SLOT(HandleOSDClosed(int)));
01776
01777 }
01778
01779 void OSD::ShowStatus(int pos, bool fill, QString msgtext, QString desc,
01780 int displaytime, int osdFunctionalType)
01781 {
01782 struct StatusPosInfo posInfo;
01783
01784 posInfo.desc = desc;
01785 posInfo.position = pos;
01786 posInfo.progBefore = false;
01787 posInfo.progAfter = false;
01788
01789 ShowStatus(posInfo, fill, msgtext, displaytime, osdFunctionalType);
01790 }
01791
01792 void OSD::ShowStatus(struct StatusPosInfo posInfo,
01793 bool fill, QString msgtext, int displaytime,
01794 int osdFunctionalType)
01795 {
01796 fill = fill;
01797
01798 HideAllExcept("status");
01799
01800 osdlock.lock();
01801 OSDSet *container = GetSet("status");
01802 if (container)
01803 {
01804 OSDTypeText *type = (OSDTypeText *)container->GetType("status");
01805 if (type)
01806 type->SetText(msgtext);
01807 type = (OSDTypeText *)container->GetType("slidertext");
01808 if (type)
01809 type->SetText(posInfo.desc);
01810
01811 OSDTypeText *exttext = (OSDTypeText *)container->GetType("extendedslidertext");
01812 if (exttext)
01813 exttext->SetText(posInfo.extdesc);
01814
01815 OSDTypeFillSlider *slider =
01816 (OSDTypeFillSlider *)container->GetType("statusslider");
01817 if (slider)
01818 slider->SetPosition(posInfo.position);
01819
01820 OSDTypePosSlider *ppos =
01821 (OSDTypePosSlider *)container->GetType("statusposition");
01822 if (ppos)
01823 ppos->SetPosition(posInfo.position);
01824
01825 OSDTypeImage *beforeImage =
01826 (OSDTypeImage *)container->GetType("progbefore");
01827 if (beforeImage)
01828 beforeImage->Hide(!posInfo.progBefore);
01829
01830 OSDTypeImage *afterImage =
01831 (OSDTypeImage *)container->GetType("progafter");
01832 if (afterImage)
01833 afterImage->Hide(!posInfo.progAfter);
01834
01835 if (displaytime > 0)
01836 container->DisplayFor(displaytime * 1000000, osdFunctionalType);
01837 else
01838 container->Display();
01839
01840 m_setsvisible = true;
01841 changed = true;
01842 }
01843 osdlock.unlock();
01844 }
01845
01846 void OSD::UpdateStatus(struct StatusPosInfo posInfo)
01847 {
01848 osdlock.lock();
01849 OSDSet *container = GetSet("status");
01850 if (container)
01851 {
01852 OSDTypeText *type = (OSDTypeText *)container->GetType("slidertext");
01853 if (type)
01854 {
01855 if (type->GetText() != posInfo.desc)
01856 {
01857 type->SetText(posInfo.desc);
01858 m_setsvisible = true;
01859 changed = true;
01860 }
01861 }
01862
01863 OSDTypeText *exttext = (OSDTypeText *)container->GetType("extendedslidertext");
01864 if (exttext)
01865 {
01866 if (exttext->GetText() != posInfo.extdesc)
01867 {
01868 exttext->SetText(posInfo.extdesc);
01869 m_setsvisible = true;
01870 changed = true;
01871 }
01872 }
01873
01874 OSDTypeFillSlider *slider =
01875 (OSDTypeFillSlider *)container->GetType("statusslider");
01876 if (slider)
01877 {
01878 if (slider->GetPosition() != posInfo.position)
01879 {
01880 slider->SetPosition(posInfo.position);
01881
01882 m_setsvisible = true;
01883 changed = true;
01884 }
01885 }
01886
01887 OSDTypePosSlider *ppos =
01888 (OSDTypePosSlider *)container->GetType("statusposition");
01889 if (ppos)
01890 {
01891 if (ppos->GetPosition() != posInfo.position)
01892 {
01893 ppos->SetPosition(posInfo.position);
01894
01895 m_setsvisible = true;
01896 changed = true;
01897 }
01898 }
01899
01900 OSDTypeImage *beforeImage =
01901 (OSDTypeImage *)container->GetType("progbefore");
01902 if (beforeImage)
01903 {
01904 if (beforeImage->isHidden() != !posInfo.progBefore)
01905 {
01906 beforeImage->Hide(!posInfo.progBefore);
01907
01908 m_setsvisible = true;
01909 changed = true;
01910 }
01911 }
01912
01913 OSDTypeImage *afterImage =
01914 (OSDTypeImage *)container->GetType("progafter");
01915 if (afterImage)
01916 {
01917 if (afterImage->isHidden() != !posInfo.progAfter)
01918 {
01919 afterImage->Hide(!posInfo.progAfter);
01920
01921 m_setsvisible = true;
01922 changed = true;
01923 }
01924 }
01925 }
01926 osdlock.unlock();
01927 }
01928
01929 void OSD::EndStatus(void)
01930 {
01931 osdlock.lock();
01932 OSDSet *container = GetSet("status");
01933 if (container)
01934 {
01935 container->Hide();
01936 m_setsvisible = true;
01937 changed = true;
01938 }
01939 osdlock.unlock();
01940 }
01941
01942 void OSD::SetChannumText(const QString &text, int length)
01943 {
01944 osdlock.lock();
01945 OSDSet *container = GetSet("channel_number");
01946 if (container)
01947 {
01948 OSDTypeText *type = (OSDTypeText *)container->GetType("channel_number");
01949 if (type)
01950 type->SetText(text);
01951
01952 container->DisplayFor(length * 1000000);
01953 m_setsvisible = true;
01954 changed = true;
01955 }
01956
01957 osdlock.unlock();
01958 }
01959
01960 void OSD::AddCCText(const QString &text, int x, int y, int color,
01961 bool teletextmode)
01962 {
01963 osdlock.lock();
01964 OSDSet *container = GetSet("cc_page");
01965 if (container)
01966 {
01967 OSDTypeCC *ccpage = (OSDTypeCC *)container->GetType("cc_page");
01968 if (ccpage)
01969 ccpage->AddCCText(text, x, y, color, teletextmode);
01970
01971 container->Display();
01972 m_setsvisible = true;
01973 changed = true;
01974 }
01975 osdlock.unlock();
01976 }
01977
01978 void OSD::ClearAllCCText()
01979 {
01980 osdlock.lock();
01981 OSDSet *container = GetSet("cc_page");
01982 if (container)
01983 {
01984 OSDTypeCC *ccpage = (OSDTypeCC *)container->GetType("cc_page");
01985 if (ccpage)
01986 {
01987 ccpage->ClearAllCCText();
01988 }
01989
01990 container->Display(false);
01991 m_setsvisible = true;
01992 changed = true;
01993 }
01994 osdlock.unlock();
01995 }
01996
01997 void OSD::UpdateCCText(vector<ccText*> *ccbuf,
01998 int replace, int scroll, bool scroll_prsv,
01999 int scroll_yoff, int scroll_ymax)
02000 {
02001 osdlock.lock();
02002 OSDSet *container = GetSet("cc_page");
02003 if (container)
02004 {
02005 OSDTypeCC *ccpage = (OSDTypeCC *)container->GetType("cc_page");
02006 int visible = 0;
02007
02008 if (ccpage)
02009 visible = ccpage->UpdateCCText(ccbuf,
02010 replace, scroll, scroll_prsv,
02011 scroll_yoff, scroll_ymax);
02012
02013 container->Display(visible);
02014 m_setsvisible = true;
02015 changed = true;
02016 }
02017 osdlock.unlock();
02018 }
02019
02020 void OSD::SetCC708Service(const CC708Service *service)
02021 {
02022 QMutexLocker locker(&osdlock);
02023
02024 OSDSet *container = GetSet("cc708_page");
02025 if (!container)
02026 return;
02027
02028 OSDType *type = container->GetType("cc708_page");
02029 OSDType708CC *ccpage = (OSDType708CC*) type;
02030 if (!ccpage)
02031 return;
02032
02033 ccpage->SetCCService(service);
02034 container->Display(1);
02035 m_setsvisible = true;
02036 changed = true;
02037 }
02038
02039 void OSD::CC708Updated(void)
02040 {
02041 QMutexLocker locker(&osdlock);
02042
02043 OSDSet *container = GetSet("cc708_page");
02044 if (!container)
02045 return;
02046
02047 OSDType *type = container->GetType("cc708_page");
02048 OSDType708CC *ccpage = dynamic_cast<OSDType708CC*>(type);
02049 if (ccpage)
02050 {
02051 container->Display(1);
02052 m_setsvisible = true;
02053 changed = true;
02054 }
02055 }
02056
02057 TeletextViewer *OSD::GetTeletextViewer(void)
02058 {
02059 OSDSet *oset = GetSet("teletext");
02060 if (!oset)
02061 return NULL;
02062
02063 OSDType *traw = oset->GetType("teletext");
02064 return dynamic_cast<TeletextViewer*>(traw);
02065 }
02066
02067 void OSD::SetSettingsText(const QString &text, int length)
02068 {
02069 HideAllExcept("settings");
02070
02071 osdlock.lock();
02072 OSDSet *container = GetSet("settings");
02073 if (container)
02074 {
02075 OSDTypeText *type = (OSDTypeText *)container->GetType("settings");
02076 if (type)
02077 type->SetText(text);
02078
02079 container->DisplayFor(length * 1000000);
02080 m_setsvisible = true;
02081 changed = true;
02082 }
02083
02084 osdlock.unlock();
02085 }
02086
02087 void OSD::NewDialogBox(const QString &name, const QString &message,
02088 QStringList &options, int length,
02089 int initial_selection)
02090 {
02091 osdlock.lock();
02092 OSDSet *container = GetSet(name);
02093 if (container)
02094 {
02095 VERBOSE(VB_IMPORTANT, "dialog: " << name << " already exists.");
02096 return;
02097 }
02098
02099 OSDSet *base = GetSet("basedialog");
02100 if (!base)
02101 {
02102 VERBOSE(VB_IMPORTANT, "couldn't find base dialog");
02103 return;
02104 }
02105
02106 container = new OSDSet(*base);
02107 container->SetName(name);
02108 container->SetCache(false);
02109 container->SetPriority(0);
02110 container->SetAllowFade(false);
02111 AddSet(container, name, false);
02112
02113 OSDTypeText *question = (OSDTypeText *)container->GetType("message");
02114 if (question)
02115 question->SetText(message);
02116
02117 int availoptions = 0;
02118 OSDTypeText *text = NULL;
02119 do
02120 {
02121 QString name = QString("option%1").arg(availoptions + 1);
02122 text = (OSDTypeText *)container->GetType(name);
02123 if (text)
02124 availoptions++;
02125 }
02126 while (text);
02127
02128 int numoptions = options.size();
02129
02130 if (availoptions < numoptions)
02131 {
02132 VERBOSE(VB_IMPORTANT, QString("Theme allows %1 options, "
02133 "menu contains %2 options").arg(availoptions).arg(numoptions));
02134 return;
02135 }
02136
02137 int offset = availoptions - numoptions;
02138 initial_selection = max(min(numoptions - 1, initial_selection), 0);
02139
02140 for (int i = 1; i <= numoptions && i <= availoptions; i++)
02141 {
02142 QString name = QString("option%1").arg(offset + i);
02143 text = (OSDTypeText *)container->GetType(name);
02144 if (!text)
02145 {
02146 VERBOSE(VB_IMPORTANT, "Couldn't find: " << name);
02147 return;
02148 }
02149
02150 text->SetText(options[i - 1]);
02151 text->SetUseAlt(true);
02152 }
02153
02154 OSDTypePositionIndicator *opr =
02155 dynamic_cast<OSDTypePositionIndicator*>(container->GetType("selector"));
02156 if (!opr)
02157 {
02158 VERBOSE(VB_IMPORTANT,
02159 "Need a positionindicator named 'selector' in the basedialog");
02160 return;
02161 }
02162
02163 opr->SetOffset(offset);
02164 opr->SetPosition(initial_selection);
02165
02166 dialogResponseList[name] = initial_selection;
02167
02168 HighlightDialogSelection(container, offset + initial_selection);
02169
02170 if (length > 0)
02171 container->DisplayFor(length * 1000000);
02172 else
02173 container->Display();
02174
02175 m_setsvisible = true;
02176 changed = true;
02177
02178 osdlock.unlock();
02179
02180 int count = 0;
02181 while (!container->HasDisplayed() && count++ < 10)
02182 usleep(1000);
02183 }
02184
02185 void OSD::HighlightDialogSelection(OSDSet *container, int num)
02186 {
02187 int availoptions = 0;
02188 OSDTypeText *text = NULL;
02189 do
02190 {
02191 QString name = QString("option%1").arg(availoptions + 1);
02192 text = (OSDTypeText *)container->GetType(name);
02193 if (text)
02194 availoptions++;
02195 }
02196 while (text);
02197
02198 for (int i = 1; i <= availoptions; i++)
02199 {
02200 QString name = QString("option%1").arg(i);
02201 text = (OSDTypeText *)container->GetType(name);
02202 if (text)
02203 {
02204 if (i == num + 1)
02205 text->SetUseAlt(false);
02206 else
02207 text->SetUseAlt(true);
02208 }
02209 }
02210 }
02211
02212 void OSD::TurnDialogOff(const QString &name)
02213 {
02214 osdlock.lock();
02215
02216 OSDSet *container = GetSet(name);
02217 if (container)
02218 {
02219 container->Hide();
02220 changed = true;
02221 }
02222
02223 osdlock.unlock();
02224 }
02225
02226 void OSD::DialogUp(const QString &name)
02227 {
02228 osdlock.lock();
02229 OSDSet *container = GetSet(name);
02230 if (container)
02231 {
02232 OSDType *basetype = container->GetType("selector");
02233 OSDTypePositionIndicator *type =
02234 dynamic_cast<OSDTypePositionIndicator*>(basetype);
02235 if (type)
02236 {
02237 type->PositionUp();
02238 dialogResponseList[name] = type->GetPosition();
02239
02240 int selected = type->GetPosition() + type->GetOffset();
02241 HighlightDialogSelection(container, selected);
02242 changed = true;
02243 }
02244 }
02245 osdlock.unlock();
02246 }
02247
02248 void OSD::DialogDown(const QString &name)
02249 {
02250 osdlock.lock();
02251 OSDSet *container = GetSet(name);
02252 if (container)
02253 {
02254 OSDType *basetype = container->GetType("selector");
02255 OSDTypePositionIndicator *type =
02256 dynamic_cast<OSDTypePositionIndicator*>(basetype);
02257 if (type)
02258 {
02259 type->PositionDown();
02260 dialogResponseList[name] = type->GetPosition();
02261
02262 int selected = type->GetPosition() + type->GetOffset();
02263 HighlightDialogSelection(container, selected);
02264 changed = true;
02265 }
02266 }
02267 osdlock.unlock();
02268 }
02269
02270 bool OSD::DialogShowing(const QString &name)
02271 {
02272 if (name == "")
02273 return false;
02274
02275 osdlock.lock();
02276 bool ret = (GetSet(name) != NULL);
02277 osdlock.unlock();
02278
02279 return ret;
02280 }
02281
02282 void OSD::DialogAbort(const QString &name)
02283 {
02284 dialogResponseList[name] = -1;
02285 }
02286
02287 int OSD::GetDialogResponse(const QString &name)
02288 {
02289 if (dialogResponseList.contains(name))
02290 {
02291 int ret = dialogResponseList[name] + 1;
02292 dialogResponseList.erase(name);
02293
02294 return ret;
02295 }
02296 return -1;
02297 }
02298
02299 void OSD::ShowEditArrow(long long number, long long totalframes, int type)
02300 {
02301 if (!editarrowleft || !editarrowright)
02302 return;
02303
02304 char name[128];
02305 sprintf(name, "%lld-%d", number, type);
02306
02307 int pos = number * 1000 / totalframes;
02308 int xtmp = (int)(round(editarrowRect.width() * wmult) / 1000.0 * pos);
02309 int xpos = xtmp + (int)(editarrowRect.left() * wmult);
02310 int ypos = (int) round(editarrowRect.top() * hmult);
02311
02312 osdlock.lock();
02313
02314 OSDSet *set = new OSDSet(name, false,
02315 osdBounds.width(), osdBounds.height(),
02316 wmult, hmult, frameint, xoffset, yoffset);
02317 set->SetAllowFade(false);
02318 OSDSet *container = GetSet("editmode");
02319 if (container)
02320 set->SetPriority(container->GetPriority() - 1);
02321 else
02322 set->SetPriority(4);
02323
02324 AddSet(set, name, false);
02325
02326 OSDTypeImage *image;
02327 if (type == 0)
02328 image = new OSDTypeImage(*editarrowleft);
02329 else
02330 image = new OSDTypeImage(*editarrowright);
02331
02332
02333 image->Reinit(wmult, hmult);
02334
02335 xpos -= image->ImageSize().width()/2;
02336
02337 image->SetPosition(QPoint(xpos, ypos), wmult, hmult);
02338
02339 set->AddType(image);
02340 set->Display();
02341
02342 changed = true;
02343
02344 osdlock.unlock();
02345 }
02346
02347 void OSD::HideEditArrow(long long number, int type)
02348 {
02349 char name[128];
02350 sprintf(name, "%lld-%d", number, type);
02351
02352 osdlock.lock();
02353 OSDSet *set = GetSet(name);
02354 if (set)
02355 set->Hide();
02356
02357 changed = true;
02358 osdlock.unlock();
02359 }
02360
02361 bool OSD::HideAllExcept(const QString &other)
02362 {
02363 bool result = false;
02364
02365 osdlock.lock();
02366
02367 OSDSet *oset = GetSet(other);
02368
02369 vector<OSDSet *>::iterator i;
02370 for (i = setList->begin(); i != setList->end(); i++)
02371 if (*i && (*i)->Displaying())
02372 {
02373 QString name = (*i)->GetName();
02374 if (name != "cc_page" && name != "cc708_page" &&
02375 name != "menu" && name != "subtitles" &&
02376 name != "interactive" &&
02377 name != other && (!oset || !oset->CanShowWith(name)))
02378 {
02379 (*i)->Hide();
02380 result = true;
02381 }
02382 }
02383
02384 changed = true;
02385 osdlock.unlock();
02386
02387 return result;
02388 }
02389
02390 bool OSD::HideSet(const QString &name)
02391 {
02392 bool ret = false;
02393 osdlock.lock();
02394
02395 OSDSet *set = GetSet(name);
02396 if (set)
02397 {
02398 if (set->Displaying())
02399 ret = true;
02400 set->Hide();
02401 }
02402
02403 changed = true;
02404 osdlock.unlock();
02405 return ret;
02406 }
02407
02408 bool OSD::HideSets(QStringList &name)
02409 {
02410 bool ret = false;
02411 osdlock.lock();
02412
02413 OSDSet *set;
02414 QStringList::Iterator i = name.begin();
02415 for (; i != name.end(); i++)
02416 {
02417 set = GetSet(*i);
02418 if (set)
02419 {
02420 if (set->Displaying())
02421 ret = true;
02422 set->Hide();
02423 }
02424 }
02425
02426 changed = true;
02427 osdlock.unlock();
02428 return ret;
02429 }
02430
02431 void OSD::UpdateEditText(const QString &seek_amount, const QString &deletemarker,
02432 const QString &edittime, const QString &framecnt)
02433 {
02434 osdlock.lock();
02435
02436 QString name = "editmode";
02437 OSDSet *set = GetSet(name);
02438 if (set)
02439 {
02440 OSDTypeText *text = (OSDTypeText *)set->GetType("seekamount");
02441 if (text && seek_amount != QString::null)
02442 text->SetText(seek_amount);
02443 text = (OSDTypeText *)set->GetType("cutindicator");
02444 if (text && deletemarker != QString::null)
02445 text->SetText(deletemarker);
02446 text = (OSDTypeText *)set->GetType("timedisplay");
02447 if (text && edittime != QString::null)
02448 text->SetText(edittime);
02449 text = (OSDTypeText *)set->GetType("framedisplay");
02450 if (text && framecnt != QString::null)
02451 text->SetText(framecnt);
02452
02453 set->Display();
02454 m_setsvisible = true;
02455 changed = true;
02456 }
02457
02458 osdlock.unlock();
02459 }
02460
02461 void OSD::DoEditSlider(QMap<long long, int> deleteMap, long long curFrame,
02462 long long totalFrames)
02463 {
02464 osdlock.lock();
02465
02466 QString name = "editmode";
02467 OSDSet *set = GetSet(name);
02468 if (set)
02469 {
02470 QString name = "editslider";
02471 OSDTypeEditSlider *tes = (OSDTypeEditSlider *)set->GetType(name);
02472 if (tes)
02473 {
02474 tes->ClearAll();
02475
02476 bool indelete = false;
02477 int startpos = 0;
02478 int endpos = 0;
02479 bool first = true;
02480
02481 QMap<long long, int>::Iterator i = deleteMap.begin();
02482 for (; i != deleteMap.end(); ++i)
02483 {
02484 long long frame = i.key();
02485 int direction = i.data();
02486
02487 if (direction == 0 && !indelete && first)
02488 {
02489 startpos = 0;
02490 endpos = frame * 1000 / totalFrames;
02491 tes->SetRange(startpos, endpos);
02492 first = false;
02493 }
02494 else if (direction == 0)
02495 {
02496 endpos = frame * 1000 / totalFrames;
02497 tes->SetRange(startpos, endpos);
02498 indelete = false;
02499 first = false;
02500 }
02501 else if (direction == 1 && !indelete)
02502 {
02503 startpos = frame * 1000 / totalFrames;
02504 indelete = true;
02505 first = false;
02506 }
02507 }
02508
02509 if (indelete)
02510 {
02511 endpos = 1000;
02512 tes->SetRange(startpos, endpos);
02513 }
02514 }
02515
02516 name = "editposition";
02517 OSDTypePosSlider *pos = (OSDTypePosSlider *)set->GetType(name);
02518 if (pos)
02519 {
02520 int num = curFrame * 1000 / totalFrames;
02521 pos->SetPosition(num);
02522 }
02523
02524 set->Display();
02525 m_setsvisible = true;
02526 changed = true;
02527 }
02528
02529 osdlock.unlock();
02530 }
02531
02532 void OSD::SetVisible(OSDSet *set, int length)
02533 {
02534 osdlock.lock();
02535 if (length > 0)
02536 set->DisplayFor(length * 1000000);
02537 else
02538 set->Display();
02539 m_setsvisible = true;
02540 changed = true;
02541 osdlock.unlock();
02542 }
02543
02544 void OSD::DisableFade(void)
02545 {
02546 totalfadetime = 0;
02547 }
02548
02549 OSDSurface *OSD::GetDisplaySurface(void)
02550 {
02551 return drawSurface;
02552 }
02553
02554 OSDSurface *OSD::Display(void)
02555 {
02556 bool anytodisplay = false;
02557 if (!setList)
02558 return NULL;
02559
02560 bool actuallydraw = false;
02561
02562 if (changed)
02563 {
02564 actuallydraw = true;
02565 changed = false;
02566 }
02567
02568 drawSurface->SetChanged(false);
02569
02570
02571
02572 if (actuallydraw)
02573 {
02574 drawSurface->SetChanged(true);
02575 drawSurface->ClearUsed();
02576 }
02577
02578 vector<OSDSet *> removeList;
02579
02580 osdlock.lock();
02581 vector<OSDSet *>::iterator i = setList->begin();
02582 for (; i != setList->end(); i++)
02583 {
02584 OSDSet *container = (*i);
02585 if (container->Displaying())
02586 {
02587 OSDTypeText *timedisp = (OSDTypeText *)container->GetType("time");
02588 if (timedisp)
02589 {
02590 QString thetime = QTime::currentTime().toString(timeFormat);
02591 if (timedisp->GetText() != thetime)
02592 {
02593 timedisp->SetText(thetime);
02594 changed = true;
02595 }
02596 }
02597
02598 int fadetime = container->GetFadeTime();
02599 if (!container->IsFading() && (totalfadetime != fadetime))
02600 container->SetFadeTime(totalfadetime);
02601
02602 container->Draw(drawSurface, actuallydraw);
02603 anytodisplay = true;
02604
02605 changed |= container->IsFading() || container->NeedsUpdate();
02606 }
02607 else if (container->HasDisplayed())
02608 {
02609 if (!container->GetCache())
02610 removeList.push_back(container);
02611 }
02612 }
02613
02614 while (removeList.size() > 0)
02615 {
02616 OSDSet *container = removeList.back();
02617 RemoveSet(container);
02618 removeList.pop_back();
02619 }
02620
02621 osdlock.unlock();
02622
02623 m_setsvisible = anytodisplay;
02624
02625 if (m_setsvisible && !drawSurface->IsClear())
02626 return drawSurface;
02627
02628 return NULL;
02629 }
02630
02631 bool OSD::Visible(void)
02632 {
02633 return m_setsvisible;
02634 }
02635
02636 OSDSet *OSD::GetSet(const QString &text)
02637 {
02638 OSDSet *ret = NULL;
02639 if (setMap.contains(text))
02640 ret = setMap[text];
02641
02642 return ret;
02643 }
02644
02645 TTFFont *OSD::GetFont(const QString &text)
02646 {
02647 TTFFont *ret = NULL;
02648 if (fontMap.contains(text))
02649 ret = fontMap[text];
02650
02651 return ret;
02652 }
02653
02654 class comp
02655 {
02656 public:
02657 bool operator()(const OSDSet *a, const OSDSet *b)
02658 {
02659 return (a->GetPriority() > b->GetPriority());
02660 }
02661 };
02662
02663 void OSD::AddSet(OSDSet *set, QString name, bool withlock)
02664 {
02665 if (withlock)
02666 osdlock.lock();
02667
02668 setMap[name] = set;
02669 setList->push_back(set);
02670
02671 sort(setList->begin(), setList->end(), comp());
02672
02673 if (withlock)
02674 osdlock.unlock();
02675 }
02676
02677 void OSD::RemoveSet(OSDSet *set)
02678 {
02679 setMap.erase(set->GetName());
02680 vector<OSDSet *>::iterator i = setList->begin();
02681 for (; i != setList->end(); i++)
02682 if (*i == set)
02683 break;
02684
02685 if (i != setList->end())
02686 setList->erase(i);
02687
02688 delete set;
02689 }
02690
02691
02692 void OSD::StartNotify(UDPNotifyOSDSet *notifySet, int displaytime)
02693 {
02694 if (!notifySet)
02695 return;
02696
02697 vector<UDPNotifyOSDTypeText *> *textList;
02698
02699 osdlock.lock();
02700
02701 OSDSet *container = GetSet(notifySet->GetName());
02702 if (container)
02703 {
02704 textList = notifySet->GetTypeList();
02705
02706 vector<UDPNotifyOSDTypeText *>::iterator j = textList->begin();
02707 for (; j != textList->end(); j++)
02708 {
02709 UDPNotifyOSDTypeText *type = (*j);
02710 if (type)
02711 {
02712 OSDTypeText *osdtype = (OSDTypeText *)container->GetType(type->GetName());
02713 if (osdtype)
02714 osdtype->SetText(type->GetText());
02715 }
02716 }
02717
02718 if (displaytime > 0)
02719 container->DisplayFor(displaytime * 1000000);
02720 else
02721 container->Display();
02722
02723 m_setsvisible = true;
02724 changed = true;
02725 }
02726
02727 osdlock.unlock();
02728 }
02729
02730 void OSD::ClearNotify(UDPNotifyOSDSet *notifySet)
02731 {
02732 if (!notifySet)
02733 return;
02734
02735 osdlock.lock();
02736
02737 OSDSet *container = GetSet(notifySet->GetName());
02738 if (container)
02739 {
02740 container->ClearAllText();
02741 container->Hide();
02742 m_setsvisible = true;
02743 changed = true;
02744 }
02745
02746 osdlock.unlock();
02747 }
02748
02749 OSDListTreeType *OSD::ShowTreeMenu(const QString &name,
02750 OSDGenericTree *treeToShow)
02751 {
02752 if (runningTreeMenu || !treeToShow)
02753 return NULL;
02754
02755 OSDListTreeType *rettree = NULL;
02756
02757 osdlock.lock();
02758
02759 OSDSet *container = GetSet(name);
02760 if (container)
02761 {
02762 rettree = (OSDListTreeType *)container->GetType("menu");
02763 if (rettree)
02764 {
02765 rettree->SetAsTree(treeToShow);
02766 rettree->SetVisible(true);
02767 runningTreeMenu = rettree;
02768 treeMenuContainer = name;
02769 container->Display();
02770 m_setsvisible = true;
02771 changed = true;
02772 }
02773 }
02774
02775 osdlock.unlock();
02776
02777 return rettree;
02778 }
02779
02780 bool OSD::IsRunningTreeMenu(void)
02781 {
02782 if (runningTreeMenu)
02783 return true;
02784 return false;
02785 }
02786
02787 bool OSD::TreeMenuHandleKeypress(QKeyEvent *e)
02788 {
02789 if (!runningTreeMenu)
02790 return false;
02791
02792 bool ret = runningTreeMenu->HandleKeypress(e);
02793
02794 osdlock.lock();
02795
02796 if (!runningTreeMenu->IsVisible())
02797 {
02798 OSDSet *container = GetSet(treeMenuContainer);
02799 if (container)
02800 container->Hide();
02801
02802 runningTreeMenu = NULL;
02803 }
02804
02805 changed = true;
02806
02807 osdlock.unlock();
02808
02809 return ret;
02810 }
02811
02812 bool OSD::IsSetDisplaying(const QString &name)
02813 {
02814 OSDSet *oset = GetSet(name);
02815 return Visible() && (oset != NULL) && oset->Displaying();
02816 }
02817
02818 bool OSD::HasSet(const QString &name)
02819 {
02820 return setMap.contains(name);
02821 }
02822
02823 QRect OSD::GetSubtitleBounds()
02824 {
02825 return QRect(xoffset, yoffset, displaywidth, displayheight);
02826 }
02827
02828 static void initialize_osd_fonts(void)
02829 {
02830 QMutexLocker locker(&cc708_init_lock);
02831 if (cc708_defaults_initialized)
02832 return;
02833 cc708_defaults_initialized = true;
02834
02835 QString default_font_type = gContext->GetSetting(
02836 "OSDCC708DefaultFontType", "MonoSerif");
02837
02838
02839 cc708_default_font_names[0] = strdup(gContext->GetSetting(
02840 QString("OSDCC708%1Font").arg(default_font_type)));
02841 cc708_default_font_names[1] = strdup(gContext->GetSetting(
02842 QString("OSDCC708%1ItalicFont").arg(default_font_type)));
02843
02844
02845 cc708_default_font_names[2] = strdup(gContext->GetSetting(
02846 "OSDCC708MonoSerifFont"));
02847 cc708_default_font_names[3] = strdup(gContext->GetSetting(
02848 "OSDCC708MonoSerifItalicFont"));
02849
02850
02851 cc708_default_font_names[4] = strdup(gContext->GetSetting(
02852 "OSDCC708PropSerifFont"));
02853 cc708_default_font_names[5] = strdup(gContext->GetSetting(
02854 "OSDCC708PropSerifItalicFont"));
02855
02856
02857 cc708_default_font_names[6] = strdup(gContext->GetSetting(
02858 "OSDCC708MonoSansSerifFont"));
02859 cc708_default_font_names[7] = strdup(gContext->GetSetting(
02860 "OSDCC708MonoSansSerifItalicFont"));
02861
02862
02863 cc708_default_font_names[8] = strdup(gContext->GetSetting(
02864 "OSDCC708PropSansSerifFont"));
02865 cc708_default_font_names[9] = strdup(gContext->GetSetting(
02866 "OSDCC708PropSansSerifItalicFont"));
02867
02868
02869 cc708_default_font_names[10] = strdup(gContext->GetSetting(
02870 "OSDCC708CasualFont"));
02871 cc708_default_font_names[11] = strdup(gContext->GetSetting(
02872 "OSDCC708CasualItalicFont"));
02873
02874
02875 cc708_default_font_names[12] = strdup(gContext->GetSetting(
02876 "OSDCC708CursiveFont"));
02877 cc708_default_font_names[13] = strdup(gContext->GetSetting(
02878 "OSDCC708CursiveItalicFont"));
02879
02880
02881 cc708_default_font_names[14] = strdup(gContext->GetSetting(
02882 "OSDCC708CapitalsFont"));
02883 cc708_default_font_names[15] = strdup(gContext->GetSetting(
02884 "OSDCC708CapitalsItalicFont"));
02885 }