bool TeletextScreen::InitialiseFont() { static bool initialised = false; //QString font = gCoreContext->GetSetting("DefaultSubtitleFont", "FreeMono"); if (initialised) { return true; #if 0 if (gTTFont->face().family() == font) return true; delete gTTFont; #endif // 0 } MythFontProperties *mythfont = new MythFontProperties(); QString font = SubtitleScreen::GetTeletextFontName(); if (mythfont) { QFont newfont(font); font.detach(); mythfont->SetFace(newfont); gTTFont = mythfont; } else return false; initialised = true; LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Loaded main subtitle font '%1'") .arg(font)); return true; }
bool SubtitleScreen::InitialiseFont(int fontStretch) { static bool initialised = false; QString font = gCoreContext->GetSetting("OSDSubFont", "FreeSans"); if (initialised) { if (gTextSubFont->face().family() == font && gTextSubFont->face().stretch() == fontStretch) { return true; } delete gTextSubFont; } MythFontProperties *mythfont = new MythFontProperties(); if (mythfont) { QFont newfont(font); newfont.setStretch(fontStretch); font.detach(); mythfont->SetFace(newfont); mythfont->SetOutline(true, Qt::black, 2, 255); gTextSubFont = mythfont; } else return false; initialised = true; LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Loaded main subtitle font '%1'") .arg(font)); return true; }
void MythUIType::Draw(MythPainter *p, int xoffset, int yoffset, int alphaMod, QRect clipRect) { m_DirtyRegion = QRegion(QRect(0, 0, 0, 0)); if (!m_Visible || m_Vanished) return; QRect realArea = m_Area.toQRect(); realArea.translate(xoffset, yoffset); if (!realArea.intersects(clipRect)) return; DrawSelf(p, xoffset, yoffset, alphaMod, clipRect); QList<MythUIType *>::Iterator it; for (it = m_ChildrenList.begin(); it != m_ChildrenList.end(); ++it) { (*it)->Draw(p, xoffset + m_Area.x(), yoffset + m_Area.y(), CalcAlpha(alphaMod), clipRect); } if (p->ShowBorders()) { static const QBrush nullbrush(Qt::NoBrush); p->DrawRect(realArea, nullbrush, QPen(m_BorderColor), 255); if (p->ShowTypeNames()) { MythFontProperties font; font.SetFace(QFont("Droid Sans")); font.SetColor(m_BorderColor); font.SetPointSize(8); p->DrawText(realArea, objectName(), 0, font, 255, realArea); } } }
bool SubtitleScreen::Initialise708Fonts(int fontStretch) { static bool initialised = false; if (initialised) { foreach(MythFontProperties* font, gCC708Fonts) font->face().setStretch(fontStretch); return true; } LOG(VB_GENERAL, LOG_INFO, "Initialise708Fonts()"); QStringList fonts; fonts.append("Droid Sans Mono"); // default fonts.append("FreeMono"); // mono serif fonts.append("DejaVu Serif"); // prop serif fonts.append("Droid Sans Mono"); // mono sans fonts.append("Liberation Sans"); // prop sans fonts.append("Purisa"); // casual fonts.append("URW Chancery L"); // cursive fonts.append("Impact"); // capitals int count = 0; foreach(QString font, fonts) { MythFontProperties *mythfont = new MythFontProperties(); if (mythfont) { QFont newfont(font); newfont.setStretch(fontStretch); font.detach(); mythfont->SetFace(newfont); gCC708Fonts.insert(count, mythfont); count++; } }
MythFontProperties *MythFontProperties::ParseFromXml( const QString &filename, const QDomElement &element, MythUIType *parent, bool addToGlobal, bool showWarnings) { // Crappy, but cached. Move to GlobalFontMap? static bool show_available = true; bool fromBase = false; MythFontProperties *newFont = new MythFontProperties(); newFont->Freeze(); if (element.tagName() == "font") LOG(VB_GENERAL, LOG_WARNING, LOC + QString("File %1: Use of 'font' is deprecated in favour of " "'fontdef'") .arg(filename)); QString name = element.attribute("name", ""); if (name.isEmpty()) { VERBOSE_XML(VB_GENERAL, LOG_ERR, filename, element, "Font requires a name"); delete newFont; return NULL; } QString base = element.attribute("from", ""); if (!base.isEmpty()) { MythFontProperties *tmp = NULL; if (parent) tmp = parent->GetFont(base); if (!tmp) tmp = GetGlobalFontMap()->GetFont(base); if (!tmp) { VERBOSE_XML(VB_GENERAL, LOG_ERR, filename, element, QString("Specified base font '%1' does not exist.").arg(base)); delete newFont; return NULL; } *newFont = *tmp; fromBase = true; } int size, pixelsize; size = pixelsize = -1; QString face = element.attribute("face", ""); if (face.isEmpty()) { if (!fromBase) { VERBOSE_XML(VB_GENERAL, LOG_ERR, filename, element, "Font needs a face"); delete newFont; return NULL; } } else { newFont->m_face.setFamily(face); } if (addToGlobal && GetGlobalFontMap()->Contains(name)) { MythFontProperties *tmp = GetGlobalFontMap()->GetFont(name); if (showWarnings) { VERBOSE_XML(VB_GENERAL, LOG_WARNING, filename, element, QString("Attempting to define '%1'\n\t\t\t" "with face '%2', but it already " "exists with face '%3'") .arg(name).arg(QFontInfo(newFont->m_face).family()) .arg((tmp) ? QFontInfo(tmp->m_face).family() : "ERROR")); } delete newFont; return NULL; } QString hint = element.attribute("stylehint", ""); if (!hint.isEmpty()) { newFont->m_face.setStyleHint((QFont::StyleHint)hint.toInt()); } for (QDomNode child = element.firstChild(); !child.isNull(); child = child.nextSibling()) { QDomElement info = child.toElement(); if (!info.isNull()) { if (info.tagName() == "size") { size = getFirstText(info).toInt(); } else if (info.tagName() == "pixelsize") { pixelsize = getFirstText(info).toInt(); } else if (info.tagName() == "color") { newFont->m_brush = QBrush(QColor(getFirstText(info))); } else if (info.tagName() == "gradient") { newFont->m_brush = parseGradient(info); } else if (info.tagName() == "shadowcolor") { newFont->m_shadowColor = QColor(getFirstText(info)); } else if (info.tagName() == "shadowoffset") { newFont->m_hasShadow = true; newFont->m_shadowOffset = parsePoint(info, false); } else if (info.tagName() == "shadowalpha") { newFont->m_shadowAlpha = getFirstText(info).toInt(); } else if (info.tagName() == "outlinecolor") { newFont->m_outlineColor = QColor(getFirstText(info)); } else if (info.tagName() == "outlinesize") { newFont->m_hasOutline = true; newFont->m_outlineSize = getFirstText(info).toInt(); } else if (info.tagName() == "outlinealpha") { newFont->m_outlineAlpha = getFirstText(info).toInt(); } else if (info.tagName() == "italics") { newFont->m_face.setItalic(parseBool(info)); } else if (info.tagName() == "letterspacing") { newFont->m_face.setLetterSpacing(QFont::AbsoluteSpacing, getFirstText(info).toInt()); } else if (info.tagName() == "wordspacing") { newFont->m_face.setWordSpacing(getFirstText(info).toInt()); } else if (info.tagName() == "decoration") { QString dec = getFirstText(info).toLower(); QStringList values = dec.split(','); QStringList::Iterator it; for ( it = values.begin(); it != values.end(); ++it ) { if (*it == "underline") newFont->m_face.setUnderline(true); else if (*it == "overline") newFont->m_face.setOverline(true); else if (*it == "strikeout") newFont->m_face.setStrikeOut(true); } } else if (info.tagName() == "weight") { QString weight = getFirstText(info).toLower(); if (weight == "ultralight" || weight == "1") newFont->m_face.setWeight(1); else if (weight == "light" || weight == "2") newFont->m_face.setWeight(QFont::Light); else if (weight == "normal" || weight == "3") newFont->m_face.setWeight(QFont::Normal); else if (weight == "demibold" || weight == "4") newFont->m_face.setWeight(QFont::DemiBold); else if (weight == "bold" || weight == "5") newFont->m_face.setWeight(QFont::Bold); else if (weight == "black" || weight == "6") newFont->m_face.setWeight(QFont::Black); else if (weight == "ultrablack" || weight == "7") newFont->m_face.setWeight(99); else newFont->m_face.setWeight(QFont::Normal); } else if (info.tagName() == "stretch") { QString stretch = getFirstText(info).toLower(); if (stretch == "ultracondensed" || stretch == "1") newFont->m_stretch = QFont::UltraCondensed; else if (stretch == "extracondensed" || stretch == "2") newFont->m_stretch = QFont::ExtraCondensed; else if (stretch == "condensed" || stretch == "3") newFont->m_stretch = QFont::Condensed; else if (stretch == "semicondensed" || stretch == "4") newFont->m_stretch = QFont::SemiCondensed; else if (stretch == "unstretched" || stretch == "5") newFont->m_stretch = QFont::Unstretched; else if (stretch == "semiexpanded" || stretch == "6") newFont->m_stretch = QFont::SemiExpanded; else if (stretch == "expanded" || stretch == "7") newFont->m_stretch = QFont::Expanded; else if (stretch == "extraexpanded" || stretch == "8") newFont->m_stretch = QFont::ExtraExpanded; else if (stretch == "ultraexpanded" || stretch == "9") newFont->m_stretch = QFont::UltraExpanded; else newFont->m_stretch = QFont::Unstretched; newFont->m_face.setStretch(newFont->m_stretch); } else { VERBOSE_XML(VB_GENERAL, LOG_ERR, filename, info, QString("Unknown tag in font '%1'").arg(name)); delete newFont; return NULL; } } } if (size <= 0 && pixelsize <= 0 && !fromBase) { VERBOSE_XML(VB_GENERAL, LOG_ERR, filename, element, "Font size must be greater than 0."); delete newFont; return NULL; } else if (pixelsize > 0) { newFont->SetPixelSize(pixelsize); } else if (size > 0) { newFont->SetPointSize(size); } newFont->Unfreeze(); QFontInfo fi(newFont->m_face); if (newFont->m_face.family() != fi.family()) { VERBOSE_XML(VB_GENERAL, LOG_ERR, filename, element, QString("Failed to load '%1', got '%2' instead") .arg(newFont->m_face.family()).arg(fi.family())); if (show_available) { LOG(VB_GUI, LOG_DEBUG, "Available fonts:"); QFontDatabase database; foreach (const QString &family, database.families()) { QStringList family_styles; family_styles << family + "::"; foreach (const QString &style, database.styles(family)) { family_styles << style + ":"; QString sizes; bool tic = false; foreach (int points, database.smoothSizes(family, style)) { if (tic) sizes += ","; tic = true; sizes += QString::number(points); } sizes += "; "; family_styles << sizes.trimmed(); } LOG(VB_GUI, LOG_DEBUG, family_styles.join(" ")); } show_available = false; } }
void MythPainter::DrawTextPriv(MythImage *im, const QString &msg, int flags, const QRect &r, const MythFontProperties &font) { if (!im) return; QColor outlineColor; int outlineSize = 0; int outlineAlpha; if (font.hasOutline()) font.GetOutline(outlineColor, outlineSize, outlineAlpha); QPoint shadowOffset(0, 0); QColor shadowColor; int shadowAlpha; if (font.hasShadow()) font.GetShadow(shadowOffset, shadowColor, shadowAlpha); QFontMetrics fm(font.face()); int totalHeight = fm.height() + outlineSize + std::max(outlineSize, std::abs(shadowOffset.y())); // initialPaddingX is the number of pixels from the left of the // input QRect to the left of the actual text. It is always 0 // because we don't add padding to the text rectangle. int initialPaddingX = 0; // initialPaddingY is the number of pixels from the top of the // input QRect to the top of the actual text. It may be nonzero // because of extra vertical padding. int initialPaddingY = (r.height() - totalHeight) / 2; // Hack. Normally we vertically center the text due to some // (solvable) issues in the SubtitleScreen code - the text rect // and the background rect are both created with PAD_WIDTH extra // padding, and to honor Qt::AlignTop, the text rect needs to be // without padding. This doesn't work for Qt::TextWordWrap, since // the first line will be vertically centered with subsequence // lines below. So if Qt::TextWordWrap is set, we do top // alignment. if (flags & Qt::TextWordWrap) initialPaddingY = 0; // textOffsetX is the number of pixels from r.left() to the left // edge of the core text. This assumes that flags contains // Qt::AlignLeft. int textOffsetX = initialPaddingX + std::max(outlineSize, -shadowOffset.x()); // textOffsetY is the number of pixels from r.top() to the top // edge of the core text. This assumes that flags contains // Qt::AlignTop. int textOffsetY = initialPaddingY + std::max(outlineSize, -shadowOffset.y()); QImage pm(r.size(), QImage::Format_ARGB32); QColor fillcolor = font.color(); if (font.hasOutline()) fillcolor = outlineColor; fillcolor.setAlpha(0); pm.fill(fillcolor.rgba()); QPainter tmp(&pm); QFont tmpfont = font.face(); tmpfont.setStyleStrategy(QFont::OpenGLCompatible); tmp.setFont(tmpfont); QPainterPath path; if (font.hasOutline()) path.addText(0, 0, tmpfont, msg); if (font.hasShadow()) { QRect a = QRect(0, 0, r.width(), r.height()); a.translate(shadowOffset.x() + textOffsetX, shadowOffset.y() + textOffsetY); shadowColor.setAlpha(shadowAlpha); tmp.setPen(shadowColor); tmp.drawText(a, flags, msg); } if (font.hasOutline()) { // QPainter::drawText() treats the Y coordinate as the top of // the text (when Qt::AlignTop is used). However, // QPainterPath::addText() treats the Y coordinate as the base // line of the text. To translate from the top to the base // line, we need to add QFontMetrics::ascent(). int adjX = 0; int adjY = fm.ascent(); outlineColor.setAlpha(outlineAlpha); tmp.setPen(outlineColor); path.translate(adjX + textOffsetX, adjY + textOffsetY); QPen pen = tmp.pen(); pen.setWidth(outlineSize * 2 + 1); pen.setCapStyle(Qt::RoundCap); pen.setJoinStyle(Qt::RoundJoin); tmp.setPen(pen); tmp.drawPath(path); path.translate(outlineSize, outlineSize); } tmp.setPen(QPen(font.GetBrush(), 0)); tmp.setBrush(font.GetBrush()); tmp.drawText(textOffsetX, textOffsetY, r.width(), r.height(), flags, msg); tmp.end(); im->Assign(pm); }
bool MythUIText::ParseElement( const QString &filename, QDomElement &element, bool showWarnings) { if (element.tagName() == "area") { SetArea(parseRect(element)); m_OrigDisplayRect = m_Area; } // else if (element.tagName() == "altarea") // Unused, but maybe in future? // m_AltDisplayRect = parseRect(element); else if (element.tagName() == "font") { QString fontname = getFirstText(element); MythFontProperties *fp = GetFont(fontname); if (!fp) fp = GetGlobalFontMap()->GetFont(fontname); if (fp) { MythFontProperties font = *fp; int screenHeight = GetMythMainWindow()->GetUIScreenRect().height(); font.Rescale(screenHeight); int fontStretch = GetMythUI()->GetFontStretch(); font.AdjustStretch(fontStretch); QString state = element.attribute("state",""); if (!state.isEmpty()) { m_FontStates.insert(state, font); } else { m_FontStates.insert("default", font); *m_Font = m_FontStates["default"]; } } } else if (element.tagName() == "value") { if (element.attribute("lang","").isEmpty()) { m_Message = qApp->translate("ThemeUI", parseText(element).toUtf8(), NULL, QCoreApplication::UnicodeUTF8); } #if 0 else if (element.attribute("lang","").toLower() == gCoreContext->GetLanguageAndVariant()) #else else if (element.attribute("lang","").toLower() == "en_us") #endif { m_Message = parseText(element); } #if 0 else if (element.attribute("lang","").toLower() == gCoreContext->GetLanguage()) #else else if (element.attribute("lang","").toLower() == "en") #endif { m_Message = parseText(element); } m_DefaultMessage = m_Message; SetText(m_Message); } else if (element.tagName() == "template")
void MythPainter::DrawTextPriv(MythImage *im, const QString &msg, int flags, const QRect &r, const MythFontProperties &font) { if (!im) return; QPoint drawOffset; font.GetOffset(drawOffset); QImage pm(r.size(), QImage::Format_ARGB32); QColor fillcolor = font.color(); if (font.hasOutline()) { QColor outlineColor; int outlineSize, outlineAlpha; font.GetOutline(outlineColor, outlineSize, outlineAlpha); fillcolor = outlineColor; } fillcolor.setAlpha(0); pm.fill(fillcolor.rgba()); QPainter tmp(&pm); QFont tmpfont = font.face(); tmpfont.setStyleStrategy(QFont::OpenGLCompatible); tmp.setFont(tmpfont); if (font.hasShadow()) { QPoint shadowOffset; QColor shadowColor; int shadowAlpha; font.GetShadow(shadowOffset, shadowColor, shadowAlpha); QRect a = QRect(0, 0, r.width(), r.height()); a.translate(shadowOffset.x() + drawOffset.x(), shadowOffset.y() + drawOffset.y()); shadowColor.setAlpha(shadowAlpha); tmp.setPen(shadowColor); tmp.drawText(a, flags, msg); } if (font.hasOutline()) { QColor outlineColor; int outlineSize, outlineAlpha; font.GetOutline(outlineColor, outlineSize, outlineAlpha); /* FIXME: use outlineAlpha */ int outalpha = 16; QRect a = QRect(0, 0, r.width(), r.height()); a.translate(-outlineSize + drawOffset.x(), -outlineSize + drawOffset.y()); outlineColor.setAlpha(outalpha); tmp.setPen(outlineColor); tmp.drawText(a, flags, msg); for (int i = (0 - outlineSize + 1); i <= outlineSize; i++) { a.translate(1, 0); tmp.drawText(a, flags, msg); } for (int i = (0 - outlineSize + 1); i <= outlineSize; i++) { a.translate(0, 1); tmp.drawText(a, flags, msg); } for (int i = (0 - outlineSize + 1); i <= outlineSize; i++) { a.translate(-1, 0); tmp.drawText(a, flags, msg); } for (int i = (0 - outlineSize + 1); i <= outlineSize; i++) { a.translate(0, -1); tmp.drawText(a, flags, msg); } } tmp.setPen(QPen(font.GetBrush(), 0)); tmp.drawText(drawOffset.x(), drawOffset.y(), r.width(), r.height(), flags, msg); tmp.end(); im->Assign(pm); }
bool MythUIText::ParseElement( const QString &filename, QDomElement &element, bool showWarnings) { if (element.tagName() == "area") { SetArea(parseRect(element)); m_OrigDisplayRect = m_Area; } // else if (element.tagName() == "altarea") // Unused, but maybe in future? // m_AltDisplayRect = parseRect(element); else if (element.tagName() == "font") { QString fontname = getFirstText(element); MythFontProperties *fp = GetFont(fontname); if (!fp) fp = GetGlobalFontMap()->GetFont(fontname); if (fp) { MythFontProperties font = *fp; int screenHeight = GetMythMainWindow()->GetUIScreenRect().height(); font.Rescale(screenHeight); int fontStretch = GetMythUI()->GetFontStretch(); font.AdjustStretch(fontStretch); QString state = element.attribute("state",""); if (!state.isEmpty()) { m_FontStates.insert(state, font); } else { m_FontStates.insert("default", font); *m_Font = m_FontStates["default"]; } } } else if (element.tagName() == "value") { if (element.attribute("lang","").isEmpty()) { m_Message = qApp->translate("ThemeUI", parseText(element).toUtf8(), NULL, QCoreApplication::UnicodeUTF8); } else if (element.attribute("lang","").toLower() == gCoreContext->GetLanguageAndVariant()) { m_Message = parseText(element); } else if (element.attribute("lang","").toLower() == gCoreContext->GetLanguage()) { m_Message = parseText(element); } m_DefaultMessage = m_Message; SetText(m_Message); } else if (element.tagName() == "template") { m_TemplateText = parseText(element); } else if (element.tagName() == "cutdown") { SetCutDown(parseBool(element)); } else if (element.tagName() == "multiline") { SetMultiLine(parseBool(element)); } else if (element.tagName() == "align") { QString align = getFirstText(element).toLower(); SetJustification(parseAlignment(align)); } else if (element.tagName() == "colorcycle") { if (GetPainter()->SupportsAnimation()) { QString tmp = element.attribute("start"); if (!tmp.isEmpty()) m_startColor = QColor(tmp); tmp = element.attribute("end"); if (!tmp.isEmpty()) m_endColor = QColor(tmp); tmp = element.attribute("steps"); if (!tmp.isEmpty()) m_numSteps = tmp.toInt(); // initialize the rest of the stuff CycleColor(m_startColor, m_endColor, m_numSteps); } else m_colorCycling = false; m_colorCycling = parseBool(element.attribute("disable")); } else if (element.tagName() == "scroll") { if (GetPainter()->SupportsAnimation()) { QString tmp = element.attribute("direction"); if (!tmp.isEmpty()) { tmp = tmp.toLower(); if (tmp == "left") m_scrollDirection = ScrollLeft; else if (tmp == "right") m_scrollDirection = ScrollRight; else if (tmp == "up") m_scrollDirection = ScrollUp; else if (tmp == "down") m_scrollDirection = ScrollDown; } m_scrolling = true; } else m_scrolling = false; } else if (element.tagName() == "case") { QString stringCase = getFirstText(element).toLower(); if (stringCase == "lower") m_textCase = CaseLower; else if (stringCase == "upper") m_textCase = CaseUpper; else if (stringCase == "capitalisefirst") m_textCase = CaseCapitaliseFirst; else if (stringCase == "capitaliseall") m_textCase = CaseCapitaliseAll; else m_textCase = CaseNormal; FillCutMessage(); } else { return MythUIType::ParseElement(filename, element, showWarnings); } return true; }
void MythQtPainter::DrawText(const QRect &r, const QString &msg, int flags, const MythFontProperties &font, int alpha, const QRect &boundRect) { if (!painter) { VERBOSE(VB_IMPORTANT, "FATAL ERROR: DrawText called with no painter"); return; } (void)alpha; painter->setOpacity(static_cast<float>(alpha) / 255.0); painter->setFont(font.face()); if (font.hasShadow()) { QPoint shadowOffset; QColor shadowColor; int shadowAlpha; font.GetShadow(shadowOffset, shadowColor, shadowAlpha); shadowColor.setAlpha(shadowAlpha); QRect a = r; a.translate(shadowOffset.x(), shadowOffset.y()); painter->setPen(shadowColor); painter->drawText(a, flags, msg); } if (font.hasOutline() && alpha > 128) { QColor outlineColor; int outlineSize, outlineAlpha; font.GetOutline(outlineColor, outlineSize, outlineAlpha); if (GetMythMainWindow()->GetUIScreenRect().height() > 700) outlineSize = 1; painter->setPen(outlineColor); QRect a = r; a.translate(0 - outlineSize, 0 - outlineSize); painter->drawText(a, flags, msg); for (int i = (0 - outlineSize + 1); i <= outlineSize; i++) { a.translate(1, 0); painter->drawText(a, flags, msg); } for (int i = (0 - outlineSize + 1); i <= outlineSize; i++) { a.translate(0, 1); painter->drawText(a, flags, msg); } for (int i = (0 - outlineSize + 1); i <= outlineSize; i++) { a.translate(-1, 0); painter->drawText(a, flags, msg); } for (int i = (0 - outlineSize + 1); i <= outlineSize; i++) { a.translate(0, -1); painter->drawText(a, flags, msg); } } painter->setPen(QPen(font.GetBrush(), 0)); painter->drawText(r, flags, msg); painter->setOpacity(1.0); }
void SubtitleScreen::Display708Strings(const CC708Window &win, int num, float aspect, vector<CC708String*> &list) { LOG(VB_VBI, LOG_INFO,LOC + QString("Display Win %1, Anchor_id %2, x_anch %3, y_anch %4, " "relative %5") .arg(num).arg(win.anchor_point).arg(win.anchor_horizontal) .arg(win.anchor_vertical).arg(win.relative_pos)); bool display = false; MythFontProperties *mythfont; uint max_row_width = 0; uint total_height = 0; uint i = 0; for (uint row = 0; (row < win.true_row_count) && (i < list.size()); row++) { uint row_width = 0, max_row_height = 0; for (; (i < list.size()) && list[i] && (list[i]->y <= row); i++) { if (list[i]->y < row) continue; mythfont = Get708Font(list[i]->attr); if (!mythfont) continue; QString text = list[i]->str.trimmed(); if (!text.isEmpty()) display = true; QFontMetrics font(*(mythfont->GetFace())); uint height = (uint)font.height() * (1 + PAD_HEIGHT); row_width += font.width(list[i]->str) + (font.maxWidth() * PAD_WIDTH * 2); max_row_height = max(max_row_height, height); } max_row_width = max(max_row_width, row_width); total_height += max_row_height; } if (!display) return; float xrange = win.relative_pos ? 100.0f : (aspect > 1.4f) ? 210.0f : 160.0f; float yrange = win.relative_pos ? 100.0f : 75.0f; float xmult = (float)m_safeArea.width() / xrange; float ymult = (float)m_safeArea.height() / yrange; uint anchor_x = (uint)(xmult * (float)win.anchor_horizontal); uint anchor_y = (uint)(ymult * (float)win.anchor_vertical); if (win.anchor_point % 3 == 1) anchor_x -= (((int)max_row_width) / 2); if (win.anchor_point % 3 == 2) anchor_x -= (int)max_row_width; if (win.anchor_point / 3 == 1) anchor_y -= (((int)total_height) / 2); if (win.anchor_point / 3 == 2) anchor_y -= (int)total_height; if (win.GetFillAlpha()) // TODO border? { QRect bg(anchor_x, anchor_y, max_row_width, total_height); QBrush fill(win.GetFillColor(), Qt::SolidPattern); MythUIShape *shape = new MythUIShape(this, QString("cc708bg%1").arg(num)); shape->SetFillBrush(fill); shape->SetArea(MythRect(bg)); m_708imageCache[num].append(shape); m_refreshArea = true; } i = 0; int y = anchor_y; for (uint row = 0; (row < win.true_row_count) && (i < list.size()); row++) { uint maxheight = 0; int x = anchor_x; bool first = true; for (; (i < list.size()) && list[i] && (list[i]->y <= row); i++) { bool last = ((i + 1) == list.size()); if (!last) last = (list[i + 1]->y > row); QString rawstring = list[i]->str; mythfont = Get708Font(list[i]->attr); if ((list[i]->y < row) || !mythfont || rawstring.isEmpty()) continue; QString trimmed = rawstring.trimmed(); if (!trimmed.size() && last) continue; QFontMetrics font(*(mythfont->GetFace())); uint height = (uint)font.height() * (1 + PAD_HEIGHT); maxheight = max(maxheight, height); uint spacewidth = font.width(QString(" ")); uint textwidth = font.width(trimmed); int leading = 0; int trailing = 0; if (trimmed.size() != rawstring.size()) { if (trimmed.size()) { leading = rawstring.indexOf(trimmed.at(0)); trailing = rawstring.size() - trimmed.size() - leading; } else { leading = rawstring.size(); } leading *= spacewidth; trailing *= spacewidth; } if (!leading) textwidth += spacewidth * PAD_WIDTH; if (!trailing) textwidth += spacewidth * PAD_WIDTH; bool background = list[i]->attr.GetBGAlpha(); QBrush bgfill = QBrush((list[i]->attr.GetBGColor(), Qt::SolidPattern)); if (leading && background && !first) { // draw background for leading space QRect space(x, y, leading, height); MythUIShape *shape = new MythUIShape(this, QString("cc708shape%1x%2lead").arg(row).arg(i)); shape->SetFillBrush(bgfill); shape->SetArea(MythRect(space)); m_708imageCache[num].append(shape); m_refreshArea = true; } x += leading; QRect rect(x, y, textwidth, height); if (trimmed.size() && textwidth && background) { MythUIShape *shape = new MythUIShape(this, QString("cc708shape%1x%2main").arg(row).arg(i)); shape->SetFillBrush(bgfill); shape->SetArea(MythRect(rect)); m_708imageCache[num].append(shape); m_refreshArea = true; } if (trimmed.size() && textwidth) { MythUIText *text = new MythUIText(list[i]->str, *mythfont, rect, rect, (MythUIType*)this, QString("cc708text%1x%2").arg(row).arg(i)); m_708imageCache[num].append(text); if (text) text->SetJustification(Qt::AlignCenter); m_refreshArea = true; } x += textwidth; if (trailing && background && !last) { // draw background for trailing space QRect space(x, y, trailing, height); MythUIShape *shape = new MythUIShape(this, QString("cc708shape%1x%2trail").arg(row).arg(i)); shape->SetFillBrush(bgfill); shape->SetArea(MythRect(space)); m_708imageCache[num].append(shape); m_refreshArea = true; } x += trailing; first = false; LOG(VB_VBI, LOG_INFO, QString("Win %1 row %2 String '%3'") .arg(num).arg(row).arg(list[i]->str)); } y += maxheight; } }