Ticket #12: mythui_themedmenu.diff

File mythui_themedmenu.diff, 83.8 KB (added by stuartm, 4 years ago)

Re-written myththemedmenu, incomplete but functional

  • mythtv/libs/libmythui/myththemedmenu.cpp

     
    1111 
    1212#include "myththemedmenu.h" 
    1313#include "mythmainwindow.h" 
    14 #include "mythfontproperties.h" 
    15 #include "mythimage.h" 
    1614#include "mythdialogbox.h" 
    1715 
    1816#include "mythgesture.h" 
     
    2826#include "mythdirs.h" 
    2927#include "lcddevice.h" 
    3028 
    31 struct TextAttributes 
     29MythThemedMenuState::MythThemedMenuState(MythScreenStack *parent, 
     30                                         const QString &name) 
     31                    : MythScreenType(parent, name) 
    3232{ 
    33     QRect textRect; 
    34     MythFontProperties font; 
    35     int textflags; 
    36 }; 
     33    m_loaded = false; 
    3734 
    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; 
    4637 
    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; 
    5640 
    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 &timestamp_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; 
    25642} 
    25743 
    25844MythThemedMenuState::~MythThemedMenuState() 
    25945{ 
    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  
    28546    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) 
    28748    { 
    28849        if (it.value().icon) 
    28950            it.value().icon->DownRef(); 
    29051        if (it.value().activeicon) 
    29152            it.value().activeicon->DownRef(); 
    292         if (it.value().watermark) 
    293             it.value().watermark->DownRef(); 
    29453    } 
    295     allButtonIcons.clear(); 
     54    m_allButtonIcons.clear(); 
    29655 
    29756    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) 
    29958    { 
    30059        jt.value()->DownRef(); 
    30160    } 
    302     titleIcons.clear(); 
    303     m_loadedImages.clear(); 
    304  
    305     normalAttributes = activeAttributes = TextAttributes(); 
    306     setDefaults(); 
    307  
    308     loaded = false; 
     61    m_titleIcons.clear(); 
    30962} 
    31063 
    311 ButtonIcon *MythThemedMenuState::getButtonIcon(const QString &type) 
     64bool MythThemedMenuState::Create(void) 
    31265{ 
    313     if (allButtonIcons.find(type) != allButtonIcons.end()) 
    314         return &(allButtonIcons[type]); 
    315     return NULL; 
    316 } 
     66    bool foundtheme = false; 
    31767 
    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); 
    32769 
    328     bool hasarea = false; 
     70    if (!foundtheme) 
     71        return false; 
    32972 
    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")); 
    33476 
    335     for (QDomNode child = element.firstChild(); !child.isNull(); 
    336          child = child.nextSibling()) 
     77    if (!m_buttonList) 
    33778    { 
    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; 
    38681    } 
    38782 
    388     if (!hasarea) 
    389     { 
    390         VERBOSE(VB_IMPORTANT, "MythThemedMenuPrivate: Missing button area in background"); 
    391         return; 
    392     } 
    393 } 
     83    m_buttonList->SetActive(true); 
    39484 
    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; 
    40686 
    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; 
    46188} 
    46289 
    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) 
     90void MythThemedMenu::setButtonActive(MythUIButtonListItem* item) 
    47191{ 
    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) 
    48094    { 
    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; 
    50397    } 
    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"); 
    51899} 
    519100 
    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) 
     101ButtonIcon *MythThemedMenuState::getButtonIcon(const QString &type) 
    528102{ 
    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; 
    692106} 
    693107 
    694 void MythThemedMenuState::parseButtonDefinition(const QString &dir,  
    695                                                 QDomElement &element) 
     108void MythThemedMenuState::CopyFrom(MythUIType *base) 
    696109{ 
    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) 
    707112    { 
    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"); 
    768114        return; 
    769115    } 
    770116 
    771     if (!hasactive) 
    772     { 
    773         VERBOSE(VB_IMPORTANT, "MythThemedMenuPrivate: No active button image defined"); 
    774         return; 
    775     } 
     117    m_loaded = st->m_loaded; 
    776118 
    777     if (!hasactivetext) 
    778     { 
    779         activeAttributes = normalAttributes; 
    780     } 
     119    MythScreenType::CopyFrom(base); 
    781120 
    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")); 
    783124} 
    784125 
    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. 
    787129 * 
    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 
    790134 */ 
    791 void MythThemedMenuState::parseLogo(const QString &dir, QDomElement &element) 
     135MythThemedMenu::MythThemedMenu(const QString &cdir, const QString &menufile, 
     136                               MythScreenStack *parent, const QString &name, 
     137                               bool allowreorder, MythThemedMenuState *state) 
     138              : MythThemedMenuState(parent, name) 
    792139{ 
    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 = ""; 
    795144 
    796     QPoint logopos; 
    797  
    798     for (QDomNode child = element.firstChild(); !child.isNull(); 
    799          child = child.nextSibling()) 
     145    if (!m_state) 
    800146    { 
    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; 
    825149    } 
    826150 
    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); 
    841152} 
    842153 
    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. 
    845155 * 
    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. 
    926158 * 
    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 
    929163 */ 
    930 void MythThemedMenuState::parseArrow(const QString &dir, QDomElement &element,  
    931                                      bool up) 
     164void MythThemedMenu::Init(const QString &menufile) 
    932165{ 
    933     QRect arrowrect; 
    934     QPoint arrowpos; 
    935     QImage *pix = NULL;     
     166    ReloadExitKey(); 
    936167 
    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) 
    942169    { 
    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; 
    964172    } 
     173    else 
     174        m_foundtheme = true; 
    965175 
    966     if (!hasimage) 
    967     { 
    968         VERBOSE(VB_IMPORTANT, "MythThemedMenuPrivate: Missing image tag in arrow"); 
     176    if (!m_foundtheme) 
    969177        return; 
    970     } 
    971178 
    972     if (!hasposition) 
    973     { 
    974         VERBOSE(VB_IMPORTANT, "MythThemedMenuPrivate: Missing position tag in arrow"); 
    975         return; 
    976     } 
     179    CopyFrom(m_state); 
    977180 
    978     arrowrect = QRect(arrowpos.x(), arrowpos.y(), pix->width(), 
    979                       pix->height()); 
     181    parseMenu(menufile); 
    980182 
    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); 
    991189} 
    992190 
    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) 
     191MythThemedMenu::~MythThemedMenu(void) 
    1000192{ 
    1001     bool hasname = false; 
    1002     bool hasoffset = false; 
    1003     bool hasicon = false; 
     193    if (m_allocedstate) 
     194        delete m_state; 
     195} 
    1004196 
    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(). 
     199bool MythThemedMenu::foundTheme(void) 
     200{ 
     201    return m_foundtheme; 
     202} 
    1011203 
    1012     name = element.attribute("name", ""); 
    1013     if (name != "") 
    1014         hasname = true; 
     204/// \brief Set the themed menus callback function and data for that function 
     205void MythThemedMenu::setCallback(void (*lcallback)(void *, QString &), void *data) 
     206{ 
     207    m_state->m_callback = lcallback; 
     208    m_state->m_callbackdata = data; 
     209} 
    1015210 
    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); 
     211void MythThemedMenu::setKillable(void) 
     212{ 
     213    m_state->m_killable = true; 
     214} 
    1025215 
    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; 
     216QString MythThemedMenu::getSelection(void) 
     217{ 
     218    return m_selection; 
    1128219} 
    1129220 
    1130 /** \brief Set buttons, logo, title icons and text, arrows and 
    1131  *         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. 
    1132223 */ 
    1133 void MythThemedMenuState::setDefaults(void) 
     224void MythThemedMenu::ReloadExitKey(void) 
    1134225{ 
    1135     logo = NULL; 
    1136     buttonnormal = buttonactive = NULL; 
    1137     balancerows = true; 
     226    int allowsd = GetMythDB()->GetNumSetting("AllowQuitShutdown"); 
    1138227 
    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; 
    1148238} 
    1149239 
    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. 
    1155244 */ 
    1156 bool MythThemedMenuState::parseSettings( 
    1157     const QString &dir, const QString &menuname) 
     245bool MythThemedMenu::keyPressEvent(QKeyEvent *e) 
    1158246{ 
    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) 
    1168248        return false; 
    1169     } 
    1170249 
    1171     QString errorMsg; 
    1172     int errorLine = 0; 
    1173     int errorColumn = 0; 
     250    m_ignorekeys = true; 
    1174251 
    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); 
    1183255 
    1184     f.close(); 
     256    m_ignorekeys = false; 
    1185257 
    1186     bool setbackground = false; 
    1187     bool setbuttondef = false; 
     258    if (m_wantpop) 
     259        m_ScreenStack->PopScreen(); 
    1188260 
    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; 
    1262262} 
    1263263 
    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) 
     264void MythThemedMenu::aboutToShow() 
    1283265{ 
    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(); 
    1291268} 
    1292269 
    1293 MythThemedMenuPrivate::~MythThemedMenuPrivate() 
    1294 { 
    1295     if (allocedstate) 
    1296         delete m_state; 
    1297 } 
    1298  
    1299270/** \brief Parses the element's tags and set the ThemeButton's type, 
    1300271 *         text, depends, and action, then adds the button. 
    1301272 * 
    1302273 *  \param element DOM element describing features of the themeButton 
    1303274 */ 
    1304 void MythThemedMenuPrivate::parseThemeButton(QDomElement &element) 
     275void MythThemedMenu::parseThemeButton(QDomElement &element) 
    1305276{ 
    1306277    QString type = ""; 
    1307278    QString text = ""; 
     
    1322293            } 
    1323294            else if (info.tagName() == "text") 
    1324295            { 
    1325                 if ((text.isNull() || text.isEmpty()) &&  
    1326                     info.attribute("lang","") == "") 
     296                if ((text.isNull() || text.isEmpty()) && 
     297                    info.attribute("lang","").isEmpty()) 
    1327298                { 
    1328                     text = getFirstText(info); 
     299                    text = qApp->translate("ThemeUI", 
     300                                            qPrintable(getFirstText(info))); 
    1329301                } 
    1330                 else if (info.attribute("lang","").toLower() ==  
     302                else if (info.attribute("lang","").toLower() == 
    1331303                         GetMythUI()->GetLanguageAndVariant()) 
    1332304                { 
    1333305                    text = getFirstText(info); 
    1334306                } 
    1335                 else if (info.attribute("lang","").toLower() ==  
     307                else if (info.attribute("lang","").toLower() == 
    1336308                         GetMythUI()->GetLanguage()) 
    1337309                { 
    1338310                    text = getFirstText(info); 
     
    1341313            else if (info.tagName() == "alttext") 
    1342314            { 
    1343315                if ((alttext.isNull() || alttext.isEmpty()) && 
    1344                     info.attribute("lang","") == "") 
     316                    info.attribute("lang","").isEmpty()) 
    1345317                { 
    1346                     alttext = getFirstText(info); 
     318                    alttext = qApp->translate("ThemeUI", 
     319                                            qPrintable(getFirstText(info))); 
    1347320                } 
    1348                 else if (info.attribute("lang","").toLower() ==  
     321                else if (info.attribute("lang","").toLower() == 
    1349322                         GetMythUI()->GetLanguageAndVariant()) 
    1350323                { 
    1351324                    alttext = getFirstText(info); 
     
    1380353        } 
    1381354    } 
    1382355 
    1383     if (text == "") 
     356    if (text.isEmpty()) 
    1384357    { 
    1385358        VERBOSE(VB_IMPORTANT, "MythThemedMenuPrivate: Missing 'text' in button"); 
    1386359        return; 
    1387360    } 
    1388     
     361 
    1389362    if (action.empty()) 
    1390363    { 
    1391364        VERBOSE(VB_IMPORTANT, "MythThemedMenuPrivate: Missing 'action' in button"); 
     
    1409382 *  non-essential portion of MythTV which the theme does not support. 
    1410383 * 
    1411384 */ 
    1412 bool MythThemedMenuPrivate::parseMenu(const QString &menuname) 
     385bool MythThemedMenu::parseMenu(const QString &menuname) 
    1413386{ 
    1414387    QString filename = findMenuFile(menuname); 
    1415388 
     
    1426399        } 
    1427400        else 
    1428401        { 
    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(); 
    1435403            return false; 
    1436404        } 
    1437          
    1438          
     405 
    1439406    } 
    1440407 
    1441408    QString errorMsg; 
     
    1454421            return false; 
    1455422        } 
    1456423 
    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(); 
    1466425        return false; 
    1467426    } 
    1468427 
    1469428    f.close(); 
    1470429 
    1471     buttonList.clear(); 
    1472     buttonRows.clear(); 
    1473  
    1474     SetupBackground(); 
    1475  
    1476430    QDomElement docElem = doc.documentElement(); 
    1477431 
    1478     menumode = docElem.attribute("name", ""); 
     432    m_menumode = docElem.attribute("name", "MAIN"); 
    1479433 
    1480434    QDomNode n = docElem.firstChild(); 
    1481435    while (!n.isNull()) 
     
    1497451        n = n.nextSibling(); 
    1498452    } 
    1499453 
    1500     if (buttonList.size() == 0) 
     454    if (m_buttonList->GetCount() == 0) 
    1501455    { 
    1502456        VERBOSE(VB_IMPORTANT, QString("MythThemedMenuPrivate: No buttons " 
    1503457                                      "for menu %1").arg(menuname)); 
    1504458        return false; 
    1505459    } 
    1506460 
    1507     if (!layoutButtons()) 
    1508         return false; 
    1509     activebutton = NULL; 
    1510     positionButtons(true); 
    1511  
    1512     SetupUITypes(); 
    1513  
    1514461    if (LCD::Get()) 
    1515462    { 
    1516         titleText = "MYTH-"; 
    1517         titleText += menumode; 
     463        m_titleText = "MYTH-"; 
     464        m_titleText += m_menumode; 
    1518465    } 
    1519466 
    1520     selection = ""; 
     467    if (m_titleState) 
     468        m_titleState->DisplayState(m_menumode); 
     469 
     470    m_selection = ""; 
    1521471    return true; 
    1522472} 
    1523473 
    1524 /// \brief Sets up menu background, must be done before the buttons are parsed 
    1525 void MythThemedMenuPrivate::SetupBackground(void) 
     474void MythThemedMenu::updateLCD(void) 
    1526475{ 
    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 { 
    1593476    LCD *lcddev = LCD::Get(); 
    1594477    if (lcddev == NULL) 
    1595478        return; 
     
    1598481    QList<LCDMenuItem> menuItems; 
    1599482    bool selected; 
    1600483 
    1601     for (int r = 0; r < (int)buttonRows.size(); r++) 
    1602     { 
    1603         if (r == currentrow) 
    1604             selected = true; 
    1605         else 
    1606             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); 
    1615498} 
    1616499 
    1617500/** \brief Create a new MythThemedButton based on the MythThemedMenuState 
     
    1623506 *  \param alttext alternate text to appear when required 
    1624507 *  \param action  actions to be associated with button 
    1625508 */ 
    1626 void MythThemedMenuPrivate::addButton(const QString &type, const QString &text,  
    1627                                       const QString &alttext,  
     509void MythThemedMenu::addButton(const QString &type, const QString &text, 
     510                                      const QString &alttext, 
    1628511                                      const QStringList &action) 
    1629512{ 
    1630     ThemedButton *newbutton = new ThemedButton(parent, type); 
     513    MythUIButtonListItem *listbuttonitem = 
     514                                new MythUIButtonListItem(m_buttonList, text); 
    1631515 
     516    ThemedButton *newbutton = new ThemedButton; 
    1632517    newbutton->type = type; 
    1633518    newbutton->action = action; 
    1634     newbutton->message = text; 
     519    newbutton->text = text; 
     520    newbutton->active = false; 
    1635521 
    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)); 
    1712523} 
    1713524 
    1714 /** \brief Properly lay out all of the buttons that were added with addButton 
    1715  *  \return true iff there are more than 0 rows or columns 
    1716  */ 
    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 balanced 
    1743         if (numbuttons <= 4) 
    1744         { 
    1745             if (columns > 2) 
    1746                 columns = 2; 
    1747         } 
    1748         else 
    1749         { 
    1750             if (columns > 3) 
    1751                 columns = 3; 
    1752         } 
    1753     }     
    1754  
    1755     // limit it to 6 items displayed at one time 
    1756     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             else 
    1779                 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         else 
    1789             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 the 
    1801  *                  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             else 
    1894                 buttonRows[row].visible = false; 
    1895         } 
    1896     } 
    1897     else 
    1898     { 
    1899         int row; 
    1900         for (row = newrow; row < (int)buttonRows.size(); row++) 
    1901         { 
    1902             if (row < newrow + visiblerows) 
    1903                 buttonRows[row].visible = true; 
    1904             else 
    1905                 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  
    1931525/** \brief Reset and reparse everything. 
    1932526 * 
    1933527 *  Note: this does not use the theme or menu file chosen in Init(), but 
    1934528 *  instead uses defaults which should work if MythTV was properly installed. 
    1935529 */ 
    1936 bool MythThemedMenuPrivate::ReloadTheme(void) 
     530void MythThemedMenu::ReloadTheme(void) 
    1937531{ 
     532    m_foundtheme = false; 
     533 
    1938534    GetGlobalFontMap()->Clear(); 
    1939     m_state->parseFonts = true; 
    1940535 
    1941     buttonList.clear(); 
    1942     buttonRows.clear(); 
     536    m_buttonList->Reset(); 
    1943537 
    1944     parent->ReloadExitKey(); 
    1945   
    1946     m_state->Reset(); 
     538    ReloadExitKey(); 
    1947539 
    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(); 
    1954541 
    1955     return parseMenu("mainmenu.xml"); 
     542    if (parseMenu("mainmenu.xml")) 
     543        m_foundtheme = true; 
    1956544} 
    1957545 
    1958546/** \brief Delegate key event to appropriate action for keyHandler() 
    1959547 * 
    1960548 *  \return true iff key event was properly handled 
    1961549 */ 
    1962 bool MythThemedMenuPrivate::keyPressHandler(QKeyEvent *e) 
     550bool MythThemedMenu::keyPressHandler(QKeyEvent *e) 
    1963551{ 
    1964552    QStringList actions; 
    1965553    GetMythMainWindow()->TranslateKeyPress("menu", e, actions); 
    1966554 
    1967     return keyHandler(actions, e->modifiers() == exitModifier); 
     555    return keyHandler(actions, e->modifiers() == m_exitModifier); 
    1968556} 
    1969557 
    1970558/** \brief Interpret key presses on the menu into the appropriate actions 
    1971559 * 
    1972560 *  \param actions list of MythTV actions to be handled. 
    1973561 */ 
    1974 bool MythThemedMenuPrivate::keyHandler(QStringList &actions, 
     562bool MythThemedMenu::keyHandler(QStringList &actions, 
    1975563                                       bool fullexit) 
    1976564{ 
    1977     ThemedButton *lastbutton = activebutton; 
    1978     int oldrow = currentrow; 
    1979     int oldcolumn = currentcolumn; 
    1980565    bool handled = false; 
    1981566 
    1982567    for (int i = 0; i < actions.size() && !handled; i++) 
     
    1984569        QString action = actions[i]; 
    1985570        handled = true; 
    1986571 
    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") 
    1988580        { 
    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             else 
    2022                 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             else 
    2052                 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         { 
    2070581            QString action = "UPMENU"; 
    2071             if (!allocedstate) 
     582            if (!m_allocedstate) 
    2072583                handleAction(action); 
    2073             else if (m_state->killable) 
     584            else if (m_state->m_killable) 
    2074585            { 
    2075                 wantpop = true; 
    2076                 if (m_state->callback != NULL) 
     586                m_wantpop = true; 
     587                if (m_state->m_callback) 
    2077588                { 
    2078589                    QString sel = "EXITING_MENU"; 
    2079                     m_state->callback(m_state->callbackdata, sel); 
     590                    m_state->m_callback(m_state->m_callbackdata, sel); 
    2080591                } 
    2081592 
    2082593                if (GetMythMainWindow()->GetMainStack()->TotalScreens() == 1) 
    2083594                    QApplication::exit(); 
    2084595            } 
    2085             else if (exitModifier >= 0 && fullexit && 
     596            else if (m_exitModifier >= 0 && fullexit && 
    2086597                     GetMythMainWindow()->GetMainStack()->TotalScreens() == 1) 
    2087598            { 
    2088599                QApplication::exit(); 
    2089                 wantpop = true; 
     600                m_wantpop = true; 
    2090601            } 
    2091             lastbutton = NULL; 
    2092602        } 
    2093603        else 
    2094604            handled = false; 
     
    2097607    if (!handled) 
    2098608        return false; 
    2099609 
    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  
    2114610    // 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(); 
    2117613 
    2118614    return true; 
    2119 }  
     615} 
    2120616 
    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) 
     617void MythThemedMenu::buttonAction(MythUIButtonListItem *item) 
    2129618{ 
    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 *>(); 
    2148620 
    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++) 
    2173623    { 
    2174         QStringList action("ESCAPE"); 
    2175         keyHandler(action, true); 
    2176         return true; 
     624        if (handleAction(*it)) 
     625            break; 
    2177626    } 
    2178627 
    2179     return false; 
     628    button = NULL; 
    2180629} 
    2181630 
    2182631/** \brief Locates the appropriate menu file from which to parse the menu 
     
    2184633 *  \param menuname file name of the menu you want to find 
    2185634 *  \return the directory in which the menu file is found 
    2186635 */ 
    2187 QString MythThemedMenuPrivate::findMenuFile(const QString &menuname) 
     636QString MythThemedMenu::findMenuFile(const QString &menuname) 
    2188637{ 
    2189638    QString testdir = GetConfDir() + "/" + menuname; 
    2190639    QFile file(testdir); 
     
    2196645    if (file.exists()) 
    2197646        return testdir; 
    2198647 
    2199          
    2200648    testdir = GetMythUI()->GetThemeDir() + "/" + menuname; 
    2201649    file.setFileName(testdir); 
    2202650    if (file.exists()) 
    2203651        return testdir; 
    2204          
     652 
    2205653    testdir = GetShareDir() + menuname; 
    2206654    file.setFileName(testdir); 
    2207655    if (file.exists()) 
    2208656        return testdir; 
    2209          
     657 
    2210658    testdir = "../mythfrontend/" + menuname; 
    2211659    file.setFileName(testdir); 
    2212660    if (file.exists()) 
    2213661        return testdir; 
    2214          
     662 
    2215663    return ""; 
    2216664} 
    2217665 
     
    2220668 *  \param action single action to be handled 
    2221669 *  \return true if the action is not to EXEC another program 
    2222670 */ 
    2223 bool MythThemedMenuPrivate::handleAction(const QString &action) 
     671bool MythThemedMenu::handleAction(const QString &action) 
    2224672{ 
    2225673    MythUIMenuCallbacks *cbs = GetMythUI()->GetMenuCBs(); 
    2226674 
     
    2229677        QString rest = action.right(action.length() - 5); 
    2230678        if (cbs && cbs->exec_program) 
    2231679            cbs->exec_program(rest); 
    2232          
     680 
    2233681        return false; 
    2234682    } 
    2235683    else if (action.left(7) == "EXECTV ") 
     
    2240688    } 
    2241689    else if (action.left(5) == "MENU ") 
    2242690    { 
    2243         QString rest = action.right(action.length() - 5); 
     691        QString menu = action.right(action.length() - 5); 
    2244692 
    2245         if (rest == "main_settings.xml" &&  
     693        if (menu == "main_settings.xml" && 
    2246694            GetMythDB()->GetNumSetting("SetupPinCodeRequired", 0) && 
    2247695            !checkPinCode("SetupPinCodeTime", "SetupPinCode", "Setup Pin:")) 
    2248696        { 
    2249697            return true; 
    2250698        } 
    2251699 
    2252         MythScreenStack *stack = parent->GetScreenStack(); 
     700        MythScreenStack *stack = GetScreenStack(); 
    2253701 
    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); 
    2258704        stack->AddScreen(newmenu); 
    2259705    } 
    2260706    else if (action.left(6) == "UPMENU") 
    2261707    { 
    2262         wantpop = true; 
     708        m_wantpop = true; 
    2263709    } 
    2264710    else if (action.left(12) == "CONFIGPLUGIN") 
    2265711    { 
     
    2275721    } 
    2276722    else if (action.left(8) == "SHUTDOWN") 
    2277723    { 
    2278         if (allocedstate) 
     724        if (m_allocedstate) 
    2279725        { 
    2280             wantpop = true; 
     726            m_wantpop = true; 
    2281727        } 
    2282728    } 
    2283729    else if (action.left(5) == "EJECT") 
     
    2292738    } 
    2293739    else 
    2294740    { 
    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); 
    2298744    } 
    2299745 
    2300     return true;    
     746    return true; 
    2301747} 
    2302748 
    2303  
    2304 bool MythThemedMenuPrivate::findDepends(const QString &fileList) 
     749bool MythThemedMenu::findDepends(const QString &fileList) 
    2305750{ 
    2306751    QStringList files = fileList.split(" "); 
    2307752    QString filename; 
    2308753 
    2309     for (QStringList::Iterator it = files.begin(); it != files.end(); ++it )  
     754    for (QStringList::Iterator it = files.begin(); it != files.end(); ++it ) 
    2310755    { 
    2311756        QString filename = findMenuFile(*it); 
    2312757        if (filename != "" && filename.endsWith(".xml")) 
     
    2330775 *  \param text              the message text to be displayed 
    2331776 *  \return true if password checks out or is not needed. 
    2332777 */ 
    2333 bool MythThemedMenuPrivate::checkPinCode(const QString &timestamp_setting, 
     778bool MythThemedMenu::checkPinCode(const QString &timestamp_setting, 
    2334779                                         const QString &password_setting, 
    2335780                                         const QString &text) 
    2336781{ 
     
    2349794    } 
    2350795    else 
    2351796    { 
    2352         QDateTime last_time = QDateTime::fromString(last_time_stamp,  
     797        QDateTime last_time = QDateTime::fromString(last_time_stamp, 
    2353798                                                    Qt::TextDate); 
    2354799        if (last_time.secsTo(curr_time) < 120) 
    2355800        { 
     
    2383828 
    2384829    return false; 
    2385830} 
    2386  
    2387 //////////////////////////////////////////////////////////////////////////// 
    2388  
    2389 /** \brief Creates a themed menu. 
    2390  * 
    2391  *  \param cdir         directory where theme is stored 
    2392  *  \param menufile     file name of menu definition file 
    2393  *  \param parent       the screen stack that owns this UI type 
    2394  *  \param name         the name of this UI type 
    2395  *  \param allowreorder will buttons be inserted into new rows or pushed back 
    2396  *  \param state        theme state associated with this menu 
    2397  */ 
    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 after 
    2412  *  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 stored 
    2418  *  \param menufile name of menu item xml file 
    2419  */ 
    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 to 
    2449 ///        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 function 
    2456 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 to  
    2473  *         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     else 
    2488         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(), but 
    2494  *  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 MythTV 
    2505  *  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 events 
    2530  * 
    2531  *  \param origtype originating element type from the screen 
    2532  *  \param ge       mouse gesture event 
    2533  */ 
    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     else 
    2542         MythScreenType::gestureEvent(origtype, ge); 
    2543 } 
    2544  
    2545 void MythThemedMenu::aboutToShow() 
    2546 { 
    2547     MythScreenType::aboutToShow(); 
    2548     d->updateLCD(); 
    2549 } 
  • mythtv/libs/libmythui/myththemedmenu.h

     
    22#define MYTHTHEMEDMENU_H_ 
    33 
    44#include "mythscreentype.h" 
     5#include "mythuistatetype.h" 
     6#include "mythuibuttonlist.h" 
     7#include "xmlparsebase.h" 
    58 
    69#include <QKeyEvent> 
    710 
    811class MythMainWindow; 
    9 class MythThemedMenuPrivate; 
    1012class MythThemedMenuState; 
    1113 
     14struct ThemedButton 
     15{ 
     16    QString type; 
     17    QStringList action; 
     18    QString text; 
     19    MythImage *icon; 
     20    bool active; 
     21}; 
     22 
     23Q_DECLARE_METATYPE(ThemedButton*); 
     24 
     25struct 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 */ 
     38class 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 
    1266/// \brief Themed menu class, used for main menus in %MythTV frontend 
    13 class MythThemedMenu : public MythScreenType 
     67class MythThemedMenu : public MythThemedMenuState 
    1468{ 
    1569    Q_OBJECT 
    1670  public: 
    1771    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); 
    2074   ~MythThemedMenu(); 
    2175 
    2276    bool foundTheme(void); 
     
    3286 
    3387  protected: 
    3488    virtual bool keyPressEvent(QKeyEvent *e); 
    35     virtual void gestureEvent(MythUIType *origtype, MythGestureEvent *ge); 
    3689 
     90  private slots: 
     91    void setButtonActive(MythUIButtonListItem* item); 
     92    void buttonAction(MythUIButtonListItem* item); 
     93 
    3794  private: 
    38     void Init(const QString &cdir, const QString &menufile); 
     95    void Init(const QString &menufile); 
    3996 
    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 &timestamp_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; 
    41134}; 
    42135 
    43136#endif