Initial theme selection is now random. Theme prompt now has a search input and no longer uses FlowLayout. (Resolves issue 520)
authordag10
Sat, 09 Feb 2013 15:26:10 -0500
changeset 8475 f605bc59c603
parent 8473 555235e90010
child 8487 ec8391680132
Initial theme selection is now random. Theme prompt now has a search input and no longer uses FlowLayout. (Resolves issue #520)
QTfrontend/CMakeLists.txt
QTfrontend/model/ThemeModel.cpp
QTfrontend/model/ThemeModel.h
QTfrontend/res/css/qt.css
QTfrontend/ui/widget/flowlayout.cpp
QTfrontend/ui/widget/flowlayout.h
QTfrontend/ui/widget/mapContainer.cpp
QTfrontend/ui/widget/mapContainer.h
QTfrontend/ui/widget/themeprompt.cpp
QTfrontend/ui/widget/themeprompt.h
--- a/QTfrontend/CMakeLists.txt	Fri Feb 08 21:22:11 2013 -0500
+++ b/QTfrontend/CMakeLists.txt	Sat Feb 09 15:26:10 2013 -0500
@@ -123,7 +123,6 @@
 file(GLOB ModelHdr model/*.h)
 file(GLOB NetHdr net/*.h)
 file(GLOB_RECURSE UIhdr ui/*.h)
-list(REMOVE_ITEM UIhdr "${CMAKE_CURRENT_SOURCE_DIR}/ui/widget/flowlayout.h")
 file(GLOB UtilHdr util/*.h)
 
 
--- a/QTfrontend/model/ThemeModel.cpp	Fri Feb 08 21:22:11 2013 -0500
+++ b/QTfrontend/model/ThemeModel.cpp	Sat Feb 09 15:26:10 2013 -0500
@@ -76,24 +76,21 @@
 
         // detect if theme is dlc
         QString themeDir = PHYSFS_getRealDir(QString("Themes/%1/icon.png").arg(theme).toLocal8Bit().data());
-        dataset.insert(Qt::UserRole + 2, !themeDir.startsWith(datadir->absolutePath()));
+        bool isDLC = !themeDir.startsWith(datadir->absolutePath());
+        dataset.insert(IsDlcRole, isDLC);
 
         // set icon path
-        dataset.insert(Qt::UserRole + 1, iconpath);
+        dataset.insert(IconPathRole, iconpath);
 
         // set name
-        dataset.insert(Qt::DisplayRole, theme);
+        dataset.insert(ActualNameRole, theme);
 
-        // load and set icon
-        QIcon icon;
-        icon.addPixmap(QPixmap(iconpath), QIcon::Normal);
-        icon.addPixmap(QPixmap(iconpath), QIcon::Disabled);
-
-        dataset.insert(Qt::DecorationRole, icon);
+        // set displayed name
+        dataset.insert(Qt::DisplayRole, (isDLC ? "*" : "") + theme);
 
         // load and set preview icon
         QIcon preview(QString("physfs://Themes/%1/icon@2x.png").arg(theme));
-        dataset.insert(Qt::UserRole, preview);
+        dataset.insert(Qt::DecorationRole, preview);
 
         m_data.append(dataset);
     }
--- a/QTfrontend/model/ThemeModel.h	Fri Feb 08 21:22:11 2013 -0500
+++ b/QTfrontend/model/ThemeModel.h	Sat Feb 09 15:26:10 2013 -0500
@@ -39,6 +39,7 @@
         Q_OBJECT
 
     public:
+        enum Roles { ActualNameRole = Qt::UserRole, IsDlcRole, IconPathRole };
         explicit ThemeModel(QObject *parent = 0);
 
         int rowCount(const QModelIndex &parent = QModelIndex()) const;
--- a/QTfrontend/res/css/qt.css	Fri Feb 08 21:22:11 2013 -0500
+++ b/QTfrontend/res/css/qt.css	Sat Feb 09 15:26:10 2013 -0500
@@ -275,21 +275,21 @@
 border-radius: 3px;
 }
 
-HatButton {
+HatButton, ThemeButton {
 text-align: left;
 }
 
-#hatList, #hatList:hover {
+#hatList, #hatList:hover, #themeList, #themeList:hover {
 border-color: #F6CB1C;
 }
 
-#hatList QScrollBar {
+#hatList QScrollBar, #themeList QScrollBar {
 background-color: #130F2A;
 border-top-right-radius: 10px;
 border-bottom-right-radius: 10px;
 }
 
-#hatList {
+#hatList, #themeList {
 border-color: #F6CB1C;
 border-width: 3px;
 border-style: solid;
@@ -297,7 +297,7 @@
 border-top-left-radius: 0px;
 }
 
-#hatList::item {
+#hatList::item, #themeList::item {
 background-color: #11084A;
 padding: 4px;
 border-radius: 10px;
@@ -307,11 +307,11 @@
 border-color: #11084A;
 }
 
-#hatList::item:hover {
+#hatList::item:hover, #themeList::item:hover {
 background-color: #150A61;
 }
 
-#hatList::item:selected {
+#hatList::item:selected, #themeList::item:selected {
 background-color: #150A61;
 }
 
--- a/QTfrontend/ui/widget/flowlayout.cpp	Fri Feb 08 21:22:11 2013 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,190 +0,0 @@
- /****************************************************************************
- **
- ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
- ** All rights reserved.
- ** Contact: Nokia Corporation (qt-info@nokia.com)
- **
- ** This file is part of the examples of the Qt Toolkit.
- **
- ** $QT_BEGIN_LICENSE:BSD$
- ** You may use this file under the terms of the BSD license as follows:
- **
- ** "Redistribution and use in source and binary forms, with or without
- ** modification, are permitted provided that the following conditions are
- ** met:
- **   * Redistributions of source code must retain the above copyright
- **     notice, this list of conditions and the following disclaimer.
- **   * Redistributions in binary form must reproduce the above copyright
- **     notice, this list of conditions and the following disclaimer in
- **     the documentation and/or other materials provided with the
- **     distribution.
- **   * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
- **     the names of its contributors may be used to endorse or promote
- **     products derived from this software without specific prior written
- **     permission.
- **
- ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
- ** $QT_END_LICENSE$
- **
- ****************************************************************************/
-
- #include <QtGui>
-
- #include "flowlayout.h"
-
-FlowLayout::FlowLayout(QWidget *parent, int margin, int hSpacing, int vSpacing)
-    : QLayout(parent), m_hSpace(hSpacing), m_vSpace(vSpacing)
-{
-    setContentsMargins(margin, margin, margin, margin);
-}
-
-FlowLayout::FlowLayout(int margin, int hSpacing, int vSpacing)
-    : m_hSpace(hSpacing), m_vSpace(vSpacing)
-{
-    setContentsMargins(margin, margin, margin, margin);
-}
-
-FlowLayout::~FlowLayout()
-{
-    QLayoutItem *item;
-    while ((item = takeAt(0)))
-        delete item;
-}
-
-void FlowLayout::addItem(QLayoutItem *item)
-{
-    itemList.append(item);
-}
-
-int FlowLayout::horizontalSpacing() const
-{
-    if (m_hSpace >= 0) {
-        return m_hSpace;
-    } else {
-        return smartSpacing(QStyle::PM_LayoutHorizontalSpacing);
-    }
-}
-
-int FlowLayout::verticalSpacing() const
-{
-    if (m_vSpace >= 0) {
-        return m_vSpace;
-    } else {
-        return smartSpacing(QStyle::PM_LayoutVerticalSpacing);
-    }
-}
-
-int FlowLayout::count() const
-{
-    return itemList.size();
-}
-
-QLayoutItem *FlowLayout::itemAt(int index) const
-{
-    return itemList.value(index);
-}
-
-QLayoutItem *FlowLayout::takeAt(int index)
-{
-    if (index >= 0 && index < itemList.size())
-        return itemList.takeAt(index);
-    else
-        return 0;
-}
-
-Qt::Orientations FlowLayout::expandingDirections() const
-{
-    return 0;
-}
-
-bool FlowLayout::hasHeightForWidth() const
-{
-    return true;
-}
-
-int FlowLayout::heightForWidth(int width) const
-{
-    int height = doLayout(QRect(0, 0, width, 0), true);
-    return height;
-}
-
-void FlowLayout::setGeometry(const QRect &rect)
-{
-    QLayout::setGeometry(rect);
-    doLayout(rect, false);
-}
-
-QSize FlowLayout::sizeHint() const
-{
-    return minimumSize();
-}
-
-QSize FlowLayout::minimumSize() const
-{
-    QSize size;
-    QLayoutItem *item;
-    foreach (item, itemList)
-        size = size.expandedTo(item->minimumSize());
-
-    size += QSize(2*margin(), 2*margin());
-    return size;
-}
-
-int FlowLayout::doLayout(const QRect &rect, bool testOnly) const
-{
-    int left, top, right, bottom;
-    getContentsMargins(&left, &top, &right, &bottom);
-    QRect effectiveRect = rect.adjusted(+left, +top, -right, -bottom);
-    int x = effectiveRect.x();
-    int y = effectiveRect.y();
-    int lineHeight = 0;
-
-    QLayoutItem *item;
-    foreach (item, itemList) {
-        QWidget *wid = item->widget();
-        int spaceX = horizontalSpacing();
-        if (spaceX == -1)
-            spaceX = wid->style()->layoutSpacing(
-                QSizePolicy::PushButton, QSizePolicy::PushButton, Qt::Horizontal);
-        int spaceY = verticalSpacing();
-        if (spaceY == -1)
-            spaceY = wid->style()->layoutSpacing(
-                QSizePolicy::PushButton, QSizePolicy::PushButton, Qt::Vertical);
-        int nextX = x + item->sizeHint().width() + spaceX;
-        if (nextX - spaceX > effectiveRect.right() && lineHeight > 0) {
-            x = effectiveRect.x();
-            y = y + lineHeight + spaceY;
-            nextX = x + item->sizeHint().width() + spaceX;
-            lineHeight = 0;
-        }
-
-        if (!testOnly)
-            item->setGeometry(QRect(QPoint(x, y), item->sizeHint()));
-
-        x = nextX;
-        lineHeight = qMax(lineHeight, item->sizeHint().height());
-    }
-    return y + lineHeight - rect.y() + bottom;
-}
-int FlowLayout::smartSpacing(QStyle::PixelMetric pm) const
-{
-    QObject *parent = this->parent();
-    if (!parent) {
-        return -1;
-    } else if (parent->isWidgetType()) {
-        QWidget *pw = static_cast<QWidget *>(parent);
-        return pw->style()->pixelMetric(pm, 0, pw);
-    } else {
-        return static_cast<QLayout *>(parent)->spacing();
-    }
-}
--- a/QTfrontend/ui/widget/flowlayout.h	Fri Feb 08 21:22:11 2013 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,77 +0,0 @@
- /****************************************************************************
- **
- ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
- ** All rights reserved.
- ** Contact: Nokia Corporation (qt-info@nokia.com)
- **
- ** This file is part of the examples of the Qt Toolkit.
- **
- ** $QT_BEGIN_LICENSE:BSD$
- ** You may use this file under the terms of the BSD license as follows:
- **
- ** "Redistribution and use in source and binary forms, with or without
- ** modification, are permitted provided that the following conditions are
- ** met:
- **   * Redistributions of source code must retain the above copyright
- **     notice, this list of conditions and the following disclaimer.
- **   * Redistributions in binary form must reproduce the above copyright
- **     notice, this list of conditions and the following disclaimer in
- **     the documentation and/or other materials provided with the
- **     distribution.
- **   * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
- **     the names of its contributors may be used to endorse or promote
- **     products derived from this software without specific prior written
- **     permission.
- **
- ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
- ** $QT_END_LICENSE$
- **
- ****************************************************************************/
-
- #ifndef FLOWLAYOUT_H
- #define FLOWLAYOUT_H
-
- #include <QLayout>
- #include <QRect>
- #include <QStyle>
- #include <QWidgetItem>
- class FlowLayout : public QLayout
- {
- public:
-     FlowLayout(QWidget *parent, int margin = -1, int hSpacing = -1, int vSpacing = -1);
-     FlowLayout(int margin = -1, int hSpacing = -1, int vSpacing = -1);
-     ~FlowLayout();
-
-     void addItem(QLayoutItem *item);
-     int horizontalSpacing() const;
-     int verticalSpacing() const;
-     Qt::Orientations expandingDirections() const;
-     bool hasHeightForWidth() const;
-     int heightForWidth(int) const;
-     int count() const;
-     QLayoutItem *itemAt(int index) const;
-     QSize minimumSize() const;
-     void setGeometry(const QRect &rect);
-     QSize sizeHint() const;
-     QLayoutItem *takeAt(int index);
-
- private:
-     int doLayout(const QRect &rect, bool testOnly) const;
-     int smartSpacing(QStyle::PixelMetric pm) const;
-
-     QList<QLayoutItem *> itemList;
-     int m_hSpace;
-     int m_vSpace;
- };
-
- #endif
--- a/QTfrontend/ui/widget/mapContainer.cpp	Fri Feb 08 21:22:11 2013 -0500
+++ b/QTfrontend/ui/widget/mapContainer.cpp	Sat Feb 09 15:26:10 2013 -0500
@@ -250,14 +250,13 @@
 
     /* Set defaults */
 
-    setRandomTheme();
     setRandomSeed();
     setMazeSize(0);
     setTemplateFilter(0);
     staticMapChanged(m_staticMapModel->index(0, 0));
     missionMapChanged(m_missionMapModel->index(0, 0));
-    updateTheme(m_themeModel->index(0, 0));
     changeMapType(MapModel::GeneratedMap);
+    setRandomTheme();
 }
 
 void HWMapContainer::setImage(const QImage newImage)
@@ -453,7 +452,7 @@
 
 void HWMapContainer::setTheme(const QString & theme)
 {
-    QModelIndexList mdl = m_themeModel->match(m_themeModel->index(0), Qt::DisplayRole, theme);
+    QModelIndexList mdl = m_themeModel->match(m_themeModel->index(0), ThemeModel::ActualNameRole, theme);
 
     if(mdl.size())
         updateTheme(mdl.at(0));
@@ -492,6 +491,7 @@
     if(!m_themeModel->rowCount()) return;
     quint32 themeNum = rand() % m_themeModel->rowCount();
     updateTheme(m_themeModel->index(themeNum));
+    qDebug() << "RANDOM THEME:" << themeNum;
 }
 
 void HWMapContainer::intSetTemplateFilter(int filter)
@@ -776,7 +776,7 @@
 
 void HWMapContainer::showThemePrompt()
 {
-    ThemePrompt prompt(this);
+    ThemePrompt prompt(m_themeID, this);
     int theme = prompt.exec() - 1; // Since 0 means canceled, so all indexes are +1'd
     if (theme < 0) return;
 
@@ -787,8 +787,9 @@
 
 void HWMapContainer::updateTheme(const QModelIndex & current)
 {
-    m_theme = selectedTheme = current.data().toString();
-    QIcon icon = qVariantValue<QIcon>(current.data(Qt::UserRole));
+    m_theme = selectedTheme = current.data(ThemeModel::ActualNameRole).toString();
+    m_themeID = current.row();
+    QIcon icon = qVariantValue<QIcon>(current.data(Qt::DecorationRole));
     QSize iconSize = icon.actualSize(QSize(65535, 65535));
     btnTheme->setFixedHeight(64);
     btnTheme->setIconSize(iconSize);
--- a/QTfrontend/ui/widget/mapContainer.h	Fri Feb 08 21:22:11 2013 -0500
+++ b/QTfrontend/ui/widget/mapContainer.h	Sat Feb 09 15:26:10 2013 -0500
@@ -163,6 +163,7 @@
         void updateThemeButtonSize();
 
         MapModel::MapInfo m_mapInfo;
+        int m_themeID;
         QString m_theme;
         QString m_curMap;
 
--- a/QTfrontend/ui/widget/themeprompt.cpp	Fri Feb 08 21:22:11 2013 -0500
+++ b/QTfrontend/ui/widget/themeprompt.cpp	Sat Feb 09 15:26:10 2013 -0500
@@ -17,20 +17,26 @@
  */
 
 #include <QDialog>
-#include <QVBoxLayout>
+#include <QGridLayout>
+#include <QHBoxLayout>
 #include <QScrollArea>
 #include <QPushButton>
 #include <QToolButton>
 #include <QWidgetItem>
 #include <QModelIndex>
+#include <QListView>
+#include <QLineEdit>
 #include <QLabel>
+#include <QSortFilterProxyModel>
+#include <QFontMetrics>
+#include <QDebug>
 
-#include "flowlayout.h"
 #include "DataManager.h"
+#include "lineeditcursor.h"
 #include "ThemeModel.h"
 #include "themeprompt.h"
 
-ThemePrompt::ThemePrompt(QWidget* parent) : QDialog(parent)
+ThemePrompt::ThemePrompt(int currentIndex, QWidget* parent) : QDialog(parent)
 {
     setModal(true);
     setWindowFlags(Qt::Sheet);
@@ -39,63 +45,128 @@
     resize(550, 430);
     setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
 
+    setStyleSheet("QPushButton { padding: 5px; margin-top: 10px; }");
+
+    // Theme model, and a model for setting a filter
+    ThemeModel * themeModel = DataManager::instance().themeModel();
+    filterModel = new QSortFilterProxyModel();
+    filterModel->setSourceModel(themeModel);
+    filterModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
+
     // Grid
-    QVBoxLayout * dialogLayout = new QVBoxLayout(this);
+    QGridLayout * dialogLayout = new QGridLayout(this);
     dialogLayout->setSpacing(0);
+    dialogLayout->setColumnStretch(1, 1);
+
+    QHBoxLayout * topLayout = new QHBoxLayout();
 
     // Help/prompt message at top
-    QLabel * lblDesc = new QLabel(tr("Select a theme for this map"));
-    lblDesc->setStyleSheet("color: #130F2A; background: #F6CB1C; border: solid 4px #F6CB1C; border-top-left-radius: 10px; border-top-right-radius: 10px; padding: auto 20px;");
+    QLabel * lblDesc = new QLabel(tr("Select a theme"));
+    lblDesc->setObjectName("lblDesc");
+    lblDesc->setStyleSheet("#lblDesc { color: #130F2A; background: #F6CB1C; border: solid 4px #F6CB1C; border-top-left-radius: 10px; padding: 4px 10px;}");
     lblDesc->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
     lblDesc->setFixedHeight(24);
     lblDesc->setMinimumWidth(0);
 
-    // Scroll area and container for theme icons
-    QWidget * themesContainer = new QWidget();
-    FlowLayout * themesGrid = new FlowLayout();
-    themesContainer->setLayout(themesGrid);
-    QScrollArea * scrollArea = new QScrollArea();
-    scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
-    scrollArea->setObjectName("scrollArea");
-    scrollArea->setStyleSheet("QScrollBar, #scrollArea { background-color: #130F2A; } #scrollArea { border-color: #F6CB1C; border-width: 3px; border-top-width: 0; border-style: solid; border-bottom-left-radius: 10px; border-bottom-right-radius: 10px; }");
-    scrollArea->setWidgetResizable(true);
-    scrollArea->setFrameShape(QFrame::NoFrame);
-    scrollArea->setWidget(themesContainer);
+    // Filter text box
+    QWidget * filterContainer = new QWidget();
+    filterContainer->setFixedHeight(24);
+    filterContainer->setObjectName("filterContainer");
+    filterContainer->setStyleSheet("#filterContainer { background: #F6CB1C; border-top-right-radius: 10px; padding: 3px; }");
+    filterContainer->setFixedWidth(250);
+    txtFilter = new LineEditCursor(filterContainer);
+    txtFilter->setFixedWidth(250);
+    txtFilter->setFocus();
+    txtFilter->setFixedHeight(22);
+    connect(txtFilter, SIGNAL(textChanged(const QString &)), this, SLOT(filterChanged(const QString &)));
+    connect(txtFilter, SIGNAL(moveUp()), this, SLOT(moveUp()));
+    connect(txtFilter, SIGNAL(moveDown()), this, SLOT(moveDown()));
+    connect(txtFilter, SIGNAL(moveLeft()), this, SLOT(moveLeft()));
+    connect(txtFilter, SIGNAL(moveRight()), this, SLOT(moveRight()));
+
+    // Filter label
+    QLabel * lblFilter = new QLabel(tr("Filter: "), txtFilter);
+    QFontMetrics lblMetrics(lblFilter->font());
+    int lblFilterWidth = lblMetrics.width(lblFilter->text());
+    lblFilter->setStyleSheet(QString("background: none; margin-left: -%1px; margin-top: 4px;").arg(lblFilterWidth + 5));
+    txtFilter->setStyleSheet(QString("LineEditCursor, QLabel { border-width: 0px; border-radius: 6px; margin-top: 3px; margin-right: 3px; padding-left: %1px; padding-bottom: 2px; background-color: rgb(23, 11, 54); } LineEditCursor:hover, LineEditCursor:focus { background-color: rgb(13, 5, 68); }").arg(lblFilterWidth + 5));
+
+    // Corner widget
+    QLabel * corner = new QLabel();
+    corner->setPixmap(QPixmap(QString::fromUtf8(":/res/inverse-corner-bl.png")));
+    corner->setFixedSize(10, 10);
+
+    // Add widgets to top layout
+    topLayout->addWidget(lblDesc);
+    topLayout->addWidget(filterContainer);
+    topLayout->addWidget(corner, 0, Qt::AlignBottom);
+    topLayout->addStretch(1);
 
     // Cancel button (closes dialog)
     QPushButton * btnCancel = new QPushButton(tr("Cancel"));
-    btnCancel->setStyleSheet("padding: 5px; margin-top: 10px;");
     connect(btnCancel, SIGNAL(clicked()), this, SLOT(reject()));
 
+    // Select button
+    QPushButton * btnSelect = new QPushButton(tr("Use selected theme"));
+    btnSelect->setDefault(true);
+    connect(btnSelect, SIGNAL(clicked()), this, SLOT(onAccepted()));
+
+    // Add themes
+    list = new ThemeListView();
+    list->setModel(filterModel);
+    list->setViewMode(QListView::IconMode);
+    list->setResizeMode(QListView::Adjust);
+    list->setMovement(QListView::Static);
+    list->setEditTriggers(QAbstractItemView::NoEditTriggers);
+    list->setSpacing(8);
+    list->setWordWrap(true);
+    list->setSelectionMode(QAbstractItemView::SingleSelection);
+    list->setObjectName("themeList");
+    list->setCurrentIndex(filterModel->index(currentIndex, 0));
+    connect(list, SIGNAL(activated(const QModelIndex &)), this, SLOT(themeChosen(const QModelIndex &)));
+    connect(list, SIGNAL(clicked(const QModelIndex &)), this, SLOT(themeChosen(const QModelIndex &)));
+
     // Add elements to layouts
-    dialogLayout->addWidget(lblDesc, 0);
-    dialogLayout->addWidget(scrollArea, 1);
-    dialogLayout->addWidget(btnCancel, 0, Qt::AlignLeft);
+    dialogLayout->addLayout(topLayout, 0, 0, 1, 3);
+    dialogLayout->addWidget(list, 1, 0, 1, 3);
+    dialogLayout->addWidget(btnCancel, 2, 0, 1, 1, Qt::AlignLeft);
+    dialogLayout->addWidget(btnSelect, 2, 2, 1, 1, Qt::AlignRight);
+}
 
-    // Tooltip label for theme name
-    lblToolTip = new QLabel(this);
+void ThemePrompt::moveUp()
+{
+    list->setCurrentIndex(list->moveCursor(QAbstractItemView::MoveUp, Qt::NoModifier));
+}
 
-    // Add theme buttons
-    ThemeModel * themes = DataManager::instance().themeModel();
-    for (int i = 0; i < themes->rowCount(); i++)
-    {
-        QModelIndex index = themes->index(i, 0);
-        QToolButton * btn = new QToolButton();
-        bool dlc = themes->data(index, Qt::UserRole + 2).toBool();
-        btn->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
-        btn->setIcon(qVariantValue<QIcon>(themes->data(index, Qt::UserRole)));
-        btn->setText((dlc ? "*" : "") + themes->data(index, Qt::DisplayRole).toString());
-        btn->setIconSize(QSize(60, 60));
-        btn->setProperty("themeID", QVariant(i));
-        btn->setStyleSheet("padding: 2px;");
-        connect(btn, SIGNAL(clicked()), this, SLOT(themeClicked()));
-        themesGrid->addWidget(btn);
-    }
+void ThemePrompt::moveDown()
+{
+    list->setCurrentIndex(list->moveCursor(QAbstractItemView::MoveDown, Qt::NoModifier));
+}
+
+void ThemePrompt::moveLeft()
+{
+    list->setCurrentIndex(list->moveCursor(QAbstractItemView::MoveLeft, Qt::NoModifier));
+}
+
+void ThemePrompt::moveRight()
+{
+    list->setCurrentIndex(list->moveCursor(QAbstractItemView::MoveRight, Qt::NoModifier));
+}
+
+void ThemePrompt::onAccepted()
+{
+    themeChosen(list->currentIndex());
 }
 
 // When a theme is selected
-void ThemePrompt::themeClicked()
+void ThemePrompt::themeChosen(const QModelIndex & index)
 {
-    QWidget * btn = (QWidget*)sender();
-    done(btn->property("themeID").toInt() + 1); // Since returning 0 means canceled
+    done(filterModel->mapToSource(index).row() + 1); // Since returning 0 means canceled
 }
+
+// When the text in the filter text box is changed
+void ThemePrompt::filterChanged(const QString & text)
+{
+    filterModel->setFilterFixedString(text);
+    list->setCurrentIndex(filterModel->index(0, 0));
+}
\ No newline at end of file
--- a/QTfrontend/ui/widget/themeprompt.h	Fri Feb 08 21:22:11 2013 -0500
+++ b/QTfrontend/ui/widget/themeprompt.h	Sat Feb 09 15:26:10 2013 -0500
@@ -21,21 +21,41 @@
 
 #include <QWidget>
 #include <QDialog>
+#include <QListView>
 
-class QLabel;
+class QLineEdit;
+class QModelIndex;
+class QSortFilterProxyModel;
+class LineEditCursor;
+
+class ThemeListView : public QListView
+{
+    friend class ThemePrompt;
+
+    public:
+        ThemeListView(QWidget* parent = 0) : QListView(parent){}
+};
 
 class ThemePrompt : public QDialog
 {
         Q_OBJECT
 
     public:
-        ThemePrompt(QWidget* parent);
+        ThemePrompt(int currentIndex = 0, QWidget* parent = 0);
 
     private:
-        QLabel * lblToolTip;
+        LineEditCursor * txtFilter;
+        ThemeListView * list;
+        QSortFilterProxyModel * filterModel;
 
     private slots:
-        void themeClicked();
+        void onAccepted();
+        void themeChosen(const QModelIndex & index);
+        void filterChanged(const QString & text);
+        void moveUp();
+        void moveDown();
+        void moveLeft();
+        void moveRight();
 };
 
 #endif // THEMEPROMPT_H