Ticket #12: mythui_themedmenu.diff
File mythui_themedmenu.diff, 83.8 KB (added by , 16 years ago) |
---|
-
mythtv/libs/libmythui/myththemedmenu.cpp
11 11 12 12 #include "myththemedmenu.h" 13 13 #include "mythmainwindow.h" 14 #include "mythfontproperties.h"15 #include "mythimage.h"16 14 #include "mythdialogbox.h" 17 15 18 16 #include "mythgesture.h" … … 28 26 #include "mythdirs.h" 29 27 #include "lcddevice.h" 30 28 31 struct TextAttributes 29 MythThemedMenuState::MythThemedMenuState(MythScreenStack *parent, 30 const QString &name) 31 : MythScreenType(parent, name) 32 32 { 33 QRect textRect; 34 MythFontProperties font; 35 int textflags; 36 }; 33 m_loaded = false; 37 34 38 struct ButtonIcon 39 { 40 QString name; 41 MythImage *icon; 42 MythImage *activeicon; 43 MythImage *watermark; 44 QPoint offset; 45 }; 35 m_titleState = m_watermarkState = NULL; 36 m_buttonList = NULL; 46 37 47 class ThemedButton : public MythUIType 48 { 49 public: 50 ThemedButton(MythUIType *parent, const QString &name) 51 : MythUIType(parent, name), 52 background(NULL), icon(NULL), text(NULL), 53 row(0), col(0) 54 { 55 } 38 m_callback = NULL; 39 m_callbackdata = NULL; 56 40 57 void SetActive(bool active) 58 { 59 MythUIStateType::StateType state = MythUIStateType::None; 60 if (active) 61 state = MythUIStateType::Full; 62 63 if (background) 64 background->DisplayState(state); 65 if (icon) 66 icon->DisplayState(state); 67 if (text) 68 text->DisplayState(state); 69 } 70 71 MythUIStateType *background; 72 MythUIStateType *icon; 73 MythUIStateType *text; 74 75 QStringList action; 76 QString message; 77 QString type; 78 79 int row; 80 int col; 81 }; 82 83 struct MenuRow 84 { 85 int numitems; 86 bool visible; 87 vector<ThemedButton *> buttons; 88 }; 89 90 class MythThemedMenuPrivate; 91 92 /** \class MyththemedMenuState 93 * \brief Private class that controls the settings of buttons, logos, 94 * backgrounds, texts, and more, for the MythThemedMenu class. 95 */ 96 class MythThemedMenuState: public XMLParseBase 97 { 98 public: 99 MythThemedMenuState(); 100 ~MythThemedMenuState(); 101 102 bool parseSettings(const QString &dir, const QString &menuname); 103 104 void parseBackground(const QString &dir, QDomElement &element); 105 void parseLogo(const QString &dir, QDomElement &element); 106 void parseArrow(const QString &dir, QDomElement &element, bool up); 107 void parseTitle(const QString &dir, QDomElement &element); 108 void parseButtonDefinition(const QString &dir, QDomElement &element); 109 void parseButton(const QString &dir, QDomElement &element); 110 111 void parseText(TextAttributes &attributes, QDomElement &element); 112 void parseOutline(TextAttributes &attributes, QDomElement &element); 113 void parseShadow(TextAttributes &attributes, QDomElement &element); 114 115 void Reset(void); 116 void setDefaults(void); 117 118 ButtonIcon *getButtonIcon(const QString &type); 119 120 QRect buttonArea; 121 122 QRect logoRect; 123 MythImage *logo; 124 125 MythImage *buttonnormal; 126 MythImage *buttonactive; 127 128 QMap<QString, ButtonIcon> allButtonIcons; 129 130 TextAttributes normalAttributes; 131 TextAttributes activeAttributes; 132 133 void (*callback)(void *, QString &); 134 void *callbackdata; 135 136 bool killable; 137 138 bool balancerows; 139 bool spreadbuttons; 140 bool buttoncenter; 141 142 QMap<QString, MythImage *> titleIcons; 143 QMap<QString, MythImage *> m_loadedImages; 144 QString titleText; 145 QPoint titlePos; 146 147 MythImage *buttonBackground; 148 149 MythImage *uparrow; 150 QRect uparrowRect; 151 MythImage *downarrow; 152 QRect downarrowRect; 153 154 QPoint watermarkPos; 155 QRect watermarkRect; 156 157 bool allowreorder; 158 int maxColumns; 159 160 int visiblerowlimit; 161 162 bool loaded; 163 164 QString themeDir; 165 166 /* FIXME, remove */ 167 static bool parseFonts; 168 }; 169 170 bool MythThemedMenuState::parseFonts = true; 171 172 class MythThemedMenuPrivate: public XMLParseBase 173 { 174 public: 175 MythThemedMenuPrivate(MythThemedMenu *lparent, const QString &cdir, 176 MythThemedMenuState *lstate); 177 ~MythThemedMenuPrivate(); 178 179 bool keyPressHandler(QKeyEvent *e); 180 bool keyHandler(QStringList &actions, bool fullexit); 181 182 bool ReloadTheme(void); 183 184 bool parseMenu(const QString &menuname); 185 186 void parseThemeButton(QDomElement &element); 187 188 void addButton(const QString &type, const QString &text, 189 const QString &alttext, const QStringList &action); 190 bool layoutButtons(void); 191 void positionButtons(bool resetpos); 192 bool makeRowVisible(int newrow, int oldrow); 193 194 bool handleAction(const QString &action); 195 bool findDepends(const QString &fileList); 196 QString findMenuFile(const QString &menuname); 197 198 void checkScrollArrows(void); 199 200 bool checkPinCode(const QString ×tamp_setting, 201 const QString &password_setting, 202 const QString &text); 203 204 void SetupBackground(); 205 void SetupUITypes(); 206 207 bool gestureEvent(MythUIType *origtype, MythGestureEvent *ge); 208 209 void updateLCD(void); 210 211 MythThemedMenu *parent; 212 213 MythThemedMenuState *m_state; 214 bool allocedstate; 215 216 vector<ThemedButton *> buttonList; 217 ThemedButton *activebutton; 218 int currentrow; 219 int currentcolumn; 220 221 vector<MenuRow> buttonRows; 222 223 QString selection; 224 bool foundtheme; 225 226 int exitModifier; 227 228 bool ignorekeys; 229 230 int maxrows; 231 int visiblerows; 232 int columns; 233 234 bool wantpop; 235 236 QString titleText; 237 QString menumode; 238 239 MythUIStateType *watermark; 240 MythUIImage *uparrow; 241 MythUIImage *downarrow; 242 }; 243 244 ///////////////////////////////////////////////////////////////////////////// 245 246 MythThemedMenuState::MythThemedMenuState() : 247 logo(NULL), buttonnormal(NULL), 248 buttonactive(NULL), callback(NULL), 249 callbackdata(NULL), killable(false), 250 balancerows(true), spreadbuttons(false), 251 buttoncenter(false), buttonBackground(NULL), 252 uparrow(NULL), downarrow(NULL), 253 allowreorder(true), maxColumns(20), 254 visiblerowlimit(6), loaded(false) 255 { 41 m_killable = false; 256 42 } 257 43 258 44 MythThemedMenuState::~MythThemedMenuState() 259 45 { 260 Reset();261 }262 263 void MythThemedMenuState::Reset(void)264 {265 if (logo)266 logo->DownRef();267 if (buttonnormal)268 buttonnormal->DownRef();269 if (buttonactive)270 buttonactive->DownRef();271 if (uparrow)272 uparrow->DownRef();273 if (downarrow)274 downarrow->DownRef();275 if (buttonBackground)276 buttonBackground->DownRef();277 278 logo = NULL;279 buttonnormal = NULL;280 buttonactive = NULL;281 uparrow = NULL;282 downarrow = NULL;283 buttonBackground = NULL;284 285 46 QMap<QString, ButtonIcon>::Iterator it; 286 for (it = allButtonIcons.begin(); it !=allButtonIcons.end(); ++it)47 for (it = m_allButtonIcons.begin(); it != m_allButtonIcons.end(); ++it) 287 48 { 288 49 if (it.value().icon) 289 50 it.value().icon->DownRef(); 290 51 if (it.value().activeicon) 291 52 it.value().activeicon->DownRef(); 292 if (it.value().watermark)293 it.value().watermark->DownRef();294 53 } 295 allButtonIcons.clear();54 m_allButtonIcons.clear(); 296 55 297 56 QMap<QString, MythImage *>::Iterator jt; 298 for (jt = titleIcons.begin(); jt !=titleIcons.end(); ++jt)57 for (jt = m_titleIcons.begin(); jt != m_titleIcons.end(); ++jt) 299 58 { 300 59 jt.value()->DownRef(); 301 60 } 302 titleIcons.clear(); 303 m_loadedImages.clear(); 304 305 normalAttributes = activeAttributes = TextAttributes(); 306 setDefaults(); 307 308 loaded = false; 61 m_titleIcons.clear(); 309 62 } 310 63 311 ButtonIcon *MythThemedMenuState::getButtonIcon(const QString &type)64 bool MythThemedMenuState::Create(void) 312 65 { 313 if (allButtonIcons.find(type) != allButtonIcons.end()) 314 return &(allButtonIcons[type]); 315 return NULL; 316 } 66 bool foundtheme = false; 317 67 318 /** \brief Parse through the element's tags and set the button's 319 * area, spread, center, rows, columns and visible lower limit. 320 * \param dir the directory path of background 321 * \param element QDomElement with information about the background 322 */ 323 void MythThemedMenuState::parseBackground( 324 const QString &dir, QDomElement &element) 325 { 326 QString path; 68 foundtheme = LoadWindowFromXML("menu-ui.xml", "mainmenu", this); 327 69 328 bool hasarea = false; 70 if (!foundtheme) 71 return false; 329 72 330 buttoncenter = true; 331 spreadbuttons = true; 332 maxColumns = 20; // Arbitrary number 333 visiblerowlimit = 6; // the old default 73 m_titleState = dynamic_cast<MythUIStateType *> (GetChild("titles")); 74 m_watermarkState = dynamic_cast<MythUIStateType *> (GetChild("watermarks")); 75 m_buttonList = dynamic_cast<MythUIButtonList *> (GetChild("menu")); 334 76 335 for (QDomNode child = element.firstChild(); !child.isNull(); 336 child = child.nextSibling()) 77 if (!m_buttonList) 337 78 { 338 QDomElement info = child.toElement(); 339 if (!info.isNull()) 340 { 341 if (info.tagName() == "buttonarea") 342 { 343 buttonArea = parseRect(info); 344 hasarea = true; 345 346 if (info.hasAttribute("background")) 347 { 348 QString bPath = dir + info.attribute("background"); 349 QImage *image = GetMythUI()->LoadScaleImage(bPath); 350 buttonBackground = MythImage::FromQImage(&image); 351 } 352 } 353 else if (info.tagName() == "buttonspread") 354 { 355 QString val = getFirstText(info); 356 if (val == "no") 357 spreadbuttons = false; 358 } 359 else if (info.tagName() == "buttoncenter") 360 { 361 QString val = getFirstText(info); 362 if (val == "no") 363 buttoncenter = false; 364 } 365 else if (info.tagName() == "balancerows") 366 { 367 QString val = getFirstText(info); 368 if (val == "no") 369 balancerows = false; 370 } 371 else if (info.tagName() == "columns") 372 { 373 QString val = getFirstText(info); 374 maxColumns = val.toInt(); 375 } 376 else if (info.tagName() == "visiblerowlimit") 377 { 378 visiblerowlimit = getFirstText(info).toInt(); 379 } 380 else 381 { 382 VERBOSE(VB_GENERAL, QString("MythThemedMenuPrivate: Unknown tag %1 in " 383 "background").arg(info.tagName())); 384 } 385 } 79 VERBOSE(VB_IMPORTANT, "Missing 'menu' buttonlist."); 80 return false; 386 81 } 387 82 388 if (!hasarea) 389 { 390 VERBOSE(VB_IMPORTANT, "MythThemedMenuPrivate: Missing button area in background"); 391 return; 392 } 393 } 83 m_buttonList->SetActive(true); 394 84 395 /** \brief Parse through the element's tags and set the shadow's color, 396 * offset, and alpha. 397 * \param attributes text attributes whose font shadow will be set 398 * \param element DOM dealing with shadow 399 */ 400 void MythThemedMenuState::parseShadow(TextAttributes &attributes, 401 QDomElement &element) 402 { 403 QPoint offset; 404 QColor color; 405 int alpha = 255; 85 m_loaded = true; 406 86 407 bool hascolor = false; 408 bool hasoffset = false; 409 bool hasalpha = false; 410 411 for (QDomNode child = element.firstChild(); !child.isNull(); 412 child = child.nextSibling()) 413 { 414 QDomElement info = child.toElement(); 415 if (!info.isNull()) 416 { 417 if (info.tagName() == "color") 418 { 419 // workaround alpha bug with named colors 420 QColor temp(getFirstText(info)); 421 color = QColor(temp.name()); 422 hascolor = true; 423 } 424 else if (info.tagName() == "offset") 425 { 426 offset = parsePoint(info); 427 hasoffset = true; 428 } 429 else if (info.tagName() == "alpha") 430 { 431 alpha = getFirstText(info).toInt(); 432 hasalpha = true; 433 } 434 else 435 { 436 VERBOSE(VB_GENERAL, QString("MythThemedMenuPrivate: Unknown tag %1 in " 437 "text/shadow").arg(info.tagName())); 438 } 439 } 440 } 441 442 if (!hascolor) 443 { 444 VERBOSE(VB_IMPORTANT, "MythThemedMenuPrivate: Missing color tag in shadow"); 445 return; 446 } 447 448 if (!hasalpha) 449 { 450 VERBOSE(VB_IMPORTANT, "MythThemedMenuPrivate: Missing alpha tag in shadow"); 451 return; 452 } 453 454 if (!hasoffset) 455 { 456 VERBOSE(VB_IMPORTANT, "MythThemedMenuPrivate: Missing offset tag in shadow"); 457 return; 458 } 459 460 attributes.font.SetShadow(true, offset, color, alpha); 87 return foundtheme; 461 88 } 462 89 463 /** \brief Parse through the element's tags and set the outline's 464 * color and size. 465 * 466 * \param attributes text attributes whose font outline will be set 467 * \param element DOM element dealing with outline 468 */ 469 void MythThemedMenuState::parseOutline(TextAttributes &attributes, 470 QDomElement &element) 90 void MythThemedMenu::setButtonActive(MythUIButtonListItem* item) 471 91 { 472 QColor color; 473 int size = 0, alpha = 255; 474 475 bool hascolor = false; 476 bool hassize = false; 477 478 for (QDomNode child = element.firstChild(); !child.isNull(); 479 child = child.nextSibling()) 92 ThemedButton *button = item->GetData().value<ThemedButton *>(); 93 if (m_watermarkState && button) 480 94 { 481 QDomElement info = child.toElement(); 482 if (!info.isNull()) 483 { 484 if (info.tagName() == "color") 485 { 486 // workaround alpha bug with named colors 487 QColor temp(getFirstText(info)); 488 color = QColor(temp.name()); 489 hascolor = true; 490 } 491 else if (info.tagName() == "size") 492 { 493 int lsize = getFirstText(info).toInt(); 494 size = GetMythMainWindow()->NormY(lsize); 495 hassize = true; 496 } 497 else 498 { 499 VERBOSE(VB_GENERAL, QString("MythThemedMenuPrivate: Unknown tag %1 in " 500 "text/shadow").arg(info.tagName())); 501 } 502 } 95 if (m_watermarkState->DisplayState(button->type)) 96 return; 503 97 } 504 505 if (!hassize) 506 { 507 VERBOSE(VB_IMPORTANT, "MythThemedMenuPrivate: Missing size in outline"); 508 return; 509 } 510 511 if (!hascolor) 512 { 513 VERBOSE(VB_IMPORTANT, "MythThemedMenuPrivate: Missing color in outline"); 514 return; 515 } 516 517 attributes.font.SetOutline(true, color, size, alpha); 98 m_watermarkState->DisplayState("DEFAULT"); 518 99 } 519 100 520 /** \brief Parse through the element's tags and set the text's area, 521 * fontsize, fontname, positioning, and decorations. 522 * 523 * \param attributes text attributes whose font face will be set 524 * \param element DOM element dealing with text 525 */ 526 void MythThemedMenuState::parseText(TextAttributes &attributes, 527 QDomElement &element) 101 ButtonIcon *MythThemedMenuState::getButtonIcon(const QString &type) 528 102 { 529 bool hasarea = false; 530 531 int weight = QFont::Normal; 532 int fontsize = 14; 533 QString fontname = "Arial"; 534 bool italic = false; 535 536 attributes.textflags = Qt::TextWordWrap; 537 for (QDomNode child = element.firstChild(); !child.isNull(); 538 child = child.nextSibling()) 539 { 540 QDomElement info = child.toElement(); 541 if (!info.isNull()) 542 { 543 if (info.tagName() == "area") 544 { 545 hasarea = true; 546 attributes.textRect = parseRect(info); 547 attributes.textRect = QRect(attributes.textRect.x(), 548 attributes.textRect.y(), 549 buttonnormal->width() - 550 attributes.textRect.width() - 551 attributes.textRect.x(), 552 buttonnormal->height() - 553 attributes.textRect.height() - 554 attributes.textRect.y()); 555 } 556 else if (info.tagName() == "fontsize") 557 { 558 fontsize = getFirstText(info).toInt(); 559 } 560 else if (info.tagName() == "fontname") 561 { 562 fontname = getFirstText(info); 563 } 564 else if (info.tagName() == "bold") 565 { 566 if (getFirstText(info) == "yes") 567 weight = QFont::Bold; 568 } 569 else if (info.tagName() == "italics") 570 { 571 if (getFirstText(info) == "yes") 572 italic = true; 573 } 574 else if (info.tagName() == "color") 575 { 576 // workaround alpha bug with named colors 577 QColor temp(getFirstText(info)); 578 attributes.font.SetColor(QColor(temp.name())); 579 } 580 else if (info.tagName() == "centered") 581 { 582 if (getFirstText(info) == "yes") 583 { 584 if (GetMythUI()->GetLanguage() == "ja") 585 { 586 attributes.textflags = Qt::AlignVCenter | 587 Qt::AlignHCenter | 588 Qt::TextWordWrap; 589 } 590 else 591 { 592 attributes.textflags = Qt::AlignTop | 593 Qt::AlignHCenter | 594 Qt::TextWordWrap; 595 } 596 } 597 } 598 // halign has three possible values: center, left, and right. // 599 else if (info.tagName() == "halign") 600 { 601 if (getFirstText(info) == "center") 602 { 603 // Apparently Japanese is drawn along a _center_ line // 604 if (GetMythUI()->GetLanguage() == "ja") 605 { 606 attributes.textflags = 607 (attributes.textflags & ~Qt::AlignHorizontal_Mask) | 608 Qt::AlignCenter; 609 } 610 else 611 { 612 attributes.textflags = 613 (attributes.textflags & ~Qt::AlignHorizontal_Mask) | 614 Qt::AlignHCenter; 615 } 616 } 617 else if (getFirstText(info) == "left") 618 { 619 attributes.textflags = 620 (attributes.textflags & ~Qt::AlignHorizontal_Mask) | 621 Qt::AlignLeft | Qt::TextWordWrap; 622 } 623 else if (getFirstText(info) == "right") 624 { 625 attributes.textflags = 626 (attributes.textflags & ~Qt::AlignHorizontal_Mask) | 627 Qt::AlignRight | Qt::TextWordWrap; 628 } 629 else 630 { 631 VERBOSE(VB_GENERAL, 632 QString("MythThemedMenuPrivate: Unknown value %1 " 633 "for halign").arg(getFirstText(info))); 634 } 635 } 636 // valign has three possible values: center, top, and bottom. // 637 else if (info.tagName() == "valign") 638 { 639 if (getFirstText(info) == "center") 640 { 641 attributes.textflags = 642 (attributes.textflags & ~Qt::AlignVertical_Mask) | 643 Qt::AlignVCenter; 644 } 645 else if (getFirstText(info) == "top") 646 { 647 attributes.textflags = 648 (attributes.textflags & ~Qt::AlignVertical_Mask) | 649 Qt::AlignTop; 650 } 651 else if (getFirstText(info) == "bottom") 652 { 653 attributes.textflags = 654 (attributes.textflags & ~Qt::AlignVertical_Mask) | 655 Qt::AlignBottom; 656 } 657 else 658 { 659 VERBOSE(VB_GENERAL, 660 QString("MythThemedMenuPrivate: Unknown value %1 " 661 "for valign").arg(getFirstText(info))); 662 } 663 } 664 else if (info.tagName() == "outline") 665 { 666 parseOutline(attributes, info); 667 } 668 else if (info.tagName() == "shadow") 669 { 670 parseShadow(attributes, info); 671 } 672 else 673 { 674 VERBOSE(VB_GENERAL, QString("MythThemedMenuPrivate: Unknown " 675 "tag %1 in text").arg(info.tagName())); 676 return; 677 } 678 } 679 } 680 681 QFont font = GetMythMainWindow()->CreateQFont( 682 fontname, fontsize, weight, italic); 683 684 attributes.font.SetFace(font); 685 686 if (!hasarea) 687 { 688 VERBOSE(VB_IMPORTANT, "MythThemedMenuPrivate: Missing 'area' " 689 "tag in 'text' element of 'genericbutton'"); 690 return; 691 } 103 if (m_allButtonIcons.find(type) != m_allButtonIcons.end()) 104 return &(m_allButtonIcons[type]); 105 return NULL; 692 106 } 693 107 694 void MythThemedMenuState::parseButtonDefinition(const QString &dir, 695 QDomElement &element) 108 void MythThemedMenuState::CopyFrom(MythUIType *base) 696 109 { 697 bool hasnormal = false; 698 bool hasactive = false; 699 bool hasactivetext = false; 700 701 QString setting; 702 703 QImage *tmp; 704 705 for (QDomNode child = element.firstChild(); !child.isNull(); 706 child = child.nextSibling()) 110 MythThemedMenuState *st = dynamic_cast<MythThemedMenuState *>(base); 111 if (!st) 707 112 { 708 QDomElement info = child.toElement(); 709 if (!info.isNull()) 710 { 711 if (info.tagName() == "normal") 712 { 713 setting = dir + getFirstText(info); 714 tmp = GetMythUI()->LoadScaleImage(setting); 715 if (tmp) 716 { 717 buttonnormal = MythImage::FromQImage(&tmp); 718 hasnormal = true; 719 } 720 } 721 else if (info.tagName() == "active") 722 { 723 setting = dir + getFirstText(info); 724 tmp = GetMythUI()->LoadScaleImage(setting); 725 if (tmp) 726 { 727 buttonactive = MythImage::FromQImage(&tmp); 728 hasactive = true; 729 } 730 } 731 else if (info.tagName() == "text") 732 { 733 if (!hasnormal) 734 { 735 VERBOSE(VB_IMPORTANT, "MythThemedMenuPrivate: The 'normal' " 736 "tag needs to come before the 'text' tag"); 737 return; 738 } 739 parseText(normalAttributes, info); 740 } 741 else if (info.tagName() == "activetext") 742 { 743 if (!hasactive) 744 { 745 VERBOSE(VB_IMPORTANT, "MythThemedMenuPrivate: The 'active' " 746 "tag needs to come before the 'activetext' tag"); 747 return; 748 } 749 parseText(activeAttributes, info); 750 hasactivetext = true; 751 } 752 else if (info.tagName() == "watermarkposition") 753 { 754 watermarkPos = parsePoint(info); 755 } 756 else 757 { 758 VERBOSE(VB_GENERAL, 759 QString("MythThemedMenuPrivate: Unknown tag %1 in " 760 "genericbutton").arg(info.tagName())); 761 } 762 } 763 } 764 765 if (!hasnormal) 766 { 767 VERBOSE(VB_IMPORTANT, "MythThemedMenuPrivate: No normal button image defined"); 113 VERBOSE(VB_IMPORTANT, "ERROR, bad parsing"); 768 114 return; 769 115 } 770 116 771 if (!hasactive) 772 { 773 VERBOSE(VB_IMPORTANT, "MythThemedMenuPrivate: No active button image defined"); 774 return; 775 } 117 m_loaded = st->m_loaded; 776 118 777 if (!hasactivetext) 778 { 779 activeAttributes = normalAttributes; 780 } 119 MythScreenType::CopyFrom(base); 781 120 782 watermarkRect = QRect(watermarkPos, QSize(0, 0)); 121 m_titleState = dynamic_cast<MythUIStateType *> (GetChild("titles")); 122 m_watermarkState = dynamic_cast<MythUIStateType *> (GetChild("watermarks")); 123 m_buttonList = dynamic_cast<MythUIButtonList *> (GetChild("menu")); 783 124 } 784 125 785 /** \brief Parse through the element's tags and set the logo's 786 * image and position. 126 //////////////////////////////////////////////////////////////////////////// 127 128 /** \brief Creates a themed menu. 787 129 * 788 * \param dir directory where logo images may be found 789 * \param element DOM element whose nodes describe the logo 130 * \param menufile file name of menu definition file 131 * \param parent the screen stack that owns this UI type 132 * \param name the name of this UI type 133 * \param state theme state associated with this menu 790 134 */ 791 void MythThemedMenuState::parseLogo(const QString &dir, QDomElement &element) 135 MythThemedMenu::MythThemedMenu(const QString &cdir, const QString &menufile, 136 MythScreenStack *parent, const QString &name, 137 bool allowreorder, MythThemedMenuState *state) 138 : MythThemedMenuState(parent, name) 792 139 { 793 bool hasimage = false; 794 bool hasposition = false; 140 m_state = state; 141 m_allocedstate = m_foundtheme = m_ignorekeys = m_wantpop = false; 142 m_exitModifier = -1; 143 m_menumode = ""; 795 144 796 QPoint logopos; 797 798 for (QDomNode child = element.firstChild(); !child.isNull(); 799 child = child.nextSibling()) 145 if (!m_state) 800 146 { 801 QDomElement info = child.toElement(); 802 if (!info.isNull()) 803 { 804 if (info.tagName() == "image") 805 { 806 QString logopath = dir + getFirstText(info); 807 QImage *tmp = GetMythUI()->LoadScaleImage(logopath); 808 if (tmp) 809 { 810 logo = MythImage::FromQImage(&tmp); 811 hasimage = true; 812 } 813 } 814 else if (info.tagName() == "position") 815 { 816 logopos = parsePoint(info); 817 hasposition = true; 818 } 819 else 820 { 821 VERBOSE(VB_GENERAL, QString("MythThemedMenuPrivate: Unknown tag %1 " 822 "in logo").arg(info.tagName())); 823 } 824 } 147 m_state = new MythThemedMenuState(parent, "themedmenustate"); 148 m_allocedstate = true; 825 149 } 826 150 827 if (!hasimage) 828 { 829 VERBOSE(VB_IMPORTANT, "MythThemedMenuPrivate: Missing image tag in logo"); 830 return; 831 } 832 833 if (!hasposition) 834 { 835 VERBOSE(VB_IMPORTANT, "MythThemedMenuPrivate: Missing position tag in logo"); 836 return; 837 } 838 839 logoRect = QRect(logopos.x(), logopos.y(), logo->width(), 840 logo->height()); 151 Init(menufile); 841 152 } 842 153 843 /** \brief Parse through the element's tags and set the title's image 844 * (and subsequent mode) and position. 154 /** \brief Loads the main UI theme, and a menu theme. 845 155 * 846 * \param dir directory where title images may be found 847 * \param element DOM element dealing with the title 848 */ 849 void MythThemedMenuState::parseTitle(const QString &dir, QDomElement &element) 850 { 851 bool hasimage = false; 852 bool hasposition = false; 853 854 for (QDomNode child = element.firstChild(); !child.isNull(); 855 child = child.nextSibling()) 856 { 857 QDomElement info = child.toElement(); 858 if (!info.isNull()) 859 { 860 if (info.tagName() == "image") 861 { 862 863 QString titlepath = dir + getFirstText(info); 864 865 QString name = info.attribute("mode", ""); 866 if (name != "") 867 { 868 MythImage *icon; 869 QImage *tmppix; 870 871 if (m_loadedImages[titlepath]) 872 { 873 icon = m_loadedImages[titlepath]; 874 icon->UpRef(); 875 } 876 else 877 { 878 tmppix = GetMythUI()->LoadScaleImage(titlepath); 879 880 if (!tmppix) 881 continue; 882 883 icon = MythImage::FromQImage(&tmppix); 884 m_loadedImages.insert(titlepath, icon); 885 } 886 887 titleIcons[name] = icon; 888 } 889 else 890 { 891 VERBOSE(VB_IMPORTANT, "MythThemedMenuPrivate: " 892 "Missing mode in titles/image"); 893 return; 894 } 895 896 hasimage = true; 897 } 898 else if (info.tagName() == "position") 899 { 900 titlePos = parsePoint(info); 901 hasposition = true; 902 } 903 else 904 { 905 VERBOSE(VB_GENERAL, QString("MythThemedMenuPrivate: Unknown tag %1 " 906 "in logo").arg(info.tagName())); 907 } 908 } 909 } 910 911 if (!hasimage) 912 { 913 VERBOSE(VB_IMPORTANT, "MythThemedMenuPrivate: Missing image tag in titles"); 914 return; 915 } 916 917 if (!hasposition) 918 { 919 VERBOSE(VB_IMPORTANT, "MythThemedMenuPrivate: Missing position tag in titles"); 920 return; 921 } 922 } 923 924 /** \brief Parse through the element's tags to set the arrows 925 * image and position. 156 * See also foundtheme(void), it will return true when called after 157 * this method if this method was successful. 926 158 * 927 * \param dir directory where arrow images may be found 928 * \param element DOM element dealing with arrow image and position 159 * See also ReloadTheme(void) which you can use to load a generic theme, 160 * if foundtheme(void) returns false after calling this. 161 * 162 * \param menufile name of menu item xml file 929 163 */ 930 void MythThemedMenuState::parseArrow(const QString &dir, QDomElement &element, 931 bool up) 164 void MythThemedMenu::Init(const QString &menufile) 932 165 { 933 QRect arrowrect; 934 QPoint arrowpos; 935 QImage *pix = NULL; 166 ReloadExitKey(); 936 167 937 bool hasimage = false; 938 bool hasposition = false; 939 940 for (QDomNode child = element.firstChild(); !child.isNull(); 941 child = child.nextSibling()) 168 if (!m_state->m_loaded) 942 169 { 943 QDomElement info = child.toElement(); 944 if (!info.isNull()) 945 { 946 if (info.tagName() == "image") 947 { 948 QString arrowpath = dir + getFirstText(info); 949 pix = GetMythUI()->LoadScaleImage(arrowpath); 950 if (pix) 951 hasimage = true; 952 } 953 else if (info.tagName() == "position") 954 { 955 arrowpos = parsePoint(info); 956 hasposition = true; 957 } 958 else 959 { 960 VERBOSE(VB_GENERAL, QString("MythThemedMenuPrivate: Unknown tag %1 " 961 "in arrow").arg(info.tagName())); 962 } 963 } 170 if (m_state->Create()) 171 m_foundtheme = true; 964 172 } 173 else 174 m_foundtheme = true; 965 175 966 if (!hasimage) 967 { 968 VERBOSE(VB_IMPORTANT, "MythThemedMenuPrivate: Missing image tag in arrow"); 176 if (!m_foundtheme) 969 177 return; 970 }971 178 972 if (!hasposition) 973 { 974 VERBOSE(VB_IMPORTANT, "MythThemedMenuPrivate: Missing position tag in arrow"); 975 return; 976 } 179 CopyFrom(m_state); 977 180 978 arrowrect = QRect(arrowpos.x(), arrowpos.y(), pix->width(), 979 pix->height()); 181 parseMenu(menufile); 980 182 981 if (up) 982 { 983 uparrow = MythImage::FromQImage(&pix); 984 uparrowRect = arrowrect; 985 } 986 else 987 { 988 downarrow = MythImage::FromQImage(&pix); 989 downarrowRect = arrowrect; 990 } 183 connect(m_buttonList, SIGNAL(itemSelected(MythUIButtonListItem*)), 184 SLOT(setButtonActive(MythUIButtonListItem*))); 185 connect(m_buttonList, SIGNAL(itemClicked(MythUIButtonListItem*)), 186 SLOT(buttonAction(MythUIButtonListItem*))); 187 188 m_buttonList->SetActive(true); 991 189 } 992 190 993 /** \brief Parse through the element's tags and set the button's 994 * definition as normal, active, text, or activetext. 995 * 996 * \param dir directory where the button images may be found 997 * \param element DOM element whose nodes define Buttons 998 */ 999 void MythThemedMenuState::parseButton(const QString &dir, QDomElement &element) 191 MythThemedMenu::~MythThemedMenu(void) 1000 192 { 1001 bool hasname = false;1002 bool hasoffset = false;1003 bool hasicon = false; 193 if (m_allocedstate) 194 delete m_state; 195 } 1004 196 1005 QString name = ""; 1006 QImage *tmpimg = NULL; 1007 MythImage *image = NULL; 1008 MythImage *activeimage = NULL; 1009 MythImage *watermark = NULL;1010 QPoint offset; 197 /// \brief Returns true iff a theme has been found by a previous call to 198 /// Init(const char*,const char*) or ReloadTheme(). 199 bool MythThemedMenu::foundTheme(void) 200 { 201 return m_foundtheme; 202 } 1011 203 1012 name = element.attribute("name", ""); 1013 if (name != "") 1014 hasname = true; 204 /// \brief Set the themed menus callback function and data for that function 205 void MythThemedMenu::setCallback(void (*lcallback)(void *, QString &), void *data) 206 { 207 m_state->m_callback = lcallback; 208 m_state->m_callbackdata = data; 209 } 1015 210 1016 for (QDomNode child = element.firstChild(); !child.isNull(); 1017 child = child.nextSibling()) 1018 { 1019 QDomElement info = child.toElement(); 1020 if (!info.isNull()) 1021 { 1022 if (info.tagName() == "image") 1023 { 1024 QString imagepath = dir + getFirstText(info); 211 void MythThemedMenu::setKillable(void) 212 { 213 m_state->m_killable = true; 214 } 1025 215 1026 if (m_loadedImages[imagepath]) 1027 { 1028 image = m_loadedImages[imagepath]; 1029 image->UpRef(); 1030 } 1031 else 1032 { 1033 tmpimg = GetMythUI()->LoadScaleImage(imagepath); 1034 image = MythImage::FromQImage(&tmpimg); 1035 m_loadedImages.insert(imagepath, image); 1036 } 1037 1038 if (image) 1039 hasicon = true; 1040 } 1041 else if (info.tagName() == "activeimage") 1042 { 1043 QString imagepath = dir + getFirstText(info); 1044 1045 if (m_loadedImages[imagepath]) 1046 { 1047 activeimage = m_loadedImages[imagepath]; 1048 activeimage->UpRef(); 1049 } 1050 else 1051 { 1052 tmpimg = GetMythUI()->LoadScaleImage(imagepath); 1053 activeimage = MythImage::FromQImage(&tmpimg); 1054 m_loadedImages.insert(imagepath, activeimage); 1055 } 1056 } 1057 else if (info.tagName() == "offset") 1058 { 1059 offset = parsePoint(info); 1060 hasoffset = true; 1061 } 1062 else if (info.tagName() == "watermarkimage") 1063 { 1064 QString imagepath = dir + getFirstText(info); 1065 1066 if (m_loadedImages[imagepath]) 1067 { 1068 watermark = m_loadedImages[imagepath]; 1069 watermark->UpRef(); 1070 } 1071 else 1072 { 1073 tmpimg = GetMythUI()->LoadScaleImage(imagepath); 1074 watermark = MythImage::FromQImage(&tmpimg); 1075 m_loadedImages.insert(imagepath, watermark); 1076 } 1077 } 1078 else 1079 { 1080 VERBOSE(VB_GENERAL, QString("MythThemedMenuPrivate: Unknown tag %1 " 1081 "in buttondef").arg(info.tagName())); 1082 } 1083 } 1084 } 1085 1086 if (!hasname) 1087 { 1088 VERBOSE(VB_IMPORTANT, "MythThemedMenuPrivate: Missing name in button"); 1089 return; 1090 } 1091 1092 if (!hasoffset) 1093 { 1094 VERBOSE(VB_IMPORTANT, QString("MythThemedMenuPrivate: Missing offset " 1095 "in buttondef %1").arg(name)); 1096 return; 1097 } 1098 1099 if (!hasicon) 1100 { 1101 VERBOSE(VB_IMPORTANT, QString("MythThemedMenuPrivate: Missing image " 1102 "in buttondef %1").arg(name)); 1103 return; 1104 } 1105 1106 ButtonIcon newbutton; 1107 1108 newbutton.name = name; 1109 newbutton.icon = image; 1110 newbutton.offset = offset; 1111 newbutton.activeicon = activeimage; 1112 1113 if (watermark) 1114 { 1115 if (watermark->width() > watermarkRect.width()) 1116 watermarkRect.setWidth(watermark->width()); 1117 1118 if (watermark->height() > watermarkRect.height()) 1119 watermarkRect.setHeight(watermark->height()); 1120 } 1121 1122 newbutton.watermark = watermark; 1123 1124 allButtonIcons[name] = newbutton; 1125 1126 if (tmpimg) 1127 delete tmpimg; 216 QString MythThemedMenu::getSelection(void) 217 { 218 return m_selection; 1128 219 } 1129 220 1130 /** \brief Set buttons, logo, title icons and text, arrows and1131 * watermarks back to the defaults.221 /** \brief Looks at "AllowQuitShutdown" setting in DB, in order to 222 * determine what to show to user on exit from the frontend. 1132 223 */ 1133 void MythThemedMenu State::setDefaults(void)224 void MythThemedMenu::ReloadExitKey(void) 1134 225 { 1135 logo = NULL; 1136 buttonnormal = buttonactive = NULL; 1137 balancerows = true; 226 int allowsd = GetMythDB()->GetNumSetting("AllowQuitShutdown"); 1138 227 1139 normalAttributes.textflags = Qt::AlignTop | Qt::AlignLeft | Qt::TextWordWrap; 1140 activeAttributes.textflags = Qt::AlignTop | Qt::AlignLeft | Qt::TextWordWrap; 1141 1142 titleIcons.clear(); 1143 titleText = ""; 1144 uparrow = NULL; 1145 downarrow = NULL; 1146 watermarkPos = QPoint(0, 0); 1147 watermarkRect = QRect(0, 0, 0, 0); 228 if (allowsd == 1) 229 m_exitModifier = Qt::ControlModifier; 230 else if (allowsd == 2) 231 m_exitModifier = Qt::MetaModifier; 232 else if (allowsd == 3) 233 m_exitModifier = Qt::AltModifier; 234 else if (allowsd == 4) 235 m_exitModifier = 0; 236 else 237 m_exitModifier = -1; 1148 238 } 1149 239 1150 /** \brief Parse the menu from the given dir for background, button, 1151 * logo, arrow, and font settings. 1152 * \param dir directory where setting may be found 1153 * \param menuname file name of menu file from which settings are parsed 1154 * \return true iff file exists, opens, and parses correctly 240 /** \brief keyboard/LIRC event handler. 241 * 242 * This translates key presses through the "menu" context into MythTV 243 * actions and then handles them as appropriate. 1155 244 */ 1156 bool MythThemedMenuState::parseSettings( 1157 const QString &dir, const QString &menuname) 245 bool MythThemedMenu::keyPressEvent(QKeyEvent *e) 1158 246 { 1159 QString filename = dir + menuname; 1160 1161 QDomDocument doc; 1162 QFile f(filename); 1163 1164 if (!f.open(QIODevice::ReadOnly)) 1165 { 1166 VERBOSE(VB_IMPORTANT, QString("MythThemedMenuPrivate::parseSettings(): " 1167 "Can't open: %1").arg(filename)); 247 if (m_ignorekeys) 1168 248 return false; 1169 }1170 249 1171 QString errorMsg; 1172 int errorLine = 0; 1173 int errorColumn = 0; 250 m_ignorekeys = true; 1174 251 1175 if (!doc.setContent(&f, false, &errorMsg, &errorLine, &errorColumn)) 1176 { 1177 VERBOSE(VB_IMPORTANT, QString("MythThemedMenuPrivate: Error, parsing %1\n" 1178 "at line: %2 column: %3 msg: %4"). 1179 arg(filename).arg(errorLine).arg(errorColumn).arg(errorMsg)); 1180 f.close(); 1181 return false; 1182 } 252 bool ret = true; 253 if (!keyPressHandler(e)) 254 ret = MythScreenType::keyPressEvent(e); 1183 255 1184 f.close();256 m_ignorekeys = false; 1185 257 1186 bool setbackground = false;1187 bool setbuttondef = false;258 if (m_wantpop) 259 m_ScreenStack->PopScreen(); 1188 260 1189 setDefaults(); 1190 1191 QDomElement docElem = doc.documentElement(); 1192 QDomNode n = docElem.firstChild(); 1193 while (!n.isNull()) 1194 { 1195 QDomElement e = n.toElement(); 1196 if (!e.isNull()) 1197 { 1198 if (e.tagName() == "background") 1199 { 1200 parseBackground(dir, e); 1201 setbackground = true; 1202 } 1203 else if (e.tagName() == "genericbutton") 1204 { 1205 parseButtonDefinition(dir, e); 1206 setbuttondef = true; 1207 } 1208 else if (e.tagName() == "logo") 1209 { 1210 parseLogo(dir, e); 1211 } 1212 else if (e.tagName() == "buttondef") 1213 { 1214 parseButton(dir, e); 1215 } 1216 else if (e.tagName() == "titles") 1217 { 1218 parseTitle(dir, e); 1219 } 1220 else if (e.tagName() == "uparrow") 1221 { 1222 parseArrow(dir, e, true); 1223 } 1224 else if (e.tagName() == "downarrow") 1225 { 1226 parseArrow(dir, e, false); 1227 } 1228 else if (e.tagName() == "font") 1229 { 1230 if (parseFonts) 1231 { 1232 MythFontProperties *font; 1233 font = MythFontProperties::ParseFromXml(e, NULL, true); 1234 delete font; 1235 } 1236 } 1237 else 1238 { 1239 VERBOSE(VB_GENERAL, QString("MythThemedMenuPrivate: Unknown " 1240 "element %1").arg(e.tagName())); 1241 } 1242 } 1243 n = n.nextSibling(); 1244 } 1245 1246 if (!setbackground) 1247 { 1248 VERBOSE(VB_IMPORTANT, "MythThemedMenuPrivate: Missing background element"); 1249 return false; 1250 } 1251 1252 if (!setbuttondef) 1253 { 1254 VERBOSE(VB_IMPORTANT, 1255 "MythThemedMenuPrivate: Missing genericbutton definition"); 1256 return false; 1257 } 1258 1259 parseFonts = false; 1260 loaded = true; 1261 return true; 261 return ret; 1262 262 } 1263 263 1264 ///////////////////////////////////////////////////////////////////////////// 1265 1266 /** \brief Constructor, Init() must be called before class can be used. 1267 * 1268 * \param lparent menu that owns this instance 1269 * \param cdir directory where theme is stored 1270 * \param lstate corresponding settings of the theme 1271 */ 1272 MythThemedMenuPrivate::MythThemedMenuPrivate(MythThemedMenu *lparent, 1273 const QString &cdir, 1274 MythThemedMenuState *lstate) : 1275 parent(lparent), m_state(lstate), 1276 allocedstate(false), activebutton(NULL), 1277 currentrow(0), currentcolumn(0), 1278 foundtheme(false), exitModifier(-1), 1279 ignorekeys(false), maxrows(0), 1280 visiblerows(0), columns(0), 1281 wantpop(false), watermark(NULL), 1282 uparrow(NULL), downarrow(NULL) 264 void MythThemedMenu::aboutToShow() 1283 265 { 1284 if (!m_state) 1285 { 1286 m_state = new MythThemedMenuState(); 1287 allocedstate = true; 1288 } 1289 1290 m_state->themeDir = cdir; 266 MythScreenType::aboutToShow(); 267 // updateLCD(); 1291 268 } 1292 269 1293 MythThemedMenuPrivate::~MythThemedMenuPrivate()1294 {1295 if (allocedstate)1296 delete m_state;1297 }1298 1299 270 /** \brief Parses the element's tags and set the ThemeButton's type, 1300 271 * text, depends, and action, then adds the button. 1301 272 * 1302 273 * \param element DOM element describing features of the themeButton 1303 274 */ 1304 void MythThemedMenu Private::parseThemeButton(QDomElement &element)275 void MythThemedMenu::parseThemeButton(QDomElement &element) 1305 276 { 1306 277 QString type = ""; 1307 278 QString text = ""; … … 1322 293 } 1323 294 else if (info.tagName() == "text") 1324 295 { 1325 if ((text.isNull() || text.isEmpty()) && 1326 info.attribute("lang","") == "")296 if ((text.isNull() || text.isEmpty()) && 297 info.attribute("lang","").isEmpty()) 1327 298 { 1328 text = getFirstText(info); 299 text = qApp->translate("ThemeUI", 300 qPrintable(getFirstText(info))); 1329 301 } 1330 else if (info.attribute("lang","").toLower() == 302 else if (info.attribute("lang","").toLower() == 1331 303 GetMythUI()->GetLanguageAndVariant()) 1332 304 { 1333 305 text = getFirstText(info); 1334 306 } 1335 else if (info.attribute("lang","").toLower() == 307 else if (info.attribute("lang","").toLower() == 1336 308 GetMythUI()->GetLanguage()) 1337 309 { 1338 310 text = getFirstText(info); … … 1341 313 else if (info.tagName() == "alttext") 1342 314 { 1343 315 if ((alttext.isNull() || alttext.isEmpty()) && 1344 info.attribute("lang","") == "")316 info.attribute("lang","").isEmpty()) 1345 317 { 1346 alttext = getFirstText(info); 318 alttext = qApp->translate("ThemeUI", 319 qPrintable(getFirstText(info))); 1347 320 } 1348 else if (info.attribute("lang","").toLower() == 321 else if (info.attribute("lang","").toLower() == 1349 322 GetMythUI()->GetLanguageAndVariant()) 1350 323 { 1351 324 alttext = getFirstText(info); … … 1380 353 } 1381 354 } 1382 355 1383 if (text == "")356 if (text.isEmpty()) 1384 357 { 1385 358 VERBOSE(VB_IMPORTANT, "MythThemedMenuPrivate: Missing 'text' in button"); 1386 359 return; 1387 360 } 1388 361 1389 362 if (action.empty()) 1390 363 { 1391 364 VERBOSE(VB_IMPORTANT, "MythThemedMenuPrivate: Missing 'action' in button"); … … 1409 382 * non-essential portion of MythTV which the theme does not support. 1410 383 * 1411 384 */ 1412 bool MythThemedMenu Private::parseMenu(const QString &menuname)385 bool MythThemedMenu::parseMenu(const QString &menuname) 1413 386 { 1414 387 QString filename = findMenuFile(menuname); 1415 388 … … 1426 399 } 1427 400 else 1428 401 { 1429 parent->GetScreenStack()->PopScreen(); 1430 #if 0 1431 MythPopupBox::showOkPopup(gContext->GetMainWindow(), QObject::tr("No Menu File"), 1432 QObject::tr(QString("Myth could not locate the menu file %1.\n\n" 1433 "We will now return to the main menu.").arg(menuname))); 1434 #endif 402 GetScreenStack()->PopScreen(); 1435 403 return false; 1436 404 } 1437 1438 405 1439 406 } 1440 407 1441 408 QString errorMsg; … … 1454 421 return false; 1455 422 } 1456 423 1457 parent->GetScreenStack()->PopScreen(); 1458 #if 0 1459 MythPopupBox::showOkPopup(gContext->GetMainWindow(), 1460 QObject::tr("Bad Menu File"), 1461 QObject::tr(QString("The menu file %1 is " 1462 "incomplete.\n\nWe will now " 1463 "return to the main menu.") 1464 .arg(menuname))); 1465 #endif 424 GetScreenStack()->PopScreen(); 1466 425 return false; 1467 426 } 1468 427 1469 428 f.close(); 1470 429 1471 buttonList.clear();1472 buttonRows.clear();1473 1474 SetupBackground();1475 1476 430 QDomElement docElem = doc.documentElement(); 1477 431 1478 m enumode = docElem.attribute("name", "");432 m_menumode = docElem.attribute("name", "MAIN"); 1479 433 1480 434 QDomNode n = docElem.firstChild(); 1481 435 while (!n.isNull()) … … 1497 451 n = n.nextSibling(); 1498 452 } 1499 453 1500 if ( buttonList.size() == 0)454 if (m_buttonList->GetCount() == 0) 1501 455 { 1502 456 VERBOSE(VB_IMPORTANT, QString("MythThemedMenuPrivate: No buttons " 1503 457 "for menu %1").arg(menuname)); 1504 458 return false; 1505 459 } 1506 460 1507 if (!layoutButtons())1508 return false;1509 activebutton = NULL;1510 positionButtons(true);1511 1512 SetupUITypes();1513 1514 461 if (LCD::Get()) 1515 462 { 1516 titleText = "MYTH-";1517 titleText +=menumode;463 m_titleText = "MYTH-"; 464 m_titleText += m_menumode; 1518 465 } 1519 466 1520 selection = ""; 467 if (m_titleState) 468 m_titleState->DisplayState(m_menumode); 469 470 m_selection = ""; 1521 471 return true; 1522 472 } 1523 473 1524 /// \brief Sets up menu background, must be done before the buttons are parsed 1525 void MythThemedMenuPrivate::SetupBackground(void) 474 void MythThemedMenu::updateLCD(void) 1526 475 { 1527 1528 if (m_state->buttonBackground)1529 {1530 MythUIImage *buttonBackground;1531 buttonBackground = new MythUIImage(parent, "menu button background");1532 buttonBackground->SetImage(m_state->buttonBackground);1533 buttonBackground->SetPosition(m_state->buttonArea.topLeft());1534 }1535 1536 }1537 1538 /// \brief Sets up UI according to the corresponding mythThemedMenuState.1539 void MythThemedMenuPrivate::SetupUITypes(void)1540 {1541 if (m_state->titleIcons.contains(menumode))1542 {1543 MythUIImage *curTitle;1544 curTitle = new MythUIImage(parent, "menu title image");1545 curTitle->SetImage(m_state->titleIcons[menumode]);1546 curTitle->SetPosition(m_state->titlePos);1547 }1548 1549 if (m_state->logo)1550 {1551 MythUIImage *logo;1552 logo = new MythUIImage(parent, "menu logo");1553 logo->SetImage(m_state->logo);1554 logo->SetPosition(m_state->logoRect.topLeft());1555 }1556 1557 watermark = new MythUIStateType(parent, "menu watermarks");1558 watermark->SetArea(m_state->watermarkRect);1559 watermark->SetShowEmpty(true);1560 QMap<QString, ButtonIcon>::Iterator it = m_state->allButtonIcons.begin();1561 for (; it != m_state->allButtonIcons.end(); ++it)1562 {1563 ButtonIcon *icon = &(it.value());1564 if (icon->watermark)1565 watermark->AddImage(icon->name, icon->watermark);1566 }1567 1568 watermark->DisplayState(activebutton->type);1569 1570 uparrow = new MythUIImage(parent, "menu up arrow");1571 if (m_state->uparrow)1572 {1573 uparrow->SetArea(m_state->uparrowRect);1574 uparrow->SetImage(m_state->uparrow);1575 }1576 uparrow->SetVisible(false);1577 uparrow->SetCanTakeFocus(true);1578 1579 downarrow = new MythUIImage(parent, "menu down arrow");1580 if (m_state->downarrow)1581 {1582 downarrow->SetArea(m_state->downarrowRect);1583 downarrow->SetImage(m_state->downarrow);1584 }1585 downarrow->SetVisible(false);1586 downarrow->SetCanTakeFocus(true);1587 1588 checkScrollArrows();1589 }1590 1591 void MythThemedMenuPrivate::updateLCD(void)1592 {1593 476 LCD *lcddev = LCD::Get(); 1594 477 if (lcddev == NULL) 1595 478 return; … … 1598 481 QList<LCDMenuItem> menuItems; 1599 482 bool selected; 1600 483 1601 for (int r = 0; r < (int)buttonRows.size(); r++)1602 {1603 if (r == currentrow)1604 selected = true;1605 else1606 selected = false;1607 1608 if (currentcolumn < buttonRows[r].numitems)1609 menuItems.append(LCDMenuItem(selected, NOTCHECKABLE,1610 buttonRows[r].buttons[currentcolumn]->message));1611 }1612 1613 if (!menuItems.isEmpty())1614 lcddev->switchToMenu(menuItems,titleText);484 // for (int r = 0; r < (int)buttonRows.size(); r++) 485 // { 486 // if (r == currentrow) 487 // selected = true; 488 // else 489 // selected = false; 490 // 491 // if (currentcolumn < buttonRows[r].numitems) 492 // menuItems.append(LCDMenuItem(selected, NOTCHECKABLE, 493 // buttonRows[r].buttons[currentcolumn]->message)); 494 // } 495 // 496 // if (!menuItems.isEmpty()) 497 // lcddev->switchToMenu(menuItems, m_titleText); 1615 498 } 1616 499 1617 500 /** \brief Create a new MythThemedButton based on the MythThemedMenuState … … 1623 506 * \param alttext alternate text to appear when required 1624 507 * \param action actions to be associated with button 1625 508 */ 1626 void MythThemedMenu Private::addButton(const QString &type, const QString &text,1627 const QString &alttext, 509 void MythThemedMenu::addButton(const QString &type, const QString &text, 510 const QString &alttext, 1628 511 const QStringList &action) 1629 512 { 1630 ThemedButton *newbutton = new ThemedButton(parent, type); 513 MythUIButtonListItem *listbuttonitem = 514 new MythUIButtonListItem(m_buttonList, text); 1631 515 516 ThemedButton *newbutton = new ThemedButton; 1632 517 newbutton->type = type; 1633 518 newbutton->action = action; 1634 newbutton->message = text; 519 newbutton->text = text; 520 newbutton->active = false; 1635 521 1636 newbutton->SetCanTakeFocus(true); 1637 newbutton->background = new MythUIStateType(newbutton, "button background"); 1638 if (m_state->buttonnormal) 1639 newbutton->background->AddImage(MythUIStateType::None, 1640 m_state->buttonnormal); 1641 if (m_state->buttonactive) 1642 newbutton->background->AddImage(MythUIStateType::Full, 1643 m_state->buttonactive); 1644 newbutton->background->DisplayState(MythUIStateType::None); 1645 1646 newbutton->SetArea(QRect(0, 0, m_state->buttonnormal->width(), 1647 m_state->buttonnormal->height())); 1648 1649 newbutton->icon = NULL; 1650 ButtonIcon *buttonicon = m_state->getButtonIcon(type); 1651 if (buttonicon) 1652 { 1653 newbutton->icon = new MythUIStateType(newbutton, "button icon"); 1654 newbutton->icon->SetPosition(buttonicon->offset); 1655 if (buttonicon->icon) 1656 newbutton->icon->AddImage(MythUIStateType::None, 1657 buttonicon->icon); 1658 if (buttonicon->activeicon) 1659 newbutton->icon->AddImage(MythUIStateType::Full, 1660 buttonicon->activeicon); 1661 newbutton->icon->DisplayState(MythUIStateType::None); 1662 } 1663 1664 newbutton->text = new MythUIStateType(newbutton, "button text state"); 1665 { 1666 QString msg = text; 1667 QRect buttonTextRect = m_state->normalAttributes.textRect; 1668 QRect testBoundRect = buttonTextRect; 1669 testBoundRect.setWidth(testBoundRect.width() + 40); 1670 1671 QFontMetrics tmp(m_state->normalAttributes.font.face()); 1672 QRect testBound = tmp.boundingRect(testBoundRect.x(), testBoundRect.y(), 1673 testBoundRect.width(), 1674 testBoundRect.height(), 1675 m_state->normalAttributes.textflags, 1676 text); 1677 if (testBound.height() > buttonTextRect.height() && alttext != "") 1678 msg = alttext; 1679 1680 MythUIText *txt = new MythUIText(msg, m_state->normalAttributes.font, 1681 buttonTextRect, buttonTextRect, 1682 newbutton->text, "button normal text"); 1683 txt->SetJustification(m_state->normalAttributes.textflags); 1684 newbutton->text->AddObject(MythUIStateType::None, txt); 1685 } 1686 { 1687 QString msg = text; 1688 QRect buttonTextRect = m_state->activeAttributes.textRect; 1689 QRect testBoundRect = buttonTextRect; 1690 testBoundRect.setWidth(testBoundRect.width() + 40); 1691 1692 QFontMetrics tmp(m_state->activeAttributes.font.face()); 1693 QRect testBound = tmp.boundingRect(testBoundRect.x(), testBoundRect.y(), 1694 testBoundRect.width(), 1695 testBoundRect.height(), 1696 m_state->activeAttributes.textflags, 1697 text); 1698 if (testBound.height() > buttonTextRect.height() && alttext != "") 1699 msg = alttext; 1700 1701 MythUIText *txt = new MythUIText(msg, m_state->activeAttributes.font, 1702 buttonTextRect, buttonTextRect, 1703 newbutton->text, "button normal text"); 1704 txt->SetJustification(m_state->activeAttributes.textflags); 1705 newbutton->text->AddObject(MythUIStateType::Full, txt); 1706 } 1707 newbutton->text->DisplayState(MythUIStateType::None); 1708 1709 newbutton->SetVisible(false); 1710 1711 buttonList.push_back(newbutton); 522 listbuttonitem->SetData(qVariantFromValue(newbutton)); 1712 523 } 1713 524 1714 /** \brief Properly lay out all of the buttons that were added with addButton1715 * \return true iff there are more than 0 rows or columns1716 */1717 bool MythThemedMenuPrivate::layoutButtons(void)1718 {1719 int numbuttons = buttonList.size();1720 1721 columns = m_state->buttonArea.width() / m_state->buttonnormal->width();1722 columns = columns > m_state->maxColumns ? m_state->maxColumns : columns;1723 1724 maxrows = m_state->buttonArea.height() / m_state->buttonnormal->height();1725 1726 if (maxrows < 1)1727 {1728 VERBOSE(VB_IMPORTANT, "MythThemedMenuPrivate: Must have "1729 "room for at least 1 row of buttons");1730 return false;1731 }1732 1733 if (columns < 1)1734 {1735 VERBOSE(VB_IMPORTANT, "MythThemedMenuPrivate: Must have "1736 "room for at least 1 column of buttons");1737 return false;1738 }1739 1740 if (m_state->balancerows)1741 {1742 // keep the rows balanced1743 if (numbuttons <= 4)1744 {1745 if (columns > 2)1746 columns = 2;1747 }1748 else1749 {1750 if (columns > 3)1751 columns = 3;1752 }1753 }1754 1755 // limit it to 6 items displayed at one time1756 if (columns * maxrows > m_state->visiblerowlimit)1757 {1758 maxrows = m_state->visiblerowlimit / columns;1759 }1760 1761 vector<ThemedButton *>::iterator iter = buttonList.begin();1762 1763 int rows = numbuttons / columns;1764 rows++;1765 1766 visiblerows = 0;1767 1768 for (int i = 0; i < rows; i++)1769 {1770 MenuRow newrow;1771 newrow.numitems = 0;1772 1773 for (int j = 0; j < columns && iter != buttonList.end();1774 j++, iter++)1775 {1776 if (columns == 3 && j == 1 && m_state->allowreorder)1777 newrow.buttons.insert(newrow.buttons.begin(), *iter);1778 else1779 newrow.buttons.push_back(*iter);1780 newrow.numitems++;1781 }1782 1783 if (i < maxrows && newrow.numitems > 0)1784 {1785 newrow.visible = true;1786 visiblerows++;1787 }1788 else1789 newrow.visible = false;1790 1791 if (newrow.numitems > 0)1792 buttonRows.push_back(newrow);1793 }1794 1795 return true;1796 }1797 1798 /** \brief Place buttons in position and set them visible and active.1799 *1800 * \param resetpos whether or not to reset the active button to the1801 * first one on the buttonlist.1802 */1803 void MythThemedMenuPrivate::positionButtons(bool resetpos)1804 {1805 QRect buttonArea = m_state->buttonArea;1806 int buttonHeight = m_state->buttonnormal->height();1807 int buttonWidth = m_state->buttonnormal->width();1808 1809 int rows = visiblerows;1810 int yspacing = (buttonArea.height() - buttonHeight * rows) /1811 (rows + 1);1812 int ystart = 0;1813 1814 if (!m_state->spreadbuttons)1815 {1816 yspacing = 0;1817 if (m_state->buttoncenter)1818 ystart = (buttonArea.height() - buttonHeight * rows) / 2;1819 }1820 1821 int row = 1;1822 1823 vector<MenuRow>::iterator menuiter = buttonRows.begin();1824 for (; menuiter != buttonRows.end(); menuiter++)1825 {1826 if (!(*menuiter).visible)1827 {1828 vector<ThemedButton *>::iterator biter;1829 biter = (*menuiter).buttons.begin();1830 for (; biter != (*menuiter).buttons.end(); biter++)1831 {1832 ThemedButton *tbutton = (*biter);1833 tbutton->SetVisible(false);1834 tbutton->SetActive(false);1835 }1836 continue;1837 }1838 1839 int ypos = yspacing * row + (buttonHeight * (row - 1));1840 ypos += buttonArea.y() + ystart;1841 1842 int xspacing = (buttonArea.width() - buttonWidth *1843 (*menuiter).numitems) / ((*menuiter).numitems + 1);1844 int col = 1;1845 vector<ThemedButton *>::iterator biter = (*menuiter).buttons.begin();1846 for (; biter != (*menuiter).buttons.end(); biter++)1847 {1848 int xpos = xspacing * col + (buttonWidth * (col - 1));1849 xpos = (m_state->maxColumns == 1) ? 0 : xpos;1850 xpos += buttonArea.x();1851 1852 ThemedButton *tbutton = (*biter);1853 1854 tbutton->SetVisible(true);1855 tbutton->SetActive(false);1856 tbutton->row = row;1857 tbutton->col = col;1858 tbutton->SetPosition(xpos, ypos);1859 1860 col++;1861 }1862 1863 row++;1864 }1865 1866 if (resetpos)1867 {1868 ThemedButton *old = activebutton;1869 activebutton = (*(buttonList.begin()));1870 1871 if (activebutton != old && old)1872 old->SetActive(false);1873 1874 activebutton->SetActive(true);1875 1876 currentrow = activebutton->row - 1;1877 currentcolumn = activebutton->col - 1;1878 }1879 }1880 1881 bool MythThemedMenuPrivate::makeRowVisible(int newrow, int oldrow)1882 {1883 if (buttonRows[newrow].visible)1884 return true;1885 1886 if (newrow > oldrow)1887 {1888 int row;1889 for (row = newrow; row >= 0; row--)1890 {1891 if (row > newrow - visiblerows)1892 buttonRows[row].visible = true;1893 else1894 buttonRows[row].visible = false;1895 }1896 }1897 else1898 {1899 int row;1900 for (row = newrow; row < (int)buttonRows.size(); row++)1901 {1902 if (row < newrow + visiblerows)1903 buttonRows[row].visible = true;1904 else1905 buttonRows[row].visible = false;1906 }1907 }1908 1909 positionButtons(false);1910 1911 checkScrollArrows();1912 1913 return true;1914 }1915 1916 /// \brief Add or remove scroll arrows as needed.1917 void MythThemedMenuPrivate::checkScrollArrows(void)1918 {1919 bool needup = false;1920 bool needdown = false;1921 1922 if (!buttonRows.front().visible)1923 needup = true;1924 if (!buttonRows.back().visible)1925 needdown = true;1926 1927 uparrow->SetVisible(needup);1928 downarrow->SetVisible(needdown);1929 }1930 1931 525 /** \brief Reset and reparse everything. 1932 526 * 1933 527 * Note: this does not use the theme or menu file chosen in Init(), but 1934 528 * instead uses defaults which should work if MythTV was properly installed. 1935 529 */ 1936 bool MythThemedMenuPrivate::ReloadTheme(void)530 void MythThemedMenu::ReloadTheme(void) 1937 531 { 532 m_foundtheme = false; 533 1938 534 GetGlobalFontMap()->Clear(); 1939 m_state->parseFonts = true;1940 535 1941 buttonList.clear(); 1942 buttonRows.clear(); 536 m_buttonList->Reset(); 1943 537 1944 parent->ReloadExitKey(); 1945 1946 m_state->Reset(); 538 ReloadExitKey(); 1947 539 1948 parent->DeleteAllChildren(); 1949 1950 QString themedir = GetMythUI()->GetThemeDir(); 1951 bool ok = m_state->parseSettings(themedir, "theme.xml"); 1952 if (!ok) 1953 return ok; 540 DeleteAllChildren(); 1954 541 1955 return parseMenu("mainmenu.xml"); 542 if (parseMenu("mainmenu.xml")) 543 m_foundtheme = true; 1956 544 } 1957 545 1958 546 /** \brief Delegate key event to appropriate action for keyHandler() 1959 547 * 1960 548 * \return true iff key event was properly handled 1961 549 */ 1962 bool MythThemedMenu Private::keyPressHandler(QKeyEvent *e)550 bool MythThemedMenu::keyPressHandler(QKeyEvent *e) 1963 551 { 1964 552 QStringList actions; 1965 553 GetMythMainWindow()->TranslateKeyPress("menu", e, actions); 1966 554 1967 return keyHandler(actions, e->modifiers() == exitModifier);555 return keyHandler(actions, e->modifiers() == m_exitModifier); 1968 556 } 1969 557 1970 558 /** \brief Interpret key presses on the menu into the appropriate actions 1971 559 * 1972 560 * \param actions list of MythTV actions to be handled. 1973 561 */ 1974 bool MythThemedMenu Private::keyHandler(QStringList &actions,562 bool MythThemedMenu::keyHandler(QStringList &actions, 1975 563 bool fullexit) 1976 564 { 1977 ThemedButton *lastbutton = activebutton;1978 int oldrow = currentrow;1979 int oldcolumn = currentcolumn;1980 565 bool handled = false; 1981 566 1982 567 for (int i = 0; i < actions.size() && !handled; i++) … … 1984 569 QString action = actions[i]; 1985 570 handled = true; 1986 571 1987 if (columns == 1) 572 // if (columns == 1) 573 // { 574 // if (action == "LEFT") 575 // action = "ESCAPE"; 576 // else if (action == "RIGHT") 577 // action = "SELECT"; 578 // } 579 if (action == "ESCAPE") 1988 580 { 1989 if (action == "LEFT")1990 action = "ESCAPE";1991 else if (action == "RIGHT")1992 action = "SELECT";1993 }1994 1995 if (action == "UP")1996 {1997 if (currentrow > 0)1998 currentrow--;1999 else if (columns == 1)2000 currentrow = buttonRows.size() - 1;2001 2002 if (currentcolumn >= buttonRows[currentrow].numitems)2003 currentcolumn = buttonRows[currentrow].numitems - 1;2004 2005 if (currentrow == oldrow && currentcolumn == oldcolumn)2006 {2007 handled = false;2008 }2009 }2010 else if (action == "PAGEUP")2011 {2012 currentrow = max(currentrow - m_state->visiblerowlimit, 0);2013 2014 if (currentcolumn >= buttonRows[currentrow].numitems)2015 currentcolumn = buttonRows[currentrow].numitems - 1;2016 }2017 else if (action == "LEFT")2018 {2019 if (currentcolumn > 0)2020 currentcolumn--;2021 else2022 currentcolumn = buttonRows[currentrow].numitems - 1;2023 }2024 else if (action == "DOWN")2025 {2026 if (currentrow < (int)buttonRows.size() - 1)2027 currentrow++;2028 else if (columns == 1)2029 currentrow = 0;2030 2031 if (currentcolumn >= buttonRows[currentrow].numitems)2032 currentcolumn = buttonRows[currentrow].numitems - 1;2033 2034 if (currentrow == oldrow && currentcolumn == oldcolumn)2035 {2036 handled = false;2037 }2038 }2039 else if (action == "PAGEDOWN")2040 {2041 currentrow = min(currentrow + m_state->visiblerowlimit,2042 (int)buttonRows.size() - 1);2043 2044 if (currentcolumn >= buttonRows[currentrow].numitems)2045 currentcolumn = buttonRows[currentrow].numitems - 1;2046 }2047 else if (action == "RIGHT")2048 {2049 if (currentcolumn < buttonRows[currentrow].numitems - 1)2050 currentcolumn++;2051 else2052 currentcolumn = 0;2053 }2054 else if (action == "SELECT")2055 {2056 lastbutton = activebutton;2057 activebutton = NULL;2058 2059 QStringList::Iterator it = lastbutton->action.begin();2060 for (; it != lastbutton->action.end(); it++)2061 {2062 if (handleAction(*it))2063 break;2064 }2065 2066 lastbutton = NULL;2067 }2068 else if (action == "ESCAPE")2069 {2070 581 QString action = "UPMENU"; 2071 if (! allocedstate)582 if (!m_allocedstate) 2072 583 handleAction(action); 2073 else if (m_state-> killable)584 else if (m_state->m_killable) 2074 585 { 2075 wantpop = true;2076 if (m_state-> callback != NULL)586 m_wantpop = true; 587 if (m_state->m_callback) 2077 588 { 2078 589 QString sel = "EXITING_MENU"; 2079 m_state-> callback(m_state->callbackdata, sel);590 m_state->m_callback(m_state->m_callbackdata, sel); 2080 591 } 2081 592 2082 593 if (GetMythMainWindow()->GetMainStack()->TotalScreens() == 1) 2083 594 QApplication::exit(); 2084 595 } 2085 else if ( exitModifier >= 0 && fullexit &&596 else if (m_exitModifier >= 0 && fullexit && 2086 597 GetMythMainWindow()->GetMainStack()->TotalScreens() == 1) 2087 598 { 2088 599 QApplication::exit(); 2089 wantpop = true;600 m_wantpop = true; 2090 601 } 2091 lastbutton = NULL;2092 602 } 2093 603 else 2094 604 handled = false; … … 2097 607 if (!handled) 2098 608 return false; 2099 609 2100 if (!buttonRows[currentrow].visible)2101 {2102 makeRowVisible(currentrow, oldrow);2103 }2104 2105 activebutton = buttonRows[currentrow].buttons[currentcolumn];2106 watermark->DisplayState(activebutton->type);2107 2108 if (lastbutton != activebutton && lastbutton && activebutton)2109 {2110 lastbutton->SetActive(false);2111 activebutton->SetActive(true);2112 }2113 2114 610 // only update the LCD if we are still on the top of the stack 2115 if (parent->GetScreenStack()->GetTopScreen() == (MythScreenType*) parent)2116 updateLCD();611 // if (GetScreenStack()->GetTopScreen() == this) 612 // updateLCD(); 2117 613 2118 614 return true; 2119 } 615 } 2120 616 2121 /** \brief Interprets mouse gestures as MythTV action events 2122 * 2123 * \param origtype originating element type for the gesture 2124 * \param ge mouse gesture event 2125 * \return true iff a gesture was handled here. 2126 */ 2127 bool MythThemedMenuPrivate::gestureEvent(MythUIType *origtype, 2128 MythGestureEvent *ge) 617 void MythThemedMenu::buttonAction(MythUIButtonListItem *item) 2129 618 { 2130 if (ge->gesture() == MythGestureEvent::Click) 2131 { 2132 if (origtype == uparrow) 2133 { 2134 QStringList action("PAGEUP"); 2135 keyHandler(action, false); 2136 } 2137 else if (origtype == downarrow) 2138 { 2139 QStringList action("PAGEDOWN"); 2140 keyHandler(action, false); 2141 } 2142 else 2143 { 2144 if (ThemedButton *button = reinterpret_cast<ThemedButton*>(origtype)) 2145 { 2146 ThemedButton *lastbutton = activebutton; 2147 activebutton = button; 619 ThemedButton *button = item->GetData().value<ThemedButton *>(); 2148 620 2149 if (LCD *lcddev = LCD::Get()) 2150 lcddev->switchToTime(); 2151 2152 QStringList::Iterator it = button->action.begin(); 2153 for (; it != button->action.end(); it++) 2154 { 2155 if (handleAction(*it)) 2156 break; 2157 } 2158 2159 watermark->DisplayState(activebutton->type); 2160 2161 if (lastbutton != activebutton && lastbutton && activebutton) 2162 { 2163 lastbutton->SetActive(false); 2164 activebutton->SetActive(true); 2165 } 2166 } 2167 } 2168 2169 return true; 2170 } 2171 2172 if (ge->gesture() == MythGestureEvent::Left) 621 QStringList::Iterator it = button->action.begin(); 622 for (; it != button->action.end(); it++) 2173 623 { 2174 QStringList action("ESCAPE"); 2175 keyHandler(action, true); 2176 return true; 624 if (handleAction(*it)) 625 break; 2177 626 } 2178 627 2179 return false;628 button = NULL; 2180 629 } 2181 630 2182 631 /** \brief Locates the appropriate menu file from which to parse the menu … … 2184 633 * \param menuname file name of the menu you want to find 2185 634 * \return the directory in which the menu file is found 2186 635 */ 2187 QString MythThemedMenu Private::findMenuFile(const QString &menuname)636 QString MythThemedMenu::findMenuFile(const QString &menuname) 2188 637 { 2189 638 QString testdir = GetConfDir() + "/" + menuname; 2190 639 QFile file(testdir); … … 2196 645 if (file.exists()) 2197 646 return testdir; 2198 647 2199 2200 648 testdir = GetMythUI()->GetThemeDir() + "/" + menuname; 2201 649 file.setFileName(testdir); 2202 650 if (file.exists()) 2203 651 return testdir; 2204 652 2205 653 testdir = GetShareDir() + menuname; 2206 654 file.setFileName(testdir); 2207 655 if (file.exists()) 2208 656 return testdir; 2209 657 2210 658 testdir = "../mythfrontend/" + menuname; 2211 659 file.setFileName(testdir); 2212 660 if (file.exists()) 2213 661 return testdir; 2214 662 2215 663 return ""; 2216 664 } 2217 665 … … 2220 668 * \param action single action to be handled 2221 669 * \return true if the action is not to EXEC another program 2222 670 */ 2223 bool MythThemedMenu Private::handleAction(const QString &action)671 bool MythThemedMenu::handleAction(const QString &action) 2224 672 { 2225 673 MythUIMenuCallbacks *cbs = GetMythUI()->GetMenuCBs(); 2226 674 … … 2229 677 QString rest = action.right(action.length() - 5); 2230 678 if (cbs && cbs->exec_program) 2231 679 cbs->exec_program(rest); 2232 680 2233 681 return false; 2234 682 } 2235 683 else if (action.left(7) == "EXECTV ") … … 2240 688 } 2241 689 else if (action.left(5) == "MENU ") 2242 690 { 2243 QString rest= action.right(action.length() - 5);691 QString menu = action.right(action.length() - 5); 2244 692 2245 if ( rest == "main_settings.xml" &&693 if (menu == "main_settings.xml" && 2246 694 GetMythDB()->GetNumSetting("SetupPinCodeRequired", 0) && 2247 695 !checkPinCode("SetupPinCodeTime", "SetupPinCode", "Setup Pin:")) 2248 696 { 2249 697 return true; 2250 698 } 2251 699 2252 MythScreenStack *stack = parent->GetScreenStack();700 MythScreenStack *stack = GetScreenStack(); 2253 701 2254 MythThemedMenu *newmenu = new MythThemedMenu(m_state->themeDir, 2255 rest, stack, rest, 2256 m_state->allowreorder, 2257 m_state); 702 MythThemedMenu *newmenu = new MythThemedMenu("", menu, stack, menu, 703 false, m_state); 2258 704 stack->AddScreen(newmenu); 2259 705 } 2260 706 else if (action.left(6) == "UPMENU") 2261 707 { 2262 wantpop = true;708 m_wantpop = true; 2263 709 } 2264 710 else if (action.left(12) == "CONFIGPLUGIN") 2265 711 { … … 2275 721 } 2276 722 else if (action.left(8) == "SHUTDOWN") 2277 723 { 2278 if ( allocedstate)724 if (m_allocedstate) 2279 725 { 2280 wantpop = true;726 m_wantpop = true; 2281 727 } 2282 728 } 2283 729 else if (action.left(5) == "EJECT") … … 2292 738 } 2293 739 else 2294 740 { 2295 selection = action;2296 if (m_state-> callback != NULL)2297 m_state-> callback(m_state->callbackdata,selection);741 m_selection = action; 742 if (m_state->m_callback) 743 m_state->m_callback(m_state->m_callbackdata, m_selection); 2298 744 } 2299 745 2300 return true; 746 return true; 2301 747 } 2302 748 2303 2304 bool MythThemedMenuPrivate::findDepends(const QString &fileList) 749 bool MythThemedMenu::findDepends(const QString &fileList) 2305 750 { 2306 751 QStringList files = fileList.split(" "); 2307 752 QString filename; 2308 753 2309 for (QStringList::Iterator it = files.begin(); it != files.end(); ++it ) 754 for (QStringList::Iterator it = files.begin(); it != files.end(); ++it ) 2310 755 { 2311 756 QString filename = findMenuFile(*it); 2312 757 if (filename != "" && filename.endsWith(".xml")) … … 2330 775 * \param text the message text to be displayed 2331 776 * \return true if password checks out or is not needed. 2332 777 */ 2333 bool MythThemedMenu Private::checkPinCode(const QString ×tamp_setting,778 bool MythThemedMenu::checkPinCode(const QString ×tamp_setting, 2334 779 const QString &password_setting, 2335 780 const QString &text) 2336 781 { … … 2349 794 } 2350 795 else 2351 796 { 2352 QDateTime last_time = QDateTime::fromString(last_time_stamp, 797 QDateTime last_time = QDateTime::fromString(last_time_stamp, 2353 798 Qt::TextDate); 2354 799 if (last_time.secsTo(curr_time) < 120) 2355 800 { … … 2383 828 2384 829 return false; 2385 830 } 2386 2387 ////////////////////////////////////////////////////////////////////////////2388 2389 /** \brief Creates a themed menu.2390 *2391 * \param cdir directory where theme is stored2392 * \param menufile file name of menu definition file2393 * \param parent the screen stack that owns this UI type2394 * \param name the name of this UI type2395 * \param allowreorder will buttons be inserted into new rows or pushed back2396 * \param state theme state associated with this menu2397 */2398 MythThemedMenu::MythThemedMenu(const QString &cdir, const QString &menufile,2399 MythScreenStack *parent, const QString &name,2400 bool allowreorder, MythThemedMenuState *state)2401 : MythScreenType(parent, name)2402 {2403 d = new MythThemedMenuPrivate(this, cdir, state);2404 d->m_state->allowreorder = allowreorder;2405 2406 Init(cdir, menufile);2407 }2408 2409 /** \brief Loads the main UI theme, and a menu theme.2410 *2411 * See also foundTheme(void), it will return true when called after2412 * this method if this method was successful.2413 *2414 * See also ReloadTheme(void) which you can use to load a generic theme,2415 * if foundTheme(void) returns false after calling this.2416 *2417 * \param cdir directory where theme.xml is stored2418 * \param menufile name of menu item xml file2419 */2420 void MythThemedMenu::Init(const QString &cdir, const QString &menufile)2421 {2422 QString dir = QString(cdir) + "/";2423 QString filename = dir + "theme.xml";2424 2425 d->foundtheme = true;2426 QFile filetest(filename);2427 if (!filetest.exists())2428 {2429 d->foundtheme = false;2430 return;2431 }2432 2433 ReloadExitKey();2434 2435 if (!d->m_state->loaded)2436 d->foundtheme = d->m_state->parseSettings(dir, "theme.xml");2437 2438 if (d->foundtheme)2439 d->parseMenu(menufile);2440 }2441 2442 MythThemedMenu::~MythThemedMenu(void)2443 {2444 if (d)2445 delete d;2446 }2447 2448 /// \brief Returns true iff a theme has been found by a previous call to2449 /// Init(const char*,const char*) or ReloadTheme().2450 bool MythThemedMenu::foundTheme(void)2451 {2452 return d->foundtheme;2453 }2454 2455 /// \brief Set the themed menus callback function and data for that function2456 void MythThemedMenu::setCallback(void (*lcallback)(void *, QString &), void *data)2457 {2458 d->m_state->callback = lcallback;2459 d->m_state->callbackdata = data;2460 }2461 2462 void MythThemedMenu::setKillable(void)2463 {2464 d->m_state->killable = true;2465 }2466 2467 QString MythThemedMenu::getSelection(void)2468 {2469 return d->selection;2470 }2471 2472 /** \brief Looks at "AllowQuitShutdown" setting in DB, in order to2473 * determine what to show to user on exit from the frontend.2474 */2475 void MythThemedMenu::ReloadExitKey(void)2476 {2477 int allowsd = GetMythDB()->GetNumSetting("AllowQuitShutdown");2478 2479 if (allowsd == 1)2480 d->exitModifier = Qt::ControlModifier;2481 else if (allowsd == 2)2482 d->exitModifier = Qt::MetaModifier;2483 else if (allowsd == 3)2484 d->exitModifier = Qt::AltModifier;2485 else if (allowsd == 4)2486 d->exitModifier = 0;2487 else2488 d->exitModifier = -1;2489 }2490 2491 /** \brief Reset and reparse everything, check foundTheme(void) for success.2492 *2493 * Note: this does not use the theme or menu file chosen in Init(), but2494 * instead uses defaults which should work if MythTV was properly installed.2495 */2496 void MythThemedMenu::ReloadTheme(void)2497 {2498 if (!d->ReloadTheme())2499 d->foundtheme = false;2500 }2501 2502 /** \brief keyboard/LIRC event handler.2503 *2504 * This translates key presses through the "menu" context into MythTV2505 * actions and then handles them as appropriate.2506 */2507 bool MythThemedMenu::keyPressEvent(QKeyEvent *e)2508 {2509 if (d->ignorekeys)2510 return false;2511 2512 d->ignorekeys = true;2513 2514 bool ret = true;2515 if (!d->keyPressHandler(e))2516 {2517 ret = MythScreenType::keyPressEvent(e);2518 }2519 2520 d->ignorekeys = false;2521 2522 2523 if (d->wantpop)2524 m_ScreenStack->PopScreen();2525 2526 return ret;2527 }2528 2529 /** \brief Interprets mouse gestures as MythTV action events2530 *2531 * \param origtype originating element type from the screen2532 * \param ge mouse gesture event2533 */2534 void MythThemedMenu::gestureEvent(MythUIType *origtype, MythGestureEvent *ge)2535 {2536 if (d->gestureEvent(origtype, ge))2537 {2538 if (d->wantpop)2539 m_ScreenStack->PopScreen();2540 }2541 else2542 MythScreenType::gestureEvent(origtype, ge);2543 }2544 2545 void MythThemedMenu::aboutToShow()2546 {2547 MythScreenType::aboutToShow();2548 d->updateLCD();2549 } -
mythtv/libs/libmythui/myththemedmenu.h
2 2 #define MYTHTHEMEDMENU_H_ 3 3 4 4 #include "mythscreentype.h" 5 #include "mythuistatetype.h" 6 #include "mythuibuttonlist.h" 7 #include "xmlparsebase.h" 5 8 6 9 #include <QKeyEvent> 7 10 8 11 class MythMainWindow; 9 class MythThemedMenuPrivate;10 12 class MythThemedMenuState; 11 13 14 struct ThemedButton 15 { 16 QString type; 17 QStringList action; 18 QString text; 19 MythImage *icon; 20 bool active; 21 }; 22 23 Q_DECLARE_METATYPE(ThemedButton*); 24 25 struct ButtonIcon 26 { 27 QString name; 28 MythImage *icon; 29 MythImage *activeicon; 30 QPoint offset; 31 }; 32 33 34 /** \class MyththemedMenuState 35 * \brief Private class that controls the settings of buttons, logos, 36 * backgrounds, texts, and more, for the MythThemedMenu class. 37 */ 38 class MythThemedMenuState : public MythScreenType 39 { 40 public: 41 MythThemedMenuState(MythScreenStack *parent, const QString &name); 42 ~MythThemedMenuState(); 43 44 bool Create(void); 45 46 ButtonIcon *getButtonIcon(const QString &type); 47 48 QMap<QString, ButtonIcon> m_allButtonIcons; 49 QMap<QString, MythImage *> m_titleIcons; 50 QString m_titleText; 51 52 void (*m_callback)(void *, QString &); 53 void *m_callbackdata; 54 55 bool m_killable; 56 57 bool m_loaded; 58 MythUIStateType *m_titleState; 59 MythUIStateType *m_watermarkState; 60 MythUIButtonList *m_buttonList; 61 62 protected: 63 void CopyFrom(MythUIType*); 64 }; 65 12 66 /// \brief Themed menu class, used for main menus in %MythTV frontend 13 class MythThemedMenu : public Myth ScreenType67 class MythThemedMenu : public MythThemedMenuState 14 68 { 15 69 Q_OBJECT 16 70 public: 17 71 MythThemedMenu(const QString &cdir, const QString &menufile, 18 MythScreenStack *parent, const QString &name,19 bool allowreorder = true, MythThemedMenuState *state = NULL);72 MythScreenStack *parent, const QString &name, 73 bool allowreorder = false, MythThemedMenuState *state = NULL); 20 74 ~MythThemedMenu(); 21 75 22 76 bool foundTheme(void); … … 32 86 33 87 protected: 34 88 virtual bool keyPressEvent(QKeyEvent *e); 35 virtual void gestureEvent(MythUIType *origtype, MythGestureEvent *ge);36 89 90 private slots: 91 void setButtonActive(MythUIButtonListItem* item); 92 void buttonAction(MythUIButtonListItem* item); 93 37 94 private: 38 void Init(const QString & cdir, const QString &menufile);95 void Init(const QString &menufile); 39 96 40 MythThemedMenuPrivate *d; 97 bool keyPressHandler(QKeyEvent *e); 98 bool keyHandler(QStringList &actions, bool fullexit); 99 100 bool parseMenu(const QString &menuname); 101 void parseThemeButton(QDomElement &element); 102 103 void addButton(const QString &type, const QString &text, 104 const QString &alttext, const QStringList &action); 105 106 bool handleAction(const QString &action); 107 bool findDepends(const QString &fileList); 108 QString findMenuFile(const QString &menuname); 109 110 bool checkPinCode(const QString ×tamp_setting, 111 const QString &password_setting, 112 const QString &text); 113 114 void updateLCD(void); 115 116 MythThemedMenu *m_parent; 117 118 MythThemedMenuState *m_state; 119 bool m_allocedstate; 120 121 ThemedButton *m_activebutton; 122 123 QString m_selection; 124 bool m_foundtheme; 125 126 int m_exitModifier; 127 128 bool m_ignorekeys; 129 130 bool m_wantpop; 131 132 QString m_titleText; 133 QString m_menumode; 41 134 }; 42 135 43 136 #endif