|
MythTV
0.26-pre
|
00001 00002 #include "mythuiguidegrid.h" 00003 00004 // ANSI C headers 00005 #include <cmath> 00006 00007 // C++ headers 00008 #include <algorithm> 00009 using namespace std; 00010 00011 // Qt headers 00012 #include <QFile> 00013 #include <QDomElement> 00014 00015 // myth 00016 #include "mythfontproperties.h" 00017 #include "mythuihelper.h" 00018 #include "x11colors.h" 00019 #include "mythlogging.h" 00020 #include "mythimage.h" 00021 #include "mythuitype.h" 00022 #include "mythmainwindow.h" 00023 #include "mythdb.h" 00024 00025 #define LOC QString("MythUIGuideGrid: ") 00026 00027 MythUIGuideGrid::MythUIGuideGrid(MythUIType *parent, const QString &name) 00028 : MythUIType(parent, name) 00029 { 00030 // themeable setting defaults 00031 m_channelCount = 5; 00032 m_timeCount = 4; 00033 m_verticalLayout = false; 00034 00035 m_font = new MythFontProperties(); 00036 m_justification = Qt::AlignLeft | Qt::AlignTop | Qt::TextWordWrap; 00037 m_multilineText = true; 00038 m_cutdown = true; 00039 00040 m_selType = "box"; 00041 m_drawSelLine = QPen(Qt::NoPen); 00042 m_drawSelFill = QBrush(Qt::NoBrush); 00043 00044 for (uint x = 0; x < RECSTATUSSIZE; x++) 00045 m_recImages[x] = NULL; 00046 00047 for (uint x = 0; x < ARROWIMAGESIZE; x++) 00048 m_arrowImages[x] = NULL; 00049 00050 m_fillType = Solid; 00051 00052 m_rowCount = 0; 00053 m_progPastCol = 0; 00054 00055 m_drawCategoryColors = true; 00056 m_drawCategoryText = true; 00057 m_categoryAlpha = 255; 00058 00059 QMap<QString, QString> catColors; 00060 parseDefaultCategoryColors(catColors); 00061 SetCategoryColors(catColors); 00062 00063 } 00064 00065 void MythUIGuideGrid::Finalize(void) 00066 { 00067 m_rowCount = m_channelCount; 00068 00069 allData = new QList<UIGTCon *>[m_rowCount]; 00070 00071 MythUIType::Finalize(); 00072 } 00073 00074 MythUIGuideGrid::~MythUIGuideGrid() 00075 { 00076 for (int i = 0; i < m_rowCount; i++) 00077 ResetRow(i); 00078 00079 delete [] allData; 00080 00081 delete m_font; 00082 m_font = NULL; 00083 00084 for (uint x = 0; x < RECSTATUSSIZE; x++) 00085 { 00086 if (m_recImages[x]) 00087 m_recImages[x]->DownRef(); 00088 } 00089 00090 for (uint x = 0; x < ARROWIMAGESIZE; x++) 00091 { 00092 if (m_arrowImages[x]) 00093 m_arrowImages[x]->DownRef(); 00094 } 00095 } 00096 00097 bool MythUIGuideGrid::ParseElement( 00098 const QString &filename, QDomElement &element, bool showWarnings) 00099 { 00100 if (element.tagName() == "layout") 00101 { 00102 QString layout = getFirstText(element).toLower(); 00103 m_verticalLayout = (layout == "vertical"); 00104 } 00105 else if (element.tagName() == "channels") 00106 { 00107 m_channelCount = getFirstText(element).toInt(); 00108 m_channelCount = max(m_channelCount, 1); 00109 m_channelCount = min(m_channelCount, MAX_DISPLAY_CHANS); 00110 } 00111 else if (element.tagName() == "timeslots") 00112 { 00113 m_timeCount = getFirstText(element).toInt(); 00114 m_timeCount = max(m_timeCount, 1); 00115 m_timeCount = min(m_timeCount, 8); 00116 } 00117 else if (element.tagName() == "solidcolor") 00118 { 00119 QString color = getFirstText(element); 00120 m_solidColor = QColor(color); 00121 } 00122 else if (element.tagName() == "selector") 00123 { 00124 m_selType = element.attribute("type"); 00125 QString lineColor = element.attribute("linecolor", ""); 00126 QString fillColor = element.attribute("fillcolor", ""); 00127 00128 if (!lineColor.isEmpty()) 00129 { 00130 m_drawSelLine = QPen(QColor(lineColor)); 00131 m_drawSelLine.setWidth(2); 00132 } 00133 else 00134 { 00135 m_drawSelLine = QPen(Qt::NoPen); 00136 } 00137 00138 if (!fillColor.isEmpty()) 00139 { 00140 m_drawSelFill = QBrush(QColor(fillColor)); 00141 } 00142 else 00143 { 00144 m_drawSelFill = QBrush(Qt::NoBrush); 00145 } 00146 } 00147 else if (element.tagName() == "recordingcolor") 00148 { 00149 QString color = getFirstText(element); 00150 m_recordingColor = QColor(color); 00151 } 00152 else if (element.tagName() == "conflictingcolor") 00153 { 00154 QString color = getFirstText(element); 00155 m_conflictingColor = QColor(color); 00156 } 00157 else if (element.tagName() == "categoryalpha") 00158 { 00159 m_categoryAlpha = getFirstText(element).toInt(); 00160 m_categoryAlpha = max(m_categoryAlpha, 1); 00161 m_categoryAlpha = min(m_categoryAlpha, 255); 00162 } 00163 else if (element.tagName() == "showcategories") 00164 { 00165 m_drawCategoryText = parseBool(element); 00166 } 00167 else if (element.tagName() == "showcategorycolors") 00168 { 00169 m_drawCategoryColors = parseBool(element); 00170 } 00171 else if (element.tagName() == "cutdown") 00172 { 00173 m_cutdown = parseBool(element); 00174 } 00175 else if (element.tagName() == "multiline") 00176 { 00177 SetMultiLine(parseBool(element)); 00178 } 00179 else if (element.tagName() == "textoffset") 00180 { 00181 m_textOffset = parsePoint(element); 00182 } 00183 else if (element.tagName() == "font") 00184 { 00185 QString fontname = getFirstText(element); 00186 MythFontProperties *font = GetFont(fontname); 00187 00188 if (!font) 00189 font = GetGlobalFontMap()->GetFont(fontname); 00190 00191 if (font) 00192 { 00193 MythFontProperties fontcopy = *font; 00194 int screenHeight = GetMythMainWindow()->GetUIScreenRect().height(); 00195 fontcopy.Rescale(screenHeight); 00196 int fontStretch = GetMythUI()->GetFontStretch(); 00197 fontcopy.AdjustStretch(fontStretch); 00198 *m_font = fontcopy; 00199 } 00200 else 00201 LOG(VB_GENERAL, LOG_ERR, LOC + "Unknown font: " + fontname); 00202 } 00203 else if (element.tagName() == "recordstatus") 00204 { 00205 int inttype = 0; 00206 QString typ = element.attribute("type"); 00207 QString img = element.attribute("image"); 00208 00209 if (typ == "SingleRecord") 00210 inttype = 1; 00211 else if (typ == "TimeslotRecord") 00212 inttype = 2; 00213 else if (typ == "ChannelRecord") 00214 inttype = 3; 00215 else if (typ == "AllRecord") 00216 inttype = 4; 00217 else if (typ == "WeekslotRecord") 00218 inttype = 5; 00219 else if (typ == "FindOneRecord") 00220 inttype = 6; 00221 else if (typ == "OverrideRecord") 00222 inttype = 7; 00223 00224 LoadImage(inttype, img); 00225 } 00226 else if (element.tagName() == "arrow") 00227 { 00228 QString dir = element.attribute("direction"); 00229 QString image = element.attribute("image"); 00230 00231 if (dir == "left") 00232 SetArrow(0, image); 00233 else if (dir == "right") 00234 SetArrow(1, image); 00235 else if (dir == "up") 00236 SetArrow(2, image); 00237 else if (dir == "down") 00238 SetArrow(3, image); 00239 } 00240 else 00241 { 00242 return MythUIType::ParseElement(filename, element, showWarnings); 00243 } 00244 00245 return true; 00246 } 00247 00248 void MythUIGuideGrid::CopyFrom(MythUIType *base) 00249 { 00250 MythUIGuideGrid *gg = dynamic_cast<MythUIGuideGrid *>(base); 00251 00252 if (!gg) 00253 { 00254 LOG(VB_GENERAL, LOG_ERR, LOC + "bad parsing"); 00255 return; 00256 } 00257 00258 m_channelCount = gg->m_channelCount; 00259 m_timeCount = gg->m_timeCount; 00260 m_verticalLayout = gg->m_verticalLayout; 00261 m_categoryAlpha = gg->m_categoryAlpha; 00262 m_textOffset = gg->m_textOffset; 00263 m_justification = gg->m_justification; 00264 m_multilineText = gg->m_multilineText; 00265 *m_font = *gg->m_font; 00266 m_solidColor = gg->m_solidColor; 00267 00268 m_selType = gg->m_selType; 00269 m_drawSelLine = gg->m_drawSelLine; 00270 m_drawSelFill = gg->m_drawSelFill; 00271 00272 m_recordingColor = gg->m_recordingColor; 00273 m_conflictingColor = gg->m_conflictingColor; 00274 00275 m_fillType = gg->m_fillType; 00276 m_cutdown = gg->m_cutdown; 00277 m_drawCategoryColors = gg->m_drawCategoryColors; 00278 m_drawCategoryText = gg->m_drawCategoryText; 00279 00280 MythUIType::CopyFrom(base); 00281 } 00282 00283 void MythUIGuideGrid::CreateCopy(MythUIType *parent) 00284 { 00285 MythUIGuideGrid *gg = new MythUIGuideGrid(parent, objectName()); 00286 gg->CopyFrom(this); 00287 } 00288 00289 QColor MythUIGuideGrid::calcColor(const QColor &color, int alphaMod) 00290 { 00291 QColor newColor(color); 00292 newColor.setAlpha((int)(color.alpha() *(alphaMod / 255.0))); 00293 return newColor; 00294 } 00295 00296 void MythUIGuideGrid::DrawSelf(MythPainter *p, int xoffset, int yoffset, 00297 int alphaMod, QRect clipRect) 00298 { 00299 for (int i = 0; i < m_rowCount; i++) 00300 { 00301 QList<UIGTCon *>::iterator it = allData[i].begin(); 00302 00303 for (; it != allData[i].end(); ++it) 00304 { 00305 UIGTCon *data = *it; 00306 00307 if (data->recStat == 0) 00308 drawBackground(p, data, alphaMod); 00309 else if (data->recStat == 1) 00310 drawBox(p, data, m_recordingColor, alphaMod); 00311 else 00312 drawBox(p, data, m_conflictingColor, alphaMod); 00313 } 00314 } 00315 00316 drawCurrent(p, &selectedItem, alphaMod); 00317 00318 for (int i = 0; i < m_rowCount; i++) 00319 { 00320 QList<UIGTCon *>::iterator it = allData[i].begin(); 00321 00322 for (; it != allData[i].end(); ++it) 00323 { 00324 UIGTCon *data = *it; 00325 drawText(p, data, alphaMod); 00326 00327 if (data->recType != 0 || data->arrow != 0) 00328 drawRecType(p, data, alphaMod); 00329 } 00330 } 00331 } 00332 00333 void MythUIGuideGrid::drawCurrent(MythPainter *p, UIGTCon *data, int alphaMod) 00334 { 00335 int breakin = 2; 00336 QRect area = data->drawArea; 00337 area.translate(m_Area.x(), m_Area.y()); 00338 area.adjust(breakin, breakin, -breakin, -breakin); 00339 int status = data->recStat; 00340 00341 if (m_selType == "roundbox") 00342 { 00343 QPen pen = m_drawSelLine; 00344 00345 if (status == 1) 00346 pen.setColor(m_recordingColor); 00347 else if (status == 2) 00348 pen.setColor(m_conflictingColor); 00349 00350 p->DrawRoundRect(area, 10, m_drawSelFill, pen, alphaMod); 00351 } 00352 else if (m_selType == "highlight") 00353 { 00354 QBrush brush = m_drawSelFill; 00355 QPen pen = m_drawSelLine; 00356 00357 if (m_drawCategoryColors && data->categoryColor.isValid()) 00358 brush.setColor(calcColor(data->categoryColor, m_categoryAlpha)); 00359 else 00360 brush.setColor(calcColor(m_solidColor, m_categoryAlpha)); 00361 00362 if (status == 1) 00363 pen.setColor(m_recordingColor); 00364 else if (status == 2) 00365 pen.setColor(m_conflictingColor); 00366 00367 brush.setColor(brush.color().lighter()); 00368 p->DrawRect(area, brush, pen, alphaMod); 00369 } 00370 else 00371 { 00372 // default to "box" selection type 00373 QPen pen = m_drawSelLine; 00374 00375 if (status == 1) 00376 pen.setColor(m_recordingColor); 00377 else if (status == 2) 00378 pen.setColor(m_conflictingColor); 00379 00380 p->DrawRect(area, m_drawSelFill, pen, alphaMod); 00381 } 00382 } 00383 00384 void MythUIGuideGrid::drawRecType(MythPainter *p, UIGTCon *data, int alphaMod) 00385 { 00386 int breakin = 1; 00387 QRect area = data->drawArea; 00388 area.translate(m_Area.x(), m_Area.y()); 00389 area.adjust(breakin, breakin, -breakin, -breakin); 00390 00391 // draw arrows 00392 if (data->arrow != 0) 00393 { 00394 if (data->arrow == 1 || data->arrow == 3) 00395 { 00396 if (m_verticalLayout) 00397 { 00398 if (m_arrowImages[2]) 00399 p->DrawImage(area.left() + (area.width() / 2) - (m_arrowImages[2]->width() / 2), 00400 area.top() , m_arrowImages[2], alphaMod); 00401 } 00402 else 00403 { 00404 if (m_arrowImages[0]) 00405 p->DrawImage(area.left(), area.top() + (area.height() / 2) - 00406 (m_arrowImages[0]->height() / 2), m_arrowImages[0], alphaMod); 00407 } 00408 } 00409 00410 if (data->arrow == 2 || data->arrow == 3) 00411 { 00412 if (m_verticalLayout) 00413 { 00414 if (m_arrowImages[3]) 00415 p->DrawImage(area.left() + (area.width() / 2) - (m_arrowImages[3]->width() / 2), 00416 area.top() + area.height() - m_arrowImages[3]->height(), m_arrowImages[3], alphaMod); 00417 } 00418 else 00419 { 00420 if (m_arrowImages[1]) 00421 p->DrawImage(area.right() - m_arrowImages[1]->width(), 00422 area.top() + (area.height() / 2) - 00423 (m_arrowImages[1]->height() / 2), m_arrowImages[1], alphaMod); 00424 } 00425 } 00426 } 00427 00428 // draw recording status 00429 if (data->recType != 0 && m_recImages[data->recType]) 00430 { 00431 p->DrawImage(area.right() - m_recImages[data->recType]->width(), 00432 area.bottom() - m_recImages[data->recType]->height(), 00433 m_recImages[data->recType], alphaMod); 00434 } 00435 } 00436 00437 void MythUIGuideGrid::drawBox(MythPainter *p, UIGTCon *data, const QColor &color, int alphaMod) 00438 { 00439 int breakin = 1; 00440 QRect area = data->drawArea; 00441 area.translate(m_Area.x(), m_Area.y()); 00442 area.adjust(breakin, breakin, -breakin, -breakin); 00443 00444 static const QPen nopen(Qt::NoPen); 00445 p->DrawRect(area, QBrush(calcColor(color, m_categoryAlpha)), nopen, alphaMod); 00446 } 00447 00448 void MythUIGuideGrid::drawBackground(MythPainter *p, UIGTCon *data, int alphaMod) 00449 { 00450 QColor overColor; 00451 QRect overArea; 00452 00453 int breakin = 1; 00454 QRect area = data->drawArea; 00455 area.translate(m_Area.x(), m_Area.y()); 00456 QColor fillColor; 00457 00458 if (m_drawCategoryColors && data->categoryColor.isValid()) 00459 fillColor = calcColor(data->categoryColor, m_categoryAlpha); 00460 else 00461 fillColor = calcColor(m_solidColor, m_categoryAlpha); 00462 00463 if (m_verticalLayout) 00464 { 00465 if (m_progPastCol && area.top() < m_progPastCol) 00466 { 00467 if (area.bottom() < m_progPastCol) 00468 { 00469 fillColor = fillColor.dark(); 00470 area.adjust(breakin, breakin, -breakin, -breakin); 00471 } 00472 else 00473 { 00474 overColor = fillColor.dark(); 00475 int first = m_progPastCol - area.top(); 00476 int second = area.height() - first; 00477 overArea = area; 00478 overArea.setHeight(first); 00479 area.translate(0, first); 00480 area.setHeight(second); 00481 00482 area.adjust(0, -breakin, -breakin, -breakin); 00483 overArea.adjust(0, breakin, -breakin, -breakin); 00484 } 00485 } 00486 else 00487 area.adjust(breakin, breakin, -breakin, -breakin); 00488 } 00489 else 00490 { 00491 if (m_progPastCol && area.left() < m_progPastCol) 00492 { 00493 if (area.right() < m_progPastCol) 00494 { 00495 fillColor = fillColor.dark(); 00496 area.adjust(breakin, breakin, -breakin, -breakin); 00497 } 00498 else 00499 { 00500 overColor = fillColor.dark(); 00501 int first = m_progPastCol - area.left(); 00502 int second = area.width() - first; 00503 overArea = area; 00504 overArea.setWidth(first); 00505 area.translate(first, 0); 00506 area.setWidth(second); 00507 00508 area.adjust(0, breakin, -breakin, -breakin); 00509 overArea.adjust(breakin, breakin, 0, -breakin); 00510 } 00511 } 00512 else 00513 area.adjust(breakin, breakin, -breakin, -breakin); 00514 } 00515 00516 if (area.width() <= 1) 00517 area.setWidth(2); 00518 00519 if (area.height() <= 1) 00520 area.setHeight(2); 00521 00522 static const QPen nopen(Qt::NoPen); 00523 p->DrawRect(area, QBrush(fillColor), nopen, alphaMod); 00524 00525 if (overArea.width() > 0) 00526 p->DrawRect(overArea, QBrush(overColor), nopen, alphaMod); 00527 } 00528 00529 void MythUIGuideGrid::drawText(MythPainter *p, UIGTCon *data, int alphaMod) 00530 { 00531 QString msg = data->title; 00532 00533 if (m_drawCategoryText && !data->category.isEmpty()) 00534 msg += QString(" (%1)").arg(data->category); 00535 00536 QRect area = data->drawArea; 00537 area.translate(m_Area.x(), m_Area.y()); 00538 area.adjust(m_textOffset.x(), m_textOffset.y(), 00539 -m_textOffset.x(), -m_textOffset.y()); 00540 00541 if (m_verticalLayout) 00542 { 00543 if ((data->arrow == 1 || data->arrow == 3) && m_arrowImages[2]) 00544 area.setTop(area.top() + m_arrowImages[2]->height()); 00545 00546 if ((data->arrow == 2 || data->arrow == 3) && m_arrowImages[3]) 00547 area.setBottom(area.bottom() - m_arrowImages[3]->height()); 00548 } 00549 else 00550 { 00551 if ((data->arrow == 1 || data->arrow == 3) && m_arrowImages[0]) 00552 area.setLeft(area.left() + m_arrowImages[0]->width()); 00553 00554 if ((data->arrow == 2 || data->arrow == 3) && m_arrowImages[1]) 00555 area.setRight(area.right() - m_arrowImages[1]->width()); 00556 } 00557 00558 if (area.width() <= 0 || area.height() <= 0) 00559 return; 00560 00561 p->DrawText(area, msg, m_justification, *m_font, alphaMod, area); 00562 } 00563 00564 void MythUIGuideGrid::SetProgramInfo(int row, int col, const QRect &area, 00565 const QString &title, const QString &genre, 00566 int arrow, int recType, int recStat, 00567 bool selected) 00568 { 00569 (void)col; 00570 UIGTCon *data = new UIGTCon(area, title, genre, arrow, recType, recStat); 00571 allData[row].append(data); 00572 00573 if (m_drawCategoryColors) 00574 { 00575 data->categoryColor = categoryColors[data->category.toLower()]; 00576 00577 if (!data->categoryColor.isValid()) 00578 data->categoryColor = categoryColors["none"]; 00579 } 00580 00581 if (selected) 00582 selectedItem = *data; 00583 } 00584 00585 bool MythUIGuideGrid::parseDefaultCategoryColors(QMap<QString, QString> &catColors) 00586 { 00587 QFile f; 00588 QStringList searchpath = GetMythUI()->GetThemeSearchPath(); 00589 00590 for (QStringList::const_iterator ii = searchpath.begin(); 00591 ii != searchpath.end(); ++ii) 00592 { 00593 f.setFileName(*ii + "categories.xml"); 00594 00595 if (f.open(QIODevice::ReadOnly)) 00596 break; 00597 } 00598 00599 if (f.handle() == -1) 00600 { 00601 LOG(VB_GENERAL, LOG_ERR, LOC + QString("Unable to open '%1'") 00602 .arg(f.fileName())); 00603 return false; 00604 } 00605 00606 QDomDocument doc; 00607 QString errorMsg; 00608 int errorLine = 0; 00609 int errorColumn = 0; 00610 00611 if (!doc.setContent(&f, false, &errorMsg, &errorLine, &errorColumn)) 00612 { 00613 LOG(VB_GENERAL, LOG_ERR, LOC + 00614 QString("Parsing colors: %1 at line: %2 column: %3") 00615 .arg(f.fileName()).arg(errorLine).arg(errorColumn) + 00616 QString("\n\t\t\t%1").arg(errorMsg)); 00617 f.close(); 00618 return false; 00619 } 00620 00621 f.close(); 00622 00623 QDomElement element = doc.documentElement(); 00624 00625 for (QDomNode child = element.firstChild(); !child.isNull(); 00626 child = child.nextSibling()) 00627 { 00628 QDomElement info = child.toElement(); 00629 00630 if (!info.isNull() && info.tagName() == "catcolor") 00631 { 00632 QString cat = info.attribute("category"); 00633 QString col = info.attribute("color"); 00634 00635 catColors[cat.toLower()] = col; 00636 } 00637 } 00638 00639 return true; 00640 } 00641 00642 void MythUIGuideGrid::SetCategoryColors(const QMap<QString, QString> &catC) 00643 { 00644 for (QMap<QString, QString>::const_iterator it = catC.begin(); 00645 it != catC.end(); ++it) 00646 { 00647 categoryColors[it.key()] = createColor(*it); 00648 } 00649 } 00650 00651 void MythUIGuideGrid::LoadImage(int recType, const QString &file) 00652 { 00653 QString themeDir = GetMythUI()->GetThemeDir(); 00654 QString filename = themeDir + file; 00655 00656 QPixmap *pix = GetMythUI()->LoadScalePixmap(filename); 00657 00658 if (pix) 00659 { 00660 m_recImages[recType] = GetPainter()->GetFormatImage(); 00661 m_recImages[recType]->Assign(*pix); 00662 delete pix; 00663 } 00664 } 00665 00666 void MythUIGuideGrid::SetArrow(int direction, const QString &file) 00667 { 00668 QString themeDir = GetMythUI()->GetThemeDir(); 00669 QString filename = themeDir + file; 00670 00671 QPixmap *pix = GetMythUI()->LoadScalePixmap(filename); 00672 00673 if (pix) 00674 { 00675 m_arrowImages[direction] = GetPainter()->GetFormatImage(); 00676 m_arrowImages[direction]->Assign(*pix); 00677 delete pix; 00678 } 00679 } 00680 00681 void MythUIGuideGrid::ResetData(void) 00682 { 00683 for (int i = 0; i < m_rowCount; i++) 00684 ResetRow(i); 00685 } 00686 00687 void MythUIGuideGrid::ResetRow(int row) 00688 { 00689 while (!allData[row].empty()) 00690 { 00691 delete allData[row].back(); 00692 allData[row].pop_back(); 00693 } 00694 } 00695 00696 void MythUIGuideGrid::SetProgPast(int ppast) 00697 { 00698 if (m_verticalLayout) 00699 m_progPastCol = m_Area.y() + (m_Area.height() * ppast / 100); 00700 else 00701 m_progPastCol = m_Area.x() + (m_Area.width() * ppast / 100); 00702 00703 SetRedraw(); 00704 } 00705 00706 void MythUIGuideGrid::SetMultiLine(bool multiline) 00707 { 00708 m_multilineText = multiline; 00709 00710 if (m_multilineText) 00711 m_justification |= Qt::TextWordWrap; 00712 else 00713 m_justification &= ~Qt::TextWordWrap; 00714 }
1.7.6.1